Add tests and optimization/compression for rendered metrics
This commit is contained in:
1 parent
1b738d11d2
commit
39404a9acf
10 files changed
+1055
-32
No files matched your search
@@ -6,7 +6,7 @@ See what it looks like below :
|
||||
|
||||

|
||||
|
||||
##### 🦑 Interested to get your own ?
|
||||
##### 🦑 Interested to get your own ?
|
||||
Try it now at [metrics.lecoq.io](https://metrics.lecoq.io/) with your GitHub username !
|
||||
|
||||
## 📜 How to use ?
|
||||
@@ -482,17 +482,17 @@ And pass `?traffic=1` in url when generating metrics.
|
||||
* `action/index.mjs` contains the GitHub action code
|
||||
* `action/dist/index.js` contains compiled the GitHub action code
|
||||
* `utils/*` contains various utilitaries for build
|
||||
|
||||
|
||||
### 💪 Contributing
|
||||
|
||||
If you would like to suggest a new feature or find a bug, you can fill an [issue](https://github.com/lowlighter/metrics/issues) describing your problem.
|
||||
|
||||
If you're motivated enough, you can submit a [pull request](https://github.com/lowlighter/metrics/pulls) to integrate new features or to solve open issues.
|
||||
Read the few sections below to get started with project structure.
|
||||
If you're motivated enough, you can submit a [pull request](https://github.com/lowlighter/metrics/pulls) to integrate new features or to solve open issues.
|
||||
Read the few sections below to get started with project structure.
|
||||
|
||||
#### Adding new metrics through GraphQL API, REST API or Third-Party service
|
||||
|
||||
If you want to gather additional metrics, update the GraphQL query from `src/query.graphql` to get additional data from [GitHub GraphQL API](https://docs.github.com/en/graphql).
|
||||
If you want to gather additional metrics, update the GraphQL query from `src/query.graphql` to get additional data from [GitHub GraphQL API](https://docs.github.com/en/graphql).
|
||||
Add additional computations and formatting in `src/metrics.mjs`.
|
||||
Raw queried data should be exposed in `data.user` whereas computed data should be in `data.computed`.
|
||||
|
||||
@@ -517,7 +517,7 @@ It then use directly `src/metrics.mjs` to generate the SVG image and commit them
|
||||
|
||||
#### Testing new features
|
||||
|
||||
To test new features, you'll need to follow the first steps of the `Deploying your own instance` tutorial.
|
||||
To test new features, you'll need to follow the first steps of the `Deploying your own instance` tutorial.
|
||||
Basically you create a `settings.json` containing a test token and `debug` mode enabled.
|
||||
|
||||
You can then start the node with `npm start` and you'll be able to test how the SVG renders with your editions by opening the server url in your browser.
|
||||
@@ -544,16 +544,22 @@ Below is a list of useful links :
|
||||
|
||||
Below is a list of primary dependencies :
|
||||
|
||||
* [express/express.js](https://github.com/expressjs/express)
|
||||
* [express/express.js](https://github.com/expressjs/express) and [expressjs/compression](https://github.com/expressjs/compression)
|
||||
* To serve, compute and render a GitHub user's metrics
|
||||
* [nfriedly/express-rate-limit](https://github.com/nfriedly/express-rate-limit)
|
||||
* To apply rate limiting on server and avoid spams and hitting GitHub API's own rate limit
|
||||
* [octokit/graphql.js](https://github.com/octokit/graphql.js/)
|
||||
* To perform request to GitHub GraphQL API
|
||||
* [octokit/graphql.js](https://github.com/octokit/graphql.js/) and [octokit/rest.js](https://github.com/octokit/rest.js)
|
||||
* To perform request to GitHub GraphQL API and GitHub REST API
|
||||
* [ptarjan/node-cache](https://github.com/ptarjan/node-cache)
|
||||
* To cache generated content
|
||||
* [renanbastos93/image-to-base64](https://github.com/renanbastos93/image-to-base64)
|
||||
* To generate base64 representation of users' avatars
|
||||
* [svg/svgo](https://github.com/svg/svgo)
|
||||
* To optimize generated SVG
|
||||
* [axios/axios](https://github.com/axios/axios)
|
||||
* To make HTTP/S requests
|
||||
* [actions/toolkit](https://github.com/actions/toolkit/tree/master) and [vercel/ncc](https://github.com/vercel/ncc)
|
||||
* To build the GitHub Action
|
||||
|
||||
All icons were ripped across GitHub's site, but still remains the intellectual property of GitHub.
|
||||
See [GitHub Logos and Usage](https://github.com/logos) for more information.
|
||||
|
||||
Vendored
+5
-5
@@ -1,4 +1,4 @@
|
||||
module.exports=(()=>{var __webpack_modules__={6677:(e,t,r)=>{"use strict";r.r(t);var s=r(5622);var o=r.n(s);var n=r(270);var i=r(3584);var a=r(2882);var c=r.n(a);var u=r(9483);var l=r.n(u);(async function(){const[e,t,r,s]=[a,u,i,n].map(e=>e&&e.default?e.default:e);try{console.log(`GitHub metrics as SVG image`);console.log(`========================================================`);console.log(`Version | 1.5.0`);process.on("unhandledRejection",e=>{throw e});const n=`<svg xmlns="http://www.w3.org/2000/svg" width="480" height="\${536 + (computed.plugins.pagespeed ? 100 : 0)}">
|
||||
module.exports=(()=>{var __webpack_modules__={76677:(e,t,r)=>{"use strict";r.r(t);var n=r(85622);var i=r.n(n);var a=r(60270);var o=r(3584);var s=r(32882);var l=r.n(s);var c=r(29483);var u=r.n(c);(async function(){const[e,t,r,n]=[s,c,o,a].map(e=>e&&e.default?e.default:e);try{console.log(`GitHub metrics as SVG image`);console.log(`========================================================`);console.log(`Version | 1.6.0`);process.on("unhandledRejection",e=>{throw e});const a=`<svg xmlns="http://www.w3.org/2000/svg" width="480" height="\${536 + (computed.plugins.pagespeed ? 100 : 0)}">
|
||||
<style>
|
||||
\${style}
|
||||
</style>
|
||||
@@ -255,7 +255,7 @@ module.exports=(()=>{var __webpack_modules__={6677:(e,t,r)=>{"use strict";r.r(t)
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
\` : \`
|
||||
\` : \`
|
||||
<section>
|
||||
<div class="row fill-width">
|
||||
<section class="categories">
|
||||
@@ -280,7 +280,7 @@ module.exports=(()=>{var __webpack_modules__={6677:(e,t,r)=>{"use strict";r.r(t)
|
||||
|
||||
</div>
|
||||
</foreignObject>
|
||||
</svg>`,i=`/* SVG global context */
|
||||
</svg>`,o=`/* SVG global context */
|
||||
svg {
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
||||
font-size: 14px;
|
||||
@@ -468,7 +468,7 @@ module.exports=(()=>{var __webpack_modules__={6677:(e,t,r)=>{"use strict";r.r(t)
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}`,a=`query Metrics {
|
||||
}`,s=`query Metrics {
|
||||
user(login: \$login) {
|
||||
name
|
||||
login
|
||||
@@ -564,4 +564,4 @@ module.exports=(()=>{var __webpack_modules__={6677:(e,t,r)=>{"use strict";r.r(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
`;console.log(`Templates | loaded`);const[c,u,l,p]=[e.getInput("token"),e.getInput("user"),e.getInput("filename",{default:"github-metrics.svg"}),e.getInput("debug",{default:false})];const d=e.getInput("committer_token",{default:null})||c;const f=o().join(l);console.log(`GitHub user | ${u}`);console.log(`Output file | ${f}`);console.log(`Github token | ${c?"provided":"missing"}`);if(!c)throw new Error("You must provide a valid GitHub token");const m=r.graphql.defaults({headers:{authorization:`token ${c}`}});const h=t.getOctokit(c);if(!p)console.debug=(()=>null);console.log(`Debug mode | ${p?"enabled":"disabled"}`);const g={lines:{enabled:e.getInput("plugin_lines",{default:false})},traffic:{enabled:e.getInput("plugin_traffic",{default:false})},pagespeed:{enabled:e.getInput("plugin_pagespeed",{default:false})}};if(e.getInput("pagespeed_token")){console.log(`Pagespeed token | provided`);g.pagespeed.token=e.getInput("pagespeed_token")}const b=Object.fromEntries(Object.entries(g).filter(([e,t])=>t.enabled).map(([e])=>[e,true]));console.log(`Plugins enabled | ${Object.entries(g).filter(([e,t])=>t.enabled).map(([e])=>e).join(", ")}`);const w=await s({login:u,q:b},{template:n,style:i,query:a,graphql:m,rest:h,plugins:g});console.log(`Render | complete`);{const e=t.getOctokit(d);console.log(`Committer | ${(await e.users.getAuthenticated()).data.login}`);let r=undefined;try{const{data:t}=await e.repos.getContent({owner:u,repo:u,path:l});r=t.sha}catch(e){}console.log(`Previous render sha | ${r||"none"}`);await e.repos.createOrUpdateFileContents({owner:u,repo:u,path:l,sha:r,message:`Update ${l} - [Skip GitHub Action]`,content:Buffer.from(w).toString("base64")});console.log(`Commit to repo | ok`)}console.log(`Success !`)}catch(t){console.error(t);e.setFailed(t.message);process.exit(1)}})().catch(e=>process.exit(1))},2541:function(e,t,r){"use strict";var s=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r in e)if(Object.hasOwnProperty.call(e,r))t[r]=e[r];t["default"]=e;return t};Object.defineProperty(t,"__esModule",{value:true});const o=s(r(2087));const n=r(4332);function issueCommand(e,t,r){const s=new Command(e,t,r);process.stdout.write(s.toString()+o.EOL)}t.issueCommand=issueCommand;function issue(e,t=""){issueCommand(e,{},t)}t.issue=issue;const i="::";class Command{constructor(e,t,r){if(!e){e="missing.command"}this.command=e;this.properties=t;this.message=r}toString(){let e=i+this.command;if(this.properties&&Object.keys(this.properties).length>0){e+=" ";let t=true;for(const r in this.properties){if(this.properties.hasOwnProperty(r)){const s=this.properties[r];if(s){if(t){t=false}else{e+=","}e+=`${r}=${escapeProperty(s)}`}}}}e+=`${i}${escapeData(this.message)}`;return e}}function escapeData(e){return n.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function escapeProperty(e){return n.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}},2882:function(e,t,r){"use strict";var s=this&&this.__awaiter||function(e,t,r,s){function adopt(e){return e instanceof r?e:new r(function(t){t(e)})}return new(r||(r=Promise))(function(r,o){function fulfilled(e){try{step(s.next(e))}catch(e){o(e)}}function rejected(e){try{step(s["throw"](e))}catch(e){o(e)}}function step(e){e.done?r(e.value):adopt(e.value).then(fulfilled,rejected)}step((s=s.apply(e,t||[])).next())})};var o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r in e)if(Object.hasOwnProperty.call(e,r))t[r]=e[r];t["default"]=e;return t};Object.defineProperty(t,"__esModule",{value:true});const n=r(2541);const i=r(9582);const a=r(4332);const c=o(r(2087));const u=o(r(5622));var l;(function(e){e[e["Success"]=0]="Success";e[e["Failure"]=1]="Failure"})(l=t.ExitCode||(t.ExitCode={}));function exportVariable(e,t){const r=a.toCommandValue(t);process.env[e]=r;const s=process.env["GITHUB_ENV"]||"";if(s){const t="_GitHubActionsFileCommandDelimeter_";const s=`${e}<<${t}${c.EOL}${r}${c.EOL}${t}`;i.issueCommand("ENV",s)}else{n.issueCommand("set-env",{name:e},r)}}t.exportVariable=exportVariable;function setSecret(e){n.issueCommand("add-mask",{},e)}t.setSecret=setSecret;function addPath(e){const t=process.env["GITHUB_PATH"]||"";if(t){i.issueCommand("PATH",e)}else{n.issueCommand("add-path",{},e)}process.env["PATH"]=`${e}${u.delimiter}${process.env["PATH"]}`}t.addPath=addPath;function getInput(e,t){const r=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(t&&t.required&&!r){throw new Error(`Input required and not supplied: ${e}`)}return r.trim()}t.getInput=getInput;function setOutput(e,t){n.issueCommand("set-output",{name:e},t)}t.setOutput=setOutput;function setCommandEcho(e){n.issue("echo",e?"on":"off")}t.setCommandEcho=setCommandEcho;function setFailed(e){process.exitCode=l.Failure;error(e)}t.setFailed=setFailed;functio
Line truncated
|
||||
`;console.log(`Templates | loaded`);const[l,c,u,d]=[e.getInput("token"),e.getInput("user"),e.getInput("filename",{default:"github-metrics.svg"}),e.getInput("debug",{default:false})];const p=e.getInput("committer_token",{default:null})||l;const m=i().join(u);console.log(`GitHub user | ${c}`);console.log(`Output file | ${m}`);console.log(`Github token | ${l?"provided":"missing"}`);if(!l)throw new Error("You must provide a valid GitHub token");const f=r.graphql.defaults({headers:{authorization:`token ${l}`}});const h=t.getOctokit(l);if(!d)console.debug=(()=>null);console.log(`Debug mode | ${d?"enabled":"disabled"}`);const g={lines:{enabled:e.getInput("plugin_lines",{default:false})},traffic:{enabled:e.getInput("plugin_traffic",{default:false})},pagespeed:{enabled:e.getInput("plugin_pagespeed",{default:false})}};if(e.getInput("pagespeed_token")){console.log(`Pagespeed token | provided`);g.pagespeed.token=e.getInput("pagespeed_token")}const y=Object.fromEntries(Object.entries(g).filter(([e,t])=>t.enabled).map(([e])=>[e,true]));console.log(`Plugins enabled | ${Object.entries(g).filter(([e,t])=>t.enabled).map(([e])=>e).join(", ")}`);const v=await n({login:c,q:y},{template:a,style:o,query:s,graphql:f,rest:h,plugins:g});console.log(`Render | complete`);{const e=t.getOctokit(p);console.log(`Committer | ${(await e.users.getAuthenticated()).data.login}`);let r=undefined;try{const{data:t}=await e.repos.getContent({owner:c,repo:c,path:u});r=t.sha}catch(e){}console.log(`Previous render sha | ${r||"none"}`);await e.repos.createOrUpdateFileContents({owner:c,repo:c,path:u,sha:r,message:`Update ${u} - [Skip GitHub Action]`,content:Buffer.from(v).toString("base64")});console.log(`Commit to repo | ok`)}console.log(`Success !`)}catch(t){console.error(t);e.setFailed(t.message);process.exit(1)}})().catch(e=>process.exit(1))},12541:function(e,t,r){"use strict";var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r in e)if(Object.hasOwnProperty.call(e,r))t[r]=e[r];t["default"]=e;return t};Object.defineProperty(t,"__esModule",{value:true});const i=n(r(12087));const a=r(74332);function issueCommand(e,t,r){const n=new Command(e,t,r);process.stdout.write(n.toString()+i.EOL)}t.issueCommand=issueCommand;function issue(e,t=""){issueCommand(e,{},t)}t.issue=issue;const o="::";class Command{constructor(e,t,r){if(!e){e="missing.command"}this.command=e;this.properties=t;this.message=r}toString(){let e=o+this.command;if(this.properties&&Object.keys(this.properties).length>0){e+=" ";let t=true;for(const r in this.properties){if(this.properties.hasOwnProperty(r)){const n=this.properties[r];if(n){if(t){t=false}else{e+=","}e+=`${r}=${escapeProperty(n)}`}}}}e+=`${o}${escapeData(this.message)}`;return e}}function escapeData(e){return a.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function escapeProperty(e){return a.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}},32882:function(e,t,r){"use strict";var n=this&&this.__awaiter||function(e,t,r,n){function adopt(e){return e instanceof r?e:new r(function(t){t(e)})}return new(r||(r=Promise))(function(r,i){function fulfilled(e){try{step(n.next(e))}catch(e){i(e)}}function rejected(e){try{step(n["throw"](e))}catch(e){i(e)}}function step(e){e.done?r(e.value):adopt(e.value).then(fulfilled,rejected)}step((n=n.apply(e,t||[])).next())})};var i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r in e)if(Object.hasOwnProperty.call(e,r))t[r]=e[r];t["default"]=e;return t};Object.defineProperty(t,"__esModule",{value:true});const a=r(12541);const o=r(29582);const s=r(74332);const l=i(r(12087));const c=i(r(85622));var u;(function(e){e[e["Success"]=0]="Success";e[e["Failure"]=1]="Failure"})(u=t.ExitCode||(t.ExitCode={}));function exportVariable(e,t){const r=s.toCommandValue(t);process.env[e]=r;const n=process.env["GITHUB_ENV"]||"";if(n){const t="_GitHubActionsFileCommandDelimeter_";const n=`${e}<<${t}${l.EOL}${r}${l.EOL}${t}`;o.issueCommand("ENV",n)}else{a.issueCommand("set-env",{name:e},r)}}t.exportVariable=exportVariable;function setSecret(e){a.issueCommand("add-mask",{},e)}t.setSecret=setSecret;function addPath(e){const t=process.env["GITHUB_PATH"]||"";if(t){o.issueCommand("PATH",e)}else{a.issueCommand("add-path",{},e)}process.env["PATH"]=`${e}${c.delimiter}${process.env["PATH"]}`}t.addPath=addPath;function getInput(e,t){const r=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(t&&t.required&&!r){throw new Error(`Input required and not supplied: ${e}`)}return r.trim()}t.getInput=getInput;function setOutput(e,t){a.issueCommand("set-output",{name:e},t)}t.setOutput=setOutput;function setCommandEcho(e){a.issue("echo",e?"on":"off")}t.setCommandEcho=setCommandEcho;function setFailed(e){process.exitCode=u.Failure;error(e)}t.setFailed=setFaile
Line truncated
|
||||
Generated
+976
-4
File diff suppressed because it is too large.
Load diff
+8
-5
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "metrics",
|
||||
"version": "1.5.0",
|
||||
"version": "1.6.0",
|
||||
"description": "Generate an user's GitHub metrics as SVG image format to embed somewhere else",
|
||||
"main": "index.mjs",
|
||||
"scripts": {
|
||||
"start": "node index.mjs",
|
||||
"build": "node utils/build.mjs",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"upgrade": "npm install @actions/core@latest @actions/github@latest @octokit/graphql@latest @octokit/rest@latest axios@latest express@latest express-rate-limit@latest image-to-base64@latest memory-cache@latest @vercel/ncc@latest"
|
||||
"test": "node tests/metrics.mjs",
|
||||
"upgrade": "npm install @actions/core@latest @actions/github@latest @octokit/graphql@latest @octokit/rest@latest axios@latest compression@latest express@latest express-rate-limit@latest image-to-base64@latest memory-cache@latest svgo@latest @vercel/ncc@latest libxmljs@latest"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -25,12 +25,15 @@
|
||||
"@octokit/graphql": "^4.5.6",
|
||||
"@octokit/rest": "^18.0.6",
|
||||
"axios": "^0.20.0",
|
||||
"compression": "^1.7.4",
|
||||
"express": "^4.17.1",
|
||||
"express-rate-limit": "^5.1.3",
|
||||
"image-to-base64": "^2.1.1",
|
||||
"memory-cache": "^0.2.0"
|
||||
"memory-cache": "^0.2.0",
|
||||
"svgo": "^1.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.24.1"
|
||||
"@vercel/ncc": "^0.24.1",
|
||||
"libxmljs": "^0.19.7"
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
import cache from "memory-cache"
|
||||
import ratelimit from "express-rate-limit"
|
||||
import metrics from "./metrics.mjs"
|
||||
import compression from "compression"
|
||||
|
||||
//Load svg template, style and query
|
||||
async function load() {
|
||||
@@ -28,6 +29,7 @@
|
||||
|
||||
//Setup server
|
||||
const app = express()
|
||||
app.use(compression())
|
||||
const middlewares = []
|
||||
//Rate limiter middleware
|
||||
if (ratelimiter) {
|
||||
|
||||
+8
-5
@@ -5,9 +5,10 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="A SVG image generator which includes activity, community and repositories metrics about your GitHub account that you can includes on your profile">
|
||||
<meta name="author" content="lowlighter">
|
||||
<link rel="icon" href="data:,">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<h1><a href="https://github.com/lowlighter/metrics">GitHub metrics</a></h1>
|
||||
|
||||
<label>
|
||||
@@ -24,9 +25,11 @@
|
||||
<br>
|
||||
<div class="code">
|
||||

|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
And for even more metrics, setup this <a href="https://github.com/marketplace/actions/github-metrics-as-svg-image">GitHub action</a> on your repository !
|
||||
</aside>
|
||||
|
||||
|
||||
<script>
|
||||
window.onload = function () {
|
||||
//User updater
|
||||
@@ -40,11 +43,11 @@
|
||||
document.querySelector("#metrics .generated").style.opacity = 0
|
||||
document.querySelector("aside").style.opacity = 0
|
||||
//Update github user
|
||||
document.querySelector(".code").innerText = ``
|
||||
document.querySelector(".code").innerHTML = ``
|
||||
document.querySelector("#user-repo").href = `https://github.com/${user}/${user}`
|
||||
document.querySelectorAll(".user").forEach(node => node.innerText = user)
|
||||
//Update metrics
|
||||
if (event.key === "Enter")
|
||||
if (event.key === "Enter")
|
||||
metrics(user)
|
||||
else
|
||||
timeout = setTimeout(() => metrics(user), 2000)
|
||||
|
||||
+13
-2
@@ -1,5 +1,6 @@
|
||||
//Imports
|
||||
import imgb64 from "image-to-base64"
|
||||
import SVGO from "svgo"
|
||||
import Plugins from "./plugins/index.mjs"
|
||||
|
||||
//Setup
|
||||
@@ -78,9 +79,19 @@
|
||||
//Wait for pending promises
|
||||
await Promise.all(pending)
|
||||
|
||||
//Eval rendering and return
|
||||
//Eval rendering
|
||||
console.debug(`metrics/metrics/${login} > computed`)
|
||||
return eval(`\`${template}\``)
|
||||
const templated = eval(`\`${template}\``)
|
||||
console.debug(`metrics/metrics/${login} > templated`)
|
||||
|
||||
//Optimize rendering
|
||||
const svgo = new SVGO({plugins:[{cleanupAttrs:true}, {inlineStyles:false}]})
|
||||
const {data:optimized} = await svgo.optimize(templated)
|
||||
console.debug(`metrics/metrics/${login} > optimized`)
|
||||
|
||||
//Result
|
||||
const rendered = optimized
|
||||
return rendered
|
||||
}
|
||||
//Internal error
|
||||
catch (error) { throw (((Array.isArray(error.errors))&&(error.errors[0].type === "NOT_FOUND")) ? new Error("user not found") : error) }
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
computed.plugins.traffic = {views}
|
||||
console.debug(`metrics/plugins/traffic/${login} > ${JSON.stringify(computed.plugins.traffic)}`)
|
||||
solve()
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
//Thrown when token has unsufficient permissions
|
||||
if (error.status === 403) {
|
||||
|
||||
+1
-1
@@ -255,7 +255,7 @@
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
` : `
|
||||
` : `
|
||||
<section>
|
||||
<div class="row fill-width">
|
||||
<section class="categories">
|
||||
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,26 @@
|
||||
//Imports
|
||||
import path from "path"
|
||||
import fs from "fs"
|
||||
import metrics from "../src/metrics.mjs"
|
||||
import octokit from "@octokit/graphql"
|
||||
import OctokitRest from "@octokit/rest"
|
||||
import libxmljs from "libxmljs"
|
||||
|
||||
//Die on unhandled rejections
|
||||
process.on("unhandledRejection", error => { throw error })
|
||||
|
||||
//Load GitHub handlers
|
||||
const token = process.argv.slice(2)[0] ?? ""
|
||||
const graphql = octokit.graphql.defaults({headers:{authorization: `token ${token}`}})
|
||||
const rest = new OctokitRest.Octokit({auth:token})
|
||||
|
||||
//Load svg template, style and query
|
||||
const [template, style, query] = await Promise.all(["template.svg", "style.css", "query.graphql"].map(async file => `${await fs.promises.readFile(path.join("src", file))}`))
|
||||
|
||||
//Compute render
|
||||
const rendered = await metrics({login:"lowlighter", q:{}}, {template, style, query, graphql, rest, plugins:{}})
|
||||
|
||||
//Ensure it's a well-formed SVG image
|
||||
const parsed = libxmljs.parseXml(rendered)
|
||||
if (parsed.errors.length)
|
||||
throw new Error(`Malformed SVG : \n${parsed.errors.join("\n")}`)
|
||||
Reference in new issue
Block a user