Add tests and optimization/compression for rendered metrics
This commit is contained in:
24
README.md
24
README.md
@@ -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.
|
||||
|
||||
10
action/dist/index.js
vendored
10
action/dist/index.js
vendored
File diff suppressed because one or more lines are too long
980
package-lock.json
generated
980
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 |
26
tests/metrics.mjs
Normal file
26
tests/metrics.mjs
Normal 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")}`)
|
||||
Reference in New Issue
Block a user