This tutorial should help you add a service to shields.io in form of a badge. You will need to learn to use JavaScript, git and Github. Please improve the tutorial while you read it.
You should read the following:
You can read
- previous successful pull-requests to see how other people implemented their badges. Usually they start with "add".
- later pull-requests tagged with
new-badge
. - implementations and their commits in the server.js file.
- merged pull-requests.
I suppose you have git installed. If you do not, install it and learn about the Github workflow.
- Fork this repository.
- Clone the fork
git clone [email protected]:YOURGITHUBUSERNAME/shields.git
cd shields
- Install npm and other required packages (Ubuntu 16.10)
sudo apt-get install npm nodejs-legacy curl imagemagick
- Install all packages
npm install
- Build the frontend
npm run build
- Run the server
npm start
- Visit the website to check the badges get loaded slowly: http://[::1]:8080/
Before you want to implement your service, you may want to open an issue and describe what you have in mind:
- What is the badge for?
- Which API do you want to use?
You may additionally proceed to say what you want to work on. This information allows other humans to help and build on your work.
If there is already a related badge, you may want to place your code next to it.
Here you can see code for a badge at route for /test/<first>/<second><ending>
.
Lines with // (1)
and alike are commented below.
// Test integration.
camp.route(/^\/test\/([^\/]+)\/([^\/]+)\.(svg|png|gif|jpg|json)$/, // (1)
cache(function(data, match, sendBadge, request) {
var first = match[1]; // (2)
var second = match[2]; // (2)
var format = match[3]; // (2)
var badgeData = getBadgeData('X' + first + 'X', data); // (3)
badgeData.text[1] = second; // (4)
badgeData.colorscheme = 'blue'; // (4)
badgeData.colorB = '#008bb8'; // (4)
sendBadge(format, badgeData); // (5)
}));
Description of the code:
- This is the route specified as regular expression.
- These lines parse the route given in (1).
- This requests a default configuration for the badge.
- These lines customize the design of the badge. Possible attributes are specified.
- This line sends the response back to the browser.
To try out this custom badge do the following:
- Copy and paste these lines into server.js. I did this at about line 5000.
- Quit the running server with
Control+C
. - Start the server again.
npm start
- Visit the badge at http://[::]:8080/test/subject/STATUS.svg. It should look like this:
Make sure, you can get the data somehow, best as JSON. There might be an API for your service delivering the data.
The test badge above is quite simple and static. You can change the behavior by asking your API. There are various examples on how to answer with a customized badge:
This example is the for the Docker Hub automated integration. (Source)
// Docker Hub automated integration. // (1)
camp.route(/^\/docker\/automated\/([^/]+)\/([^/]+)\.(svg|png|gif|jpg|json)$/, // (2)
cache(function(data, match, sendBadge, request) { // (2)
var user = match[1]; // eg, jrottenberg // (3)
var repo = match[2]; // eg, ffmpeg // (3)
var format = match[3]; // (3)
if (user === '_') { // (4)
user = 'library'; // (4)
} // (4)
var path = user + '/' + repo; // (4)
var url = 'https://registry.hub.docker.com/v2/repositories/' + path; // (4)
var badgeData = getBadgeData('docker build', data); // (5)
request(url, function(err, res, buffer) { // (6)
if (checkErrorResponse(badgeData, err, res, 'repo not found')) { // (7)
sendBadge(format, badgeData); // (7)
return; // (7)
}
try {
var parsedData = JSON.parse(buffer); // (8)
var is_automated = parsedData.is_automated; // (8)
if (is_automated) {
badgeData.text[1] = 'automated'; // (9)
badgeData.colorscheme = 'blue'; // (9)
} else {
badgeData.text[1] = 'manual'; // (9)
badgeData.colorscheme = 'yellow'; // (9)
}
badgeData.colorB = data.colorB || '#008bb8'; // (9)
sendBadge(format, badgeData); // (9)
} catch(e) { // (10)
badgeData.text[1] = 'invalid'; // (10)
sendBadge(format, badgeData); // (10)
}
});
}));
The source code is annotated with // (1)
and alike on the right side.
The following numbering explains what happens in the corresponding lines.
- All badges are preceded by a comment. This allows other developers to find the badge regardless of implementation. Usually, badges with a similar topic have their implementation close to each other's.
- The regular expression matches the path behind the host name in the URL, e.g.
img.shields.io
.Example: https://img.shields.io/docker/automated/jrottenberg/ffmpeg.svg All parts are enclosed by brackets/^\/docker\/automated\/([^/]+)\/([^/]+)\.(svg|png|gif|jpg|json)$/ \.(svg|png|gif|jpg|json) The supported endings e.g. ".svg" ([^/]+)\/([^/]+) The name of the repository e.g. "jrottenberg/ffmpeg" \/docker\/automated\/ "/docker/automated/" is the start of the url. "/" must be escaped to "\/".
()
are passed though to the function as the parametermatch
. - The parts of the match are named.
- Based on the input parameters, we construct our query to the API.
Here,
"_"
is a special case. Theurl
is created to query the API. - Create the basic badge to use. You can read about the different formats available. It contains the format for all responses, regardless of the API's response.
- We request the
url
and pass a call back function to the request. The function is called once the data is retrieved from the API. - We want to always see a badge regardless the input. In some cases the API may return an error or a HTTP status code indicating a client error or a server error e.g. if the query was invalid. The error response is handled by the checkErrorResponse function and a badge with an appropriate status is returned: "inaccessible" , "not found" or "invalid" .
- The data returned by the API as JSON is parsed.
- Based on the result, the text and the color of the badge are altered.
- In case of an error, an "invalid" badge is constructed.
The pattern described can be found in may other badges. When you look at the server.js, you find many other badges. Some of them may query the same API. Those can be of additional help when implementing your badge.
TODO This has something to do with private/secret.json.
- Credentials should be stored there.
- You do not need to create this file, the server works without.
- Somewhere the format (JSON? Keys?) should be documented.
- How to get the keys?
Once you are done implementing your badge, you can add it to the collection on shields.io.
First, we make it visible locally at http://[::1]:8080/. Edit lib/all-badge-examples.js in the right category (Build, Downloads, ...) and add your badge:
{
title: 'Test Badge from the tutorial',
keywords: [
'some-search-keyword'
],
previewUri: '/test/subject/STATUS.svg',
},
Save, run npm run build
, and you can see it locally.
When creating a badge for a new service or changing a badge's behavior, tests should be included. They serve several purposes:
- They speed up future contributors when they are debugging or improving a badge.
- If a contributors like to change your badge, chances are, they forget edge cases and break your code. Tests may give hints in such cases.
- The contributor and reviewer can easily verify the code works as intended.
- When a badge stops working on the live server, maintainers can find out right away.
There is a dedicated tutorial for tests in the service-tests folder. Please follow it to include tests on your pull-request.
You have implemented changes in server.js
and lib/all-badge-examples.js
.
These changes shall go live on shields.io.
To do that, create a pull-request.
By doing this, your changes are made public to the shields team.
You can respond to their questions and the badge may soon be merged.
These files can also be of help for creating your own badge.