Add tests and optimization/compression for rendered metrics

This commit is contained in:
lowlighter
2020-10-13 14:00:48 +02:00
parent 1b738d11d2
commit 39404a9acf
10 changed files with 1055 additions and 32 deletions

View File

@@ -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.

File diff suppressed because one or more lines are too long

980
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -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"
}
}

View File

@@ -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) {

View File

@@ -5,6 +5,7 @@
<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>
@@ -25,6 +26,8 @@
<div class="code">
![<span class="md-alt">GitHub metrics</span>](https://metrics.lecoq.io/my-github-user)
</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>
@@ -40,7 +43,7 @@
document.querySelector("#metrics .generated").style.opacity = 0
document.querySelector("aside").style.opacity = 0
//Update github user
document.querySelector(".code").innerText = `![GitHub metrics](https://metrics.lecoq.io/${user})`
document.querySelector(".code").innerHTML = `![<span class="md-alt">GitHub metrics</span>](https://metrics.lecoq.io/${user})`
document.querySelector("#user-repo").href = `https://github.com/${user}/${user}`
document.querySelectorAll(".user").forEach(node => node.innerText = user)
//Update metrics

View File

@@ -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) }

26
tests/metrics.mjs Normal file
View File

@@ -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")}`)