This is a ready-to-use solution with a serverless backend (AWS: API Gateway, Lambda, DynamoDB) and a simple frontend to render the dashboards.
Works with both private and public repositories.
Calls are made from the front-end to the back-end without any authorization. It's suggested you lock down the front-end with some applicable means, like an SSO layer or Cloudflare Access or something similar.
If you want to get data for private repositories you will need a "classic" GitHub personal access token (PAT) with permissions to use the workflow
scope. If you are in an organization, make sure to authorize the use of the token against your organization.
From the Lambda function, it will first check a hash of the input in DynamoDB as a type of cache. If the cache has content and it's fresher than a minute, return it. Else go to GitHub to retrieve workflow data, transform it a bit, pass it to Shields.io to generate the SVG badge, and then finally return all of it.
If you're curious, each dashboard component is ~1200 bytes so that should give you an idea for the DynamoDB usage.
Feel free to upgrade it with nicer visuals, API keys or security, client-side caching, or anything else you fancy!
- Recent Node.js (ideally 20+) installed.
- Amazon Web Services (AWS) account with sufficient permissions so that you can deploy infrastructure.
- Ideally some experience with Serverless Framework as that's what we will use to deploy the service and infrastructure.
- You will need to deploy the stack prior to working with it locally as it uses actual infrastructure even in local mode.
Clone, fork, or download the repo as you normally would. Run npm install
.
Run npm run deploy
once you are authenticated with AWS. You will get a URL for your endpoint - use this in the front-end code.
For the front-end, just host it on a static website host like Cloudflare Pages or Netlify.
The below commands are the most critical ones. See package.json
for more commands! Substitute npm
for yarn
or whatever floats your boat.
npm start
: Run Serverless Framework in offline modenpm test
: Run tests on the codebasenpm run deploy
: Deploy with Serverless Frameworknpm run build
: Package and build the code with Serverless Frameworknpm run teardown
: Removes the deployed stack
You have to set the following in serverless.yml
:
custom.config.awsAccountNumber
: Your AWS account number.GITHUB_TOKEN
must be set if you want to call private repositories.
Optionally you can use AWS Secrets Manager instead of hard-coding the GitHub token. There is some code prepped for this, but you will have to manually create the secret in your AWS account.
In frontend/index.html
, you will have to modify:
- The endpoint for the
getData()
function, as well as the ingoing payload.
POST {{BASE_URL}}/
[
{
"owner": "mikaelvesavuori",
"repo": "dorametrix",
"ref": "main"
},
...
]
Example below. One object per successful request.
[
{
"conclusion": "success",
"status": "completed",
"owner": "mikaelvesavuori",
"repo": "dorametrix",
"ref": "main",
"badge": "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"104\" height=\"20\" role=\"img\" aria-label=\"main: completed\"><title>main: completed</title><linearGradient id=\"s\" x2=\"0\" y2=\"100%\"><stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/><stop offset=\"1\" stop-opacity=\".1\"/></linearGradient><clipPath id=\"r\"><rect width=\"104\" height=\"20\" rx=\"3\" fill=\"#fff\"/></clipPath><g clip-path=\"url(#r)\"><rect width=\"37\" height=\"20\" fill=\"#555\"/><rect x=\"37\" width=\"67\" height=\"20\" fill=\"#4c1\"/><rect width=\"104\" height=\"20\" fill=\"url(#s)\"/></g><g fill=\"#fff\" text-anchor=\"middle\" font-family=\"Verdana,Geneva,DejaVu Sans,sans-serif\" text-rendering=\"geometricPrecision\" font-size=\"110\"><text aria-hidden=\"true\" x=\"195\" y=\"150\" fill=\"#010101\" fill-opacity=\".3\" transform=\"scale(.1)\" textLength=\"270\">main</text><text x=\"195\" y=\"140\" transform=\"scale(.1)\" fill=\"#fff\" textLength=\"270\">main</text><text aria-hidden=\"true\" x=\"695\" y=\"150\" fill=\"#010101\" fill-opacity=\".3\" transform=\"scale(.1)\" textLength=\"570\">completed</text><text x=\"695\" y=\"140\" transform=\"scale(.1)\" fill=\"#fff\" textLength=\"570\">completed</text></g></svg>"
},
...
]