There's a lot of demand for the Gitlab badges (#541) and the PR has been lingering, so I thought I'd start off one of the simple ones as a new-style service. This one is SVG-based, so it shouldn't require the API-token logic which could use some more testing and will require us to create an app and configure it on our server.
We don't have any validation in place for `queryParams`. Probably this should be added to BaseService, though for the time being I extracted a helper function.
Thanks to @LVMBDV for getting this work started in #1838!
Close#2334
To avoid merge conflicts, I've deferred removing the aliasing logic in `prepareExamples`. That whole function will be refactored momentarily, and there's also #2339 open.
Now that the static badge has been moved in #2284, next in line for cleaning out `server.js` is this “static badge, old format.” I imagine this route is _very, very old_. (I wouldn’t be surprised if it’s not used at all. I’d be curious to see some stats on that endpoint. If it's not regularly getting requests I could see dropping it.)
In the case of URLs which have permanently changed, an approach I’d like to try is issuing a 301 Redirect.
The benefit is that if a user pastes the URL into the address bar while they are previewing or editing it, the browser will replace the address with the corrected URL when it loads. I figure this will cause some people to update their URLs with no effort, simply because they previewed the badge in their browser, and others to change over, if they notice it.
We incur a slight cost, which is a second request. However many browsers cache the 301’s indefinitely, and we can set an effectively infinite cache duration so the CDN and most other downstream caches will keep them a long time. And handling the redirect is extremely cheap.
This is a nice way to preserve backward compatibility of old routes without having to complicate the new route, such as in the case of vso -> azure-devops. For maintenance purposes, the route that redirects can effectively be treated separately.
It’s also a nice, gentle, and confidence-inspiring way to signal that users should update their URLs.
We could generalize this code, though I think this is a good place to start. This route is tricky because it needs to be loaded last, complicating a reusable solution.
This continues the work from #2279, by allowing example badges to be specified using `namedParams`. Using an object makes it possible for us to display these in form fields down the line. (#701)
I've called this the "preferred" way, and labeled the other ways deprecated. I've also added some doc to the `examples` property in BaseService. Then I realized we had some doc in the tutorial, though I think it's fine to have a short version in the tutorial, and the gory detail in BaseService.
I've also added a `pattern` keyword, and made `urlPattern` an alias.
Closes#2050.
- Stop running daily service tests in the main repo (since they're now handled [over here](https://github.com/badges/daily-tests)
- Add coverage and separate daily tests badges with links to coveralls
- Update our coverage ignores
- Move scripts, which do not need coverage, into `scripts/`
- Split out coverage test for npm package
- Remove spurious env var
Ref: #1584#2314
This picks up @RedSparr0w's work in #1802.
1. The handler for the static badge is moved into its own service with a synchronous handler. Avoiding an async call may make the static badges slightly faster, though it may be worth profiling this if it turns out we want asynchronous static badges in the future. If it doesn't make a performance difference we could make this handler `async` like the others.
2. Most of the custom static-badge logic is in a BaseStaticBadge base class.
3. Rewrite the static Gitter badge to use BaseStaticBadge.
4. A bit of minor cleanup in related functions.
This simplifies and further optimizes text-width computation by computing the entire width table in advance, and serializing it in the style of QuickTextMeasurer (#1390). This entirely removes the need for PDFKit at runtime. This has the advantage of fixing #1305 – more generally: producing the same result everywhere – without having to deploy a copy of Verdana.
The lifting is delegated to these three libraries, which are housed in a monorepo: https://github.com/metabolize/anafanafo
I'd be happy to move it into the badges org if folks want to collaborate on maintaining them.
QuickTextMeasurer took kerning pairs into account, whereas this implementation does not. I was thinking kerning would be a necessary refinement, though this seems to work well enough.
I dropped in a binary-search package to traverse the data structure, in part to conserve space. This causes a moderate performance regression, though there is ample room for improving on that: https://github.com/badges/shields/pull/2311#issuecomment-439182704
When I deployed 5e99aad2de to s0, shortly after Sentry picked up an unhandled error. I'm not sure which of the legacy badges this is in.
The bug was introduced just now, in #2257. Oops!
A test would have caught this, but I don't think it's worth wrapping tests around this difficult-to-test code. It makes more sense I think, to refactor the remaining badges that use it, replace it with something using async/await (maybe based on [node-cache](https://www.npmjs.com/package/node-cache), and test that.
* move gh-badges files out of /lib
As far as possible, this is just moving files
around and updating paths however there are 2
functional changes in this commit:
- remove use of lib/register-chai-plugins.spec
in badge-cli.spec.js
- remove use of starRating()
in text-measurer.spec.js
* update service tests that use colorscheme.json
* split package.json in two
* clean up import
* don't hard-code path
* start a changelog
* put a license file in the package dir
* re-organise documentation 📚
* don't pack test files
* remove favicon from Makefile
* give package its own test command
* link the docs better in README
The NuGet badge examples are straggling in all-badge-examples. Rather than move them as is, I thought it made more sense to refactor the services and see if they could be generated. I didn't take that on here; this is a straight rewrite of the badges. The old implementations were fairly difficult to follow. The new implementations are complicated too, though I hope much more readable.
Though the NuGet behaviors could be consolidated into a single flag, I split `withTenant` and `withFeed` into separate flags, thinking naming the behaviors makes the implementations easier to understand. I defaulted these to true, thinking that really this is really a MyGet implementation which is generalized to NuGet. Though maybe it makes more sense to have the MyGet style as the default. Probably it doesn't matter much either way.
I added a helper class ServiceUrlBuilder to construct the Shields service URL. It's useful in this complex case where the URL must be built up conditionally. This might be useful in a couple other places.
I also wrote a new service to handle the Powershell badges. They've diverged a little bit from the Nuget v2. There's a bit of shared code which I factored out.
If the XML Nuget APIs are more reliable, we could consider switching everything else over to them, though for now I would like to get this merged and get #2078 fixed.
Fix#2078
All the recent circle builds are failing and when I re-ran a build on master, I'm seeing the same failure.
```
npm ERR! path /root/repo/node_modules/gh-badges
npm ERR! code ENOENT
npm ERR! errno -2
npm ERR! syscall access
npm ERR! enoent ENOENT: no such file or directory, access '/root/repo/node_modules/gh-badges'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent
npm ERR! A complete log of this run can be found in:
npm ERR! /root/.npm/_logs/2018-11-12T14_28_41_232Z-debug.log
Exited with code 254
```
After reading https://discuss.circleci.com/t/cant-run-npm-install/19012 I wonder if it's related to the `working_directory` line. That issue suggests not using it.
The GitHub service family is the largest, and as yet untouched by our service rewrite. I thought I would start the process by tackling one service.
This pull request has a few things going on:
1. Rename pull-request-status to pull-request-check-state. We have another badge called pull request status. It seems like the checks are called one thing in the UI and another thing in the API, which is unfortunate. If other folks have strong feelings about the name, I’ll defer.
2. Move its tests and tighten up the syntax.
3. Move its badge examples including the doc string.
4. Add a new helper `errorMessagesFor` to use in the new services in place of `githubCheckErrorResponse`. It seems like we didn’t really use the `errorMessages` parameter to `githubCheckErrorResponse`, so I pared this down. I’m not sure if this is the function we’ll ultimately want, but it seems like a good place to start.
5. Pull fetch code I _know_ we use in other places into `github-common-fetch`. As in the PR I just opened for azure-devops, this takes a functional approach to the shared code, which is more direct, nimble, and easy to reason about than inheritance.
6. Create `GithubAuthService` which functions identically to BaseJsonService, except for one thing, which is that it uses the token pool. I accomplished this by adding a `_requestFetcher` property to BaseService, which is initialized to `sendAndCacheRequest` in the constructor, and can be overridden in subclasses. Since we weren’t using `_sendAndCacheRequest` directly except in BaseService and tests, I removed that property. I like this approach to patching in the GitHub auth because it’s very simple and creates no new API exposure. However, the way we’re doing the dependency injection feels a bit odd. Maybe the eventual refactor of request-handler would be a godo time to revisit this.
The GitHub requests go through many, many layers of indirection at this point. Later on it would be good to shave some of these off, perhaps once the legacy GitHub services have been converted, or when all the services are done and we can take another look at the base service hierarchy. The work in #2021 and #1205 is also related.
The term “url” is overloaded in services, to refer to the Shields route and also the API URL. Calling the Shields URL a “route” is on the whole more descriptive, and makes it clearer and more obvious which one of these we’re talking about. It’s a small thing, though seems like an improvement.
We have a few functions called `buildUrl`. I’ve renamed them to `buildRoute` when they refer to routes, and left them as `buildUrl` when they refer to API URLs.
I included a minor style tweak and some formatting cleanup in `TUTORIAL.md`.
I went down a rabbit hole while trying to untangle the bug in the dockbit and bitrise examples https://github.com/badges/shields/pull/2234#pullrequestreview-169997546.
The URL generation code is spaghetti-like, with functions, many of which I wrote, with opaque names, doing similar but not identical things, and making slightly incompatible assumptions about the way query strings are handled.
I got a bit lost and need to take a step back.
Meanwhile, this is a small piece of work I did that’s worth keeping. It doesn’t scratch the surface of the tangle, but it does remove a bit of duplication.
It also makes a minor stylistic ES6 change in the handling of default arguments.
Ref: #2027
1. Add validation to BaseSvgScrapingService and update readthedocs accordingly.
2. Rewrite vso and add more tests. Rename it internally to azure-devops. URLs are still `/vso` for now. Should we make a way to let a service register multiple URL patterns?
3. Handle shared code using a functional pattern instead of inheritance. This comes from a discussion https://github.com/badges/shields/pull/2031#issuecomment-417893819. I like the functional approach because it's more direct, nimble, and easy to reason about; plus it allows services to grow from a family of one to two more easily.
* Basic process metrics
* Enable Prometheus by an environment variable
* Code formatting
* Documentation for Prometheus metrics
* Link from README to documentation of Prometheus
* Link from README to documentation of Prometheus
* Link from README to documentation of Prometheus
* Separate module for metrics + tests
* Metrics limited by IP
* Metrics are forbidded for all requets by default
* Code refactoring
* allowedIps passed as a string to PrometheusMetrics
* Handle missing config
* METRICS_PROMETHEUS_ALLOWED_IPS added to documentation
* Log info about enabled metrics
* Unused code removed
* package-lock.json updated
* prom-client updated to 11.1.2
* Code refactoring
* Do not read IP address from X-Forwarder-For header
This is consistent with what we're pretty much already doing, and saves us from making the request during code review.
These were all autofixed and most of them seem easier to read. Some in the legacy services should be rewritten in more legible forms during refactor (ie using intermediate variables, or using request’s qs option). There are some in helper functions and elsewhere that should get rewritten separately. I don't want to change them in this PR because the changes will get lost in this diff, though we could identify them here and fix them before or just after.
Continuing the work from #2234, this creates additional, empty LegacyServices to hold the badge examples for conda and cocoapods. It's an approach we could take to finish emptying out all-badge-examples while the refactoring continues.
On the website badge, even the first URL path component is variable. I didn't think it could be moved, but it can!
Based on discussion in #2031, this adds an abstract service for SVG badges. I started with Readthedocs and the other services can be done as a follow-on.
I called it **BaseSvgScrapingService** rather than **BaseSvgService** to clarify that it's for badges from svg source data – not svg badges, which is all the badges.
Since I don't expect the svg parsing function to be used anywhere else once the services are refactored, I moved it into the class. I added a default value for `valueMatcher`, which works on Shields-style badges and seems to be used more than once.
The tests are based on XmlBaseService. I added one for valueMatcher, and also moved the SVG parsing badge here. Testing on codacy + vso should ensure the old `fetchFromSvg` is still working.
* Upgrade babel 6.x to babel 7.0
* Next 6.1.1 + additional babel packages needed for Babel 7.0
* Add @babel/register
* use @babel/preset-env in babel.presets to enable babel.env configuration
I had to track down the right lint rule for this. We have no-useless-rename for destructuring and import/export. The one for object literals is object-shorthand.
all-badge-examples is a common cause of merge conflicts. It’s difficult to adjust the badge categorization in that file – or to understand the diff – because it requires moving a block from one point to another. It’s much easier to edit a badge’s category in one place.
This starts the process of breaking up what’s left of that file, following up on the work from #1931. New-style services can only be in one category, which means legacy service examples have to be split along category lines. I split out separate legacy service classes where I could do so easily, leaving behind the ones which require more work, for one reason or another.
To run this requires renaming `private/secret.json` to `private/secret-production.json` in the working tree used for deployment.
Goals:
- Ensure production secrets are not used in development
- Avoid modifying the current working tree
- Avoid branch switching: make sure the current ref gets deployed
- If something other than `master` is deployed, leave `HEAD` alone; don't reset to `master`
- Ensure the build runs before server deploy (#1941)
This makes use of Git working trees, which is a relatively new but stable feature in Git. I was initially reluctant to use git worktree, mostly because I don't like adding new tooling that isn't necessary. The other alternative I experimented with was copying or re-cloning to an entirely separate working copy. This was messier and more brittle than using `git worktree`.
* define a public interface for NPM package
* move check-node-version to dependencies
* add missing file to package
* update docs
* bump version
* add gh-badges option to issue template
* abstract text measuring from users
* add a DocBlock for BadgeFactory.create()
Add some error messages for the developer when .service.js is malformed
When loading `.service.js` files which don’t contain services, such as when the export is forgotten, print helpful error messages. This will only occur during development; the unit tests will catch these problems well before code reaches the server.
* upgrade to Joi 14
Joi 14 throws an exception on regexes which use the `g` flag
see https://github.com/hapijs/joi/issues/1615
semver-regex uses the `g` flag
https://github.com/sindresorhus/semver-regex/blob/master/index.js
so in order to upgrade Joi, I've swapped out semver-regex
We'll use joi-extension-semver for semver validation now
* use isVPlusDottedVersionNClauses in jetbrains tests
some of these projects use version numbers like
v1.7 or
v3.0.0.141
In #2028 I suggested that we update as much of the code as possible to make consistent use of async await. This snags a bunch of the utility code and attempts to do that.
* Precommit hook with prettier and eslint added
* Info about running prettier removed from documentation
* Info about a pre-commit hook in documentation
- Fix case where app/branch exists but has no builds or CI runs
- Fix aplicationId/branch regex case
- Issue #2076:
- `ci/{projectId}` reports the result of a CI run
- `build/{applicationName}` reports the result of a build
- `ci/{applicationName}` reports the result of a _build_
(but isn't documented anywhere) for "backwards compatibility"
This picks up the work from #1321 on top of the work from #1940.
It allows the user to choose a compact tests format, or to override the labels with their own text or symbols.
I've rewritten the deprecated services using the `deprecatedService` helper from #1922. I added a test for `Deprecated`, and for `enforceDeprecation`, which isn't being used right now, but is there for future use.
This also makes it possible to write services using BaseService which do not have any named parameters (with a test).
Ref: #1358
This continues a consistency update we’ve been making to standardize on URL based on a recommendation from WHATWG: https://url.spec.whatwg.org/#goals
This also helps with copying and pasting between all-badge-examples and new-style services, where it’s otherwise easy to make a mistake.
Ref: #1322#1341
* allow service classes to define a static example
* define static example for some services
(apm, appveyor, cdnjs, clojars, gem, librariesio, npm, uptimerobot)
* add/update tests
This allows us to show an example without making an API call to a live service for better performance.
We can now specify 3 fields in the example definition:
* urlPattern for the version with placeholders e.g: /npm/dw/:package.svg
* ExampleUrl/Uri for the concrete example e.g: /npm/dw/localeval.svg
* PreviewUrl/Uri for the static (or live) image we will actually show
This is a bit of sugar that reduces the boilerplate for creating testers in what I expect will become the standard case: a service in `foo/foo-thing.service.js` with its tests in `foo/foo-thing.tester.js`.
This makes a small stylistic change, which is to name the service by its CamelCase class name rather than an invented snake-case ID. Whereas before the name was specified in `class FooThing extends Base[Json]Service` and a second time in the tester, it now only needs to be specified once.
- Move the Docker Pulls badge from **Other** to **Downloads**.
- Create **Platform & Version Support** for the following:
- django version support
- python version support
- node version support
- pypi - wheel (waiting to avoid conflict with #1922)
- pipi - format (waiting to avoid conflict with #1922)
- pipi - implementation (waiting to avoid conflict with #1922)
- hhvm
- cocoapods platform
- conda
- php version badges
This implements proposals 1, 2, and 4 from #1905:
* Move gem rank from ratings to downloads; tweak title
* Move docker build from other to build
* Move bundlephobia, github file, github repo, imagelayers, and microbadger size + layers badges into new category
* Fill in a couple missing titles
This is a fairly simple addition of a Redis-backed TokenPersistence. When GithubConstellation is initialized, it will create a FsTokenPersistence or a RedisTokenPersistence based on configuration. Have added tests of the Redis backend as an integration test, and ensured the server starts up correctly when a `REDIS_URL` is configured.
Ref: #1848
Instead of saving tokens on a timer, save them when they change. Use EventEmitter to keep the components loosely coupled.
This is easier to reason about, much easier to test, and better supports adapting to backends which support atomic operations.
This replaces json-autosave, which was a bit difficult to read and also hard to test, with fsos, the lower-level utility it’s built on.
Ref: #1848
- Log the response when using `test:services:trace`
- Fully log large nested objects
Since the `badgeData` is in a different format from the JSON response, and also doesn't include the title, including this output is helpful. It makes it clearer what the Joi matchers are trying to match.
Sometimes when there's a deep nested structure, it's helpful or necessary to see the entire thing.
We use arrow functions in most places; this enforces it.
Passing arrow functions to Mocha is discouraged: https://mochajs.org/#arrow-functions
This was a mix of autofixes and hand adjustments.
* InvalidParameter: New error type
* Return inaccessible for 5xx errors from services
* Add test for Inaccessible on 5xx
* Add tests for named error types
I ran into this while working on #1867, where ultimately I couldn't solve my problem by injecting config. This will make it easier in the future, though.
This creates a new convenience class which consolidates all the Github initialization. It supports dependency injection and facilitates refactoring the persistence along the lines of #1205.
Also ref #1848
When JSON responses come back, they are sometimes not in the format expected by the API. As a result we have a lot of defensive coding (expressions like `(data || {}).someProperty`) to avoid exceptions being thrown in badge processing. Often we rely on the `try` blocks that wrap so much of the badge-processing code, which catch all JavaScript exceptions and return some error result, usually **invalid**. The problem with this is that these `try` blocks catch all sorts of programmer errors too, so when we see **invalid** we don't know whether the API returned something unexpected, or we've made a mistake. We also spend a lot of time writing defensive tests around malformed responses, and creating and maintaining the defensive coding.
A better solution is to validate the API responses using declarative contracts. Here the programmer says exactly what they expect from the API. That way, if the response isn't what we expect we can just say it's an **invalid json response**. And if our code then throws an exception, well that's our mistake; when we catch that we can call it a **shields internal error**. It's also less code and less error-prone. Over time we may be confident enough in the contracts that we won't need so many tests of malformed responses. The contract doesn't need to describe the entire response, only the part that's needed. Unknown keys can simply be dropped, preventing unvalidated parts of the response from creeping into the code. Checking what's in our response before calling values on it also makes our code more secure.
I used Joi here, since we're already using it for testing. There may be another contracts library that's a better fit, though I think we could look at that later.
Those changes are in base.js.
The rest is a rewrite of the remaining NPM badges, including the extraction of an NpmBase class. Inspired by @chris48s's work in #1740, this class splits the service concerns into fetching, validation, transformation, and rendering. This is treated as a design pattern. See the PR discussion for more. There are two URL patterns, one which allows specifying a tag (used by e.g. the version badge `https://img.shields.io/npm/v/npm/next.svg`), and the other which does not accept a tag (e.g. the license badge `https://img.shields.io/npm/l/express.svg`). Subclasses like NpmLicense and NpmTypeDefinitions can specify the URL fragment, examples, the validation schema for the chunk of the package data they use, and a render function. The NpmVersion subclass uses a different endpoint, so it overrides the `handle` implementation from NpmBase.
The remaining services using BaseJsonService are shimmed, so they will keep working after the changes.
* add simple-icons
* handle undefined
* support logoColor param
* our icon > simple-icon
* dont crash ✅
* return false → undefined
* update test
* add test
* support logoColor on our logos
* cache as base64, pre-load-simple-icons, logo-helper
* add ?logoColor information
* and simple-icons reference, link to github master branch for our logos
* update simple-icons
update to 1.7.1
* Revert "and simple-icons reference, link to github master branch for our logos"
This reverts commit 5e99d5f8db.
* add link to simple-icons
* Add snapshot test
* support dash in place of space for logo name
- Present 'downloads', 'version', etc as pages
- Don't show any badges on the index page,
just links to categories.
- Tweak search so we can search all badges
from the index page, but without rendering
every badge as soon as we press a key.
* loosely detect semver versions
* semver loose validity
* add test
* semver compare versions when null
* add comments for loose
* remove console.log, only match semver scheme
* looser version restrictions
* re-sort version tests
comments refered to incorrect test
* add support for pre-release tags
#1682
* support uppercase, lowercase mixed
* make pre-release opt in
* change pre param to object
* add notes
* hide left side if no text
* fix whitespace at start of template
* for-the-badge done
* center text
* add logo support
* update snapshot test
* make first - in static badge optional
* add no label support to non static badges
* Add test for label
* update to not allow use of false/0/null
* fixup
I’m guessing something has changed with the way rounding happens in bundlephobia. I don’t expect this to happen again, but if it does we can change this to a regex.
This causes extremely strange failures in CircleCI. `npm install`, oddly, rewrites and reformats package.json. We hash package.json to determine the cache keys, and oddly enough Circle computes a new hash when we write the cache. `npm-install` writes to one cache key. The tasks that follow read from another. Nothing runs.
I'm running into this because I'm using prettier auto-format on another project, and the presence of a `.prettierrc` means it's started trying to format Shields code.
In separate news, I'm loving auto-formatting!
* tell browsers and downstream caches to cache for
`env.BADGE_MAX_AGE_SECONDS`, default 0 for dev
* set Cache-Control: no-cache, no-store, must-revalidate if maxAge=0
* add servertime badge to help with cache header debugging
* if service category is 'debug', exclude from examples
* ignore maxAge GET param if less than `env.BADGE_MAX_AGE_SECONDS`
This addresses some long-standing comments in https://github.com/badges/shields/issues/1458#issuecomment-368270996
We should also adopt Gatsby, create-react-app, or something similar designed for static sites, to eliminate the unnecessary runtime dependency on Next.js while also letting someone else maintain our front-end tooling. :-D These alternative tools might work just fine in subdirectories without config, and we might be able to leave Jekyll turned on (though we don’t need it). However these git-related changes are orthogonal.
- Don’t check out master, making it possible to deploy the currently checked-out commit
- Disable Jekyll which we don’t need. This allows _next folders to be deployed, and the related URL rewriting to be removed.
- Completely empty the deploy branch’s index before deployment. This prevents errors from broken symlinks, while preserving the commit history in the deploy branch.
- Do the deployment work in a git working tree. This requires Git 2.18 but makes it possible to do the above very safely.
This was designed as part of a rewrite of the Github auth code in #1205 which is stalled because I don't want to deploy it without access to server logs. The need for token rotation came up recently in #541, so I picked up this code, removed the github-specific bits, and pulled it in. Ordinarily I wouldn't merge helper code without a use, though sadly it seems like the best way to move forward this rewrite.
* add support for rgb, rgb, css named colors
* add support for hsl, hsla & add color-validate
* update makeBadge test, better coverage
* re-add comment
* add comment for supported colors
* dynamic badge gen, remove 'hex'
* add support for 1.0 opacity & fix 101-109
* fix colorscheme tests
* remove extra tests
* add test for negative values
* add test for uppercase & mixed case colors
* fix mixed case/uppercase test
* allow whitespace around color
* update test error messages
* add comments
* add more uppercase test
* update error message
* default to grey/red if invalid color chosen
default colorscheme:
colorA: grey
colorB: red
* Revert "default to grey/red if invalid color chosen"
This reverts commit 10db0c6d74.
Reverted as this affects the CLI version/when no color specified.
* validColor -> isCSSColor
* assignColor function
* update tests to use sazerac
* Add Jenkins Jacoco coverage badge
* [Jenkins] add service test for jacoco coverage
* Added Jenkins Coverage (Jacoco) in all-badge-examples page
* Defined variables using let/const instead of var
* Used template string for the uri
* Used checkErrorResponse helper function for the error check
* Used NaN method for not a number test
* Prefixed the original Jenkin coverage test with "cobertura:"
* Moved the happy test case at front
* Merge the business logic between jacoco and cobertura
* Fixed lint issue
* Trigger notification
fix [waffle] labels badge
- update URL and parsing code to use /columns endpoint
- add error handling for 'not found' case
- add missing test cases
- update home page example
Closes#1731
* update nock
The version we were using didn't allow
regex pattern with allowUnmocked option.
Update to latest version which includes this patch:
https://github.com/node-nock/nock/pull/1068
* update codeclimate test to allow any snapshot id on second call
This test was failing because the
snapshot id changed for some reason.
This change allows that to happen
and we will still intercept the
second API call.
* upgrade danger.js to latest version
* If PR contains tests using assert, suggest expect syntax
* if PR touches service, check service tester also touched
* Basic version of commit-status badge added
* Support for case with no common ancestor
* Handle unknown branch
* Service tests with error responses
* Handle unexpected 404 responses from github
* Branch is a base
* Tests reordered
* Using not the newest commit in tests
* Test for checked commit identical with the newest commit in branch
* Code refactoring
* Example for Github commit merge status
* Color fix for Docker Hub automated integration
* Test for overriding colorB in docker stars badge
* Test for overriding colorB in docker pulls badge
* #008bb8 is color of automated docker builds
* Test for overriding colorB in docker build badge
* Overriding colorB in docker stars badge
* Overriding colorB in docker pulls badge
* Overriding colorB in docker automated badge
* Better assertions in docker tests
* The default docker color updated to match the logo
* allow services to export >1 classes
This change to loadServiceClasses() allows us to define
services which either export a single service class e.g:
module.exports = class Cdnjs extends BaseService {
//...
}
or more than one. e.g:
module.exports = {
GemVersion,
GemDownloads,
GemOwner,
GemRank,
}
* refactor ruby gem badges
- move badge code to service classes
- throw exceptions for errors
- use let and const
- change tests to expect 'downloads' label for error badges
- general tidying
* fix typo in tests
* Don't always use class name in example label
This allows (for example) GemVersion and GemDownloads
both to use the example label 'Gem'
* The most recent code examples in tutorial
* An extra empty line removed
* An extra escapring characters removed
* checkErrorResponse mentioned in tutorial
* Typo fix in tutorial
* Static badges as examples in tutorial
* Missing word in the tutorial added
* Typo fix in tutorial
* pass error object to InvaildResponse()
this prevents us from throwing
TypeError: Cannot read property 'stack' of undefined
when we attempt to parse invalid json
* refactor [cdnjs] integration
* Support for buildkite
* Added to the examples as well
* Removed the unnecessary label property
* Fixed the example
* Improve the tests
* Made the branch optional and review suggestions
* Added network error test
* Unexpected response test
* PR review suggestions
* Updated test to include all responses
* Forgot one of the tests
* Add dynamic yaml badge
* Forgot package lock
* Switch tests to yaml data source
* Add yaml to the dynamic badge maker options
* Reorder to match documentation examples
* Reordered dynamic types to be alphabetical
* Removed regex as pinend commit makes it unnecessary and fixed url
* Removed unused import
* Add more YAML MIME types
* Removed duplicate tests which don't differ between data types
Make a clear distinction between programmer errors ("internal errors") and runtime errors, and allow configuring the server to let the programmer errors bubble up in development and unit testing. This saves a huge amount of time because it generates ordinary stack traces when things go wrong. And, if these errors occur in production, we'll catch them, and display **shields | internal error** which is the equivalent of a 500 error.
Instead of centralizing examples, specify them from within a service.
* Avoid duplication in service loading + refactor
* Avoid duplication in URLs, rename uri -> url in BaseService
This resolves the following error occurring in production:
```
TypeError: Cannot read property 'slice' of null
/home/m/shields/lib/suggest.js in twitterPage at line 63:31
const schema = url.protocol.slice(0, -1);
```
This resolves the following error occurring in production:
```
TypeError: Cannot read property 'slice' of null
/home/m/shields/lib/suggest.js in findSuggestions at line 40:33
const userRepo = url.pathname.slice(1).split('/');
```
We’ve cleared the backlog of pull requests needing adoption and closed the old ones out, so it seems best to remove this from the contributing guidelines.
* Set request options for dynamic json badges to include accept header of application/json and json:true
* Added headers for XML dynamic badges
* Added tests for dynamic badges to check correct Accept headers are set
This merges the `node-8` branch. The heavy lift was by @Daniel15 with refactoring from me and a patch by @RedSparr0w.
* New API for registering services (#963)
* Disable Node 6 tests on node-8 branch (#1423)
* BaseService: Factor out methods _regex and _namedParamsForMatch (#1425)
- Adjust test grouping
- Rename data -> queryParams, text -> message
* BaseService tests: Use Chai (#1450)
* BaseService: make serviceData and badgeData explicit and declarative (#1451)
* fix isValidStyle test (#1544)
* Run tests in Node 9, not Node 6 (#1543)
These tests should fail if something is accidentally changed that affects the SVG or JSON files. In the case of deliberate changes, we can update the snapshots.
* remove newlines from datauri
* update test, remove decode
* support multiline datauris
* replace whitespace before checking isDataUri
removed multiline support from regex
* prependPrefix set default as empty string
* update
* add dynamic xml badge support
* add tests
* dynamic badge add tests for query param
* remove try catch
* use `checkErrorResponse()`
* update tests
* [dynamic json] add test for multiple items
* Rebase, [dynamic xml] Add support for multiple items
* 404 response -> resource not found
* multiple results test less greedy regex
still alot of room for improvement to this test
* update dynamic badge gen
* add dynamic xml gen tests
* update tests id & path
* datalist -> select
* uri -> url
kept support for uri, incase of any already existing badges.
* split dynamic gen uri
* update query placeholder
Gratipay is gone :(
For #1359
This failure from https://circleci.com/gh/badges/shields/1411?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link
```
7) Gratipay
Receiving
[ GET http://localhost:1111/gratipay/Gratipay.json ]:
ValidationError: child "value" fails because ["value" with value "invalid" fails to match the required pattern: /^\$[0-9]+(\.[0-9]{2})?\/week/]
at Object.exports.process (node_modules/joi/lib/errors.js:190:19)
at internals.Object._validateWithOptions (node_modules/joi/lib/types/any/index.js:669:31)
at module.exports.internals.Any.root.validate (node_modules/joi/lib/index.js:139:23)
at Object.pathMatch.matchJSONTypes (node_modules/icedfrisby/lib/pathMatch.js:303:9)
at node_modules/icedfrisby/lib/icedfrisby.js:703:10
at IcedFrisbyNock._invokeExpects (node_modules/icedfrisby/lib/icedfrisby.js:1294:33)
at start (node_modules/icedfrisby/lib/icedfrisby.js:1274:12)
at Request.runCallback [as _callback] (node_modules/icedfrisby/lib/icedfrisby.js:1232:16)
at Request.self.callback (node_modules/request/request.js:186:22)
at Request.<anonymous> (node_modules/request/request.js:1163:10)
at IncomingMessage.<anonymous> (node_modules/request/request.js:1085:12)
at endReadableNT (_stream_readable.js:1056:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
```
* closes#1499 - update hhvm service
http://hhvm.h4cc.de... -> https://php-eye.com/api/v1/package...
* fix typo
* add switch breaks
* typo
* const & let vs var
* hhvm service tests
* unused const/var
* alias master & dev-master
* improved status messages - repo not found, branch not found
better tests: including invalidJSON fixture
* add service tests for NuGet v2 services
* fixup - test the correct endpoint
* remove superfluous try/catch blocks
* test the colors too
* use invalid json fixture
* Integrated Vaadin service to server.js & load age from color-formatters lib
* Added 8 tests for Vaadin services
* Added Vaadin badge to main page under Misc
* Used checkErrorResponse() and fix 404 test return value
* Removed maturity from URL field option
* Remove duplicate `age` module import
* Removed comment
* Changed several URI fields and fixed according tests
* Service tests for NPM total downloads
* Spread syntax removed
* service-tests/helpers/mocks.js -> service-tests/helpers/response-fixtures.js
* Another value an invalid JSON in response-fixtures
* Using invalidJSON helper in service tests
* Working example in a service test of microbadger
* isPercentage supports decimal and integer values
* Added a shield for calculating npm bundle sizes
* Fix linting errors
* Fixed badges for bundlephobia
* Remove un-required keywords
* Simplified handler based on feedback
* Use isFileSize for validation
* Convert camel-cased error codes to space separated ones
* Updated error format
* Fixed error formatting
* Renamed gzip to minzip
* Fixes lint error
* Remove test that times out
* refactor tests to make it more readable
* meaningless change
* use trim
* service tests for [cocoapods]
* Add tests for CocoaPods Endpoints
Bug fixes:
* Call `metrics.cocoapods.org` API endpoints over HTTPs
* Show correct left-side badge text on error in version/platform/license badges
* Handle null doc coverage gracefully
* Add handling for 'not found' responses
* drop last param to checkErrorResponse
* remove redundant line
* set badge label using more terse notation
* specify allowed platform values
* Fixed remaining CodeClimate badges
* Added explicit percentage keyword and dropped top level URL
* Merged the two badge handlers into one
* Removed trailing space
* Switched to "dash" URL style
* Reinstated top-level URL
* Swicthed to use letter as optional keyword
* Updated badge examples
* Cleaned up
* Changed badge label to technical debt
* Switched tests to more mainstream projects as previous ones were deleted
* Rearranged badge URLs and default formats
* Updated examples
* add test suite to formalise existing behaviour of shippable service
* throw more descriprive errors, use es6 declarations
* switch from SVG parsing to shippable API
* add test case for unexpected status code
* remove unused import
* link to source for status codes
* Show logos on social badges
* Revert "Showcase logos in social badges on the front page"
This reverts commit 61fa22b7e4.
* Update footer badges to all be social style
as per reverted commit 61fa22b7e4
Rather than depend on Shields production, use the GitHub auth info from CI. It's disorienting to have our own CI go down when production is down. It also makes it harder to review PRs when there are ops issues.
* [FIX] error colorscheme
* throw error if jsonpath query non existent
* fixup
* show brightgreen badge by default
* update test
* let -> var
* set lightgrey when no uri specified
* update tests
* red color for no uri specified
* dynamic badge use setBadgecolor()
* add tests for ruby gems version badge
* add tests for ruby gems users badge
* add tests for ruby gems rank badge
* add tests for ruby gems downloads badges
* don't allow 0th rank
* move version info to left side of badge
* fix: update nodejs version to latest LTS, to fullfill check-node-version. close#1437
* docs: add docker run example without shields.env file, because there is no such file in a repo and container wont start
* fix: docker build project, clean npm and run production mode. close#1373
For #1359
This failure from https://circleci.com/gh/badges/shields/1411?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link
```
26) Uptime Robot
Uptime Robot: Percentage (valid)
[ GET http://localhost:1111/uptimerobot/ratio/m778918918-3e92c097147760ee39d02d36.json ]:
ValidationError: child "value" fails because ["value" with value "99.992%" fails to match the required pattern: /^[0-9]+%$/]
at Object.exports.process (node_modules/joi/lib/errors.js:190:19)
at internals.Object._validateWithOptions (node_modules/joi/lib/types/any/index.js:669:31)
at module.exports.internals.Any.root.validate (node_modules/joi/lib/index.js:139:23)
at Object.pathMatch.matchJSONTypes (node_modules/icedfrisby/lib/pathMatch.js:303:9)
at node_modules/icedfrisby/lib/icedfrisby.js:703:10
at IcedFrisbyNock._invokeExpects (node_modules/icedfrisby/lib/icedfrisby.js:1294:33)
at start (node_modules/icedfrisby/lib/icedfrisby.js:1274:12)
at Request.runCallback [as _callback] (node_modules/icedfrisby/lib/icedfrisby.js:1232:16)
at Request.self.callback (node_modules/request/request.js:186:22)
at Request.<anonymous> (node_modules/request/request.js:1163:10)
at IncomingMessage.<anonymous> (node_modules/request/request.js:1085:12)
at endReadableNT (_stream_readable.js:1056:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
27) Uptime Robot
Uptime Robot: Percentage (valid, with numberOfDays param)
[ GET http://localhost:1111/uptimerobot/ratio/7/m778918918-3e92c097147760ee39d02d36.json ]:
ValidationError: child "value" fails because ["value" with value "99.967%" fails to match the required pattern: /^[0-9]+%$/]
at Object.exports.process (node_modules/joi/lib/errors.js:190:19)
at internals.Object._validateWithOptions (node_modules/joi/lib/types/any/index.js:669:31)
at module.exports.internals.Any.root.validate (node_modules/joi/lib/index.js:139:23)
at Object.pathMatch.matchJSONTypes (node_modules/icedfrisby/lib/pathMatch.js:303:9)
at node_modules/icedfrisby/lib/icedfrisby.js:703:10
at IcedFrisbyNock._invokeExpects (node_modules/icedfrisby/lib/icedfrisby.js:1294:33)
at start (node_modules/icedfrisby/lib/icedfrisby.js:1274:12)
at Request.runCallback [as _callback] (node_modules/icedfrisby/lib/icedfrisby.js:1232:16)
at Request.self.callback (node_modules/request/request.js:186:22)
at Request.<anonymous> (node_modules/request/request.js:1163:10)
at IncomingMessage.<anonymous> (node_modules/request/request.js:1085:12)
at endReadableNT (_stream_readable.js:1056:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
```
To fix service test that fails in CI (due to no github auth) https://github.com/badges/shields/issues/1359#issuecomment-354184074
- DRY getPhpReleases()
- Pass named options to regularUpdate
- Add json option
- php-version: Move helpers before functions, and move exports to end
- Avoid mutating the inputs
- Declare all the input and output keys
- Avoid recomputing escapeXml on the same values
- Capitalize social badge labels before measuring
* twitter | add error text
inaccessable = 404 etc
invalid user = no data returned from endpoint
invalid = error thrown
* Twitter add tests
* add test for twitter url badge
Ref: #1379
This takes a naive approach to font-width computation, the most compute-intensive part of rendering badges.
1. Add the widths of the individual characters.
- These widths are measured on startup using PDFKit.
2. For each character pair, add a kerning adjustment
- The difference between the width of each character pair, and the sum of the characters' separate widths.
- These are computed for each character pair on startup using PDFKit.
3. For a string with characters outside the printable ASCII character set, fall back to PDFKit.
This branch averaged 0.041 ms in `makeBadge`, compared to 0.144 ms on master, a speedup of 73%. That was on a test of 10,000 consecutive requests (using the `benchmark-performance.sh` script, now checked in).
The speedup applies to badges containing exclusively printable ASCII characters. It wouldn't be as dramatic on non-ASCII text. Though, we could add some frequently used non-ASCII characters to the cached set.
Add a class which applies display: none to badges we don’t want to see. This is accomplished by passing a `shouldDisplay` function along with each badge, which pulls the current query through a closure and applies it.
A bit roundabout, but it works.
The rest of the changes are refactors to avoid code duplication.
I decreased the debouce rate to 50, which seems to work well.
Fix#1314
I have a branch going to automatically generate stats on which services have tests, and make a line chart over time. I'm having a lot of fun with that so I'll keep at it.
Meanwhile, here is my subjective list of critical services, for #1358.
IcedFrisby/IcedFrisby#71 will allow us to set a per-test `timeout()` and per-test `retry()`, which should allow us to keep flaky tests green most of the time.
A slough of service tests are failing locally, though they are also failing in master and seem unrelated to these changes. (#1359)
IcedFrisby is maturing toward a 2.0 API. There's been one breaking change to the way dependencies are installed, and probably more changes to come in the API itself. Shields uses such a small part of that API that 2.0, when it's released, may not even affect us.
… so we can stop saying "you forgot to…" in code review. 😀
This idea has come up a number of times. If we can write code to detect a contributor guideline, this tool will message the contributor automatically in a pull request. This lets people fix their own problems, relieves maintainers and reviewers from nagging, and keeps anyone from having to constantly ask for more tests.
For futher reading:
- [How to use Danger well](http://danger.systems/js/usage/culture.html)
- [Examples of the kind of thing it can do](http://danger.systems/js/)
- [Dangerfile reference](http://danger.systems/js/reference.html)
I don’t like that our build goes red on master all the time due to flaky service tests. I thought I’d look into other CI services that would make it possible to run the scheduled tests nightly without causing those messages to show up.
CircleCI, Heroku CI, and Codeship were obvious choices. Heroku CI wasn’t free and I didn’t have any experience with Codeship, so I looked into CircleCI. I’ve used their 1.0 system a lot though this was my first time on their 2.0 system. As with earlier versions, they’ve put a lot of work into making the build fast – perhaps more than any other CI system I’ve seen.
I had such good results, my goal shifted from scheduled daily builds (that don’t litter our commit history with red builds) to improving the CI experience as a whole.
This change made a big impact:
- Build logs load much, much faster. In the test I just ran, 22 seconds to < 2 seconds, a 90% improvement.
- Status of each step shows up right in the GitHub UI, which makes it much faster to see exactly what’s failed.
- Builds run about 50-75% faster on account of parallelism.
- GitHub service tests are fixed. This has been a long-standing issue.
- Ability to ssh into a build container to debug failures.
Here’s what I did:
- Created custom Docker images with our dependencies. To be honest, I’m not even sure these are necessary, only to install the greenkeeper-lockfile. We could get dejavu from npm. They make startup very fast.
- Created an npm-install stage which loads all dependencies into node_modules and caches them.
- Created separate stages for our main tests, service tests, and frontend tests, and stages to run the main tests and service tests in Node 6. These run in parallel, up to four at a time.
- Separated service test ID output from the service test results themselves. (I check these often during the PR process, when I confirm that service tests actually ran. Because the production Shields server caches the title, after updating it you can’t tell whether the update is taking effect.)
- Added a personal access token for the shields-ci user. This should actually fix the long-standing issue #979. CircleCI provides an option to “Pass secrets to builds from forked pull requests,” which means unlike Travis, they’ll give us enough rope to shoot ourselves in the foot.
- Schedule a daily build, which runs all the service tests.
* Add test suite for BitBucket service integration
* Present BitBucket issues as a metric (for consistency with BitBucket PR endpoint and GitHub endpoints)
* Factor out a shared regex
* Fail cleanly if count is `undefined`
- Fix issue in Firefox 57 when run from static build
- Fix color parameter in dynamic badge maker
- Correctly apply maxAge in usage badges
- Follow the WHATWG lead and begin to standardize on URL, not URI (https://url.spec.whatwg.org/#goals)
Both of the depcheck's are throwing errors
OS: `Windows 10`
Node: `v8.7.0`
Current Output:
```cmd
npm run frontend-depcheck
> gh-badges@1.3.0 frontend-depcheck C:\Users\Dan\Documents\GitHub\shields
> check-node-version --node '>= 8.0'
C:\Users\Dan\Documents\GitHub\shields\node_modules\semver\semver.js:678
throw new TypeError('Invalid comparator: ' + comp);
^
TypeError: Invalid comparator: '
at Comparator.parse (C:\Users\Dan\Documents\GitHub\shields\node_modules\semver\semver.js:678:11)
at new Comparator (C:\Users\Dan\Documents\GitHub\shields\node_modules\semver\semver.js:662:8)
at C:\Users\Dan\Documents\GitHub\shields\node_modules\semver\semver.js:828:12
at Array.map (<anonymous>)
at Range.parseRange (C:\Users\Dan\Documents\GitHub\shields\node_modules\semver\semver.js:827:13)
at Range.<anonymous> (C:\Users\Dan\Documents\GitHub\shields\node_modules\semver\semver.js:769:17)
at Array.map (<anonymous>)
at new Range (C:\Users\Dan\Documents\GitHub\shields\node_modules\semver\semver.js:768:40)
at C:\Users\Dan\Documents\GitHub\shields\node_modules\check-node-version\index.js:119:32
at module.exports (C:\Users\Dan\Documents\GitHub\shields\node_modules\map-values\index.js:9:18)
npm ERR! Windows_NT 10.0.16299
npm ERR! argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Users\\Dan\\AppData\\Roaming\\npm\\node_modules\\npm\\bin\\npm-cli.js" "run" "frontend-depcheck"
npm ERR! node v8.7.0
npm ERR! npm v4.3.0
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! gh-badges@1.3.0 frontend-depcheck: `check-node-version --node '>= 8.0'`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the gh-badges@1.3.0 frontend-depcheck script 'check-node-version --node '>= 8.0''.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the gh-badges package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! check-node-version --node '>= 8.0'
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs gh-badges
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls gh-badges
npm ERR! There is likely additional logging output above.
npm ERR! Please include the following file with any support request:
npm ERR! C:\Users\Dan\AppData\Roaming\npm-cache\_logs\2017-12-04T00_30_04_974Z-debug.log
```
```cmd
npm run server-depcheck
> gh-badges@1.3.0 server-depcheck C:\Users\Dan\Documents\GitHub\shields
> check-node-version --node '>= 6.0 < 9.0'
The system cannot find the file specified.
npm ERR! Windows_NT 10.0.16299
npm ERR! argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Users\\Dan\\AppData\\Roaming\\npm\\node_modules\\npm\\bin\\npm-cli.js" "run" "server-depcheck"
npm ERR! node v8.7.0
npm ERR! npm v4.3.0
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! gh-badges@1.3.0 server-depcheck: `check-node-version --node '>= 6.0 < 9.0'`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the gh-badges@1.3.0 server-depcheck script 'check-node-version --node '>= 6.0 < 9.0''.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the gh-badges package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! check-node-version --node '>= 6.0 < 9.0'
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs gh-badges
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls gh-badges
npm ERR! There is likely additional logging output above.
npm ERR! Please include the following file with any support request:
npm ERR! C:\Users\Dan\AppData\Roaming\npm-cache\_logs\2017-12-04T00_32_13_243Z-debug.log
```
Looks like its due to `'` being used around the version rather than `"`.
This PR Output:
```cmd
npm run frontend-depcheck
> gh-badges@1.3.0 frontend-depcheck C:\Users\Dan\Documents\GitHub\shields
> check-node-version --node ">= 8.0"
```
```cmd
npm run server-depcheck
> gh-badges@1.3.0 server-depcheck C:\Users\Dan\Documents\GitHub\shields
> check-node-version --node ">= 6.0 < 9.0"
```
- Periodically log github auth information
- Tokens are hashed which reduces the security risk inherent in the logs
- A consistent hash is used so tokens can be correlated across the three data structures and across the three servers
- Add an admin endpoint for github auth information
- Tokens are returned as-is to enable troubleshooting (e.g. comparing our reqRemaining to github’s)
While working on #1288 I configured frontend tests. I'm going in a different direction with that, though it seems worth keeping the test configuration. I added tests for one of the helper methods.
- Heroku reads the Node version from package.json. We're about to upgrade to Node 8 so this change to `engines` is only pre-emptive. It won't have any effect on the production servers.
- The production deploy scripts were missing the frontend files. This fixes that.
- This modifies the build setup to allow `BASE_URL=/`, which makes all requests relative to the page itself. That simplifies deploying the "debugging" frontend to the production servers, and makes it easy to host the frontend on Heroku.
I rewrote the frontend in React using a module bundler. It's matched feature-for-feature with the current frontend, with only slight changes in the styling. I did not fuss about making the styling identical; the badge popup looks particularly different.
This makes the front end much easier to develop. I'm really looking forward to implementing #701, to which this paves the way.
This makes light use of Next.js, which provides webpack config and dev/build tooling. We’ll probably replace it with create-react-app or our own webpack setup because unfortunately it comes with a lot of runtime overhead (the build is 400k).
Let’s open new issues for bugs and features, and track other follow-ups here: https://github.com/badges/shields/projects/1
- Support single-server testing and a local dev server (like Next) that is on a different port from the shields server
- Refactor config schema
With this change, the suggestions work locally in #1273.
The version in Shields goes back to last August. I reviewed the commits and didn't see any obvious incompatibilities. Hopefully @espadrine can weigh in!
Provide greater consistency for badges related to versions. Fix#1181.
- the `version` function in `color-formatters` was previously returning the colour of the badge, but also its text with a leading _v_. It was broken down into two separate functions and the text formatting part was moved to `text-formatters`, where it really belongs.
- unit tests were added for these two functions in `color-formatters.spec` and `text-formatters.spec`, using Sazerac.
- as discussed in #1181, the leading _v_ was omitted for _xxxx-yy-zz_ date patterns. Any future exceptions can easily be added to the `ignoredVersionPatterns` pattern.
- the badge colour was previously switched to orange if a hyphen was found in the version string. This didn't seem ideal, instead pattern matching is done to find keywords such as `beta`, `alpha` or `snapshot`. Of course, this list can easily be extended.
- all badges related to versions now use the `versionText` and `versionColor` functions. There are a few rare exceptions, for instance in cases where the data returned by the service's API allows to figure things out without relying on any parsing/pattern matching (eg. `badgeData.colorscheme = prerelease ? 'orange' : 'blue';`, where `prerelease` is determined from an API's response).
This fixes a bug introduced in 076cb14, wherein we discarded tokens received
from other servers, and wherein we could save tokens with invalid
identification.
The bug was raised by Paul Melnikow.
Sazerac is a library for data-driven tests, where a series of tests asserts that the return value of a function matches the expected value. It provides nice syntax for tightening this up.
https://hackernoon.com/sazerac-data-driven-testing-for-javascript-e3408ac29d8c
This converts our tests to use it, and replaces some similar home-grown code.
I fixed one bug I encountered along the way: mikec/sazerac#12.
* Push frontend to production servers at /index.html
Local production builds will use local server instead of img.shields.io, to support local testing
* Restore https://img.shields.io to example URIs
* Add User Defined URL support
* Add test
* eslint fixes
* 100% coverage
* use JSONpath
* update try.html
* Update tests, restore prefix & suffix
* order dependencies alphabetically
* update jsonpath version dependency
* update url structure & move to query strings
* update error handling & remove xml refrences
* fix eslint errors
* update tests
* update dynamic badge generator
* url -> uri & decode uri
Allow an encoded url to be used.
needed for any uri that requires params in the address
* resolve conflicts
* update for new page generation
* check uri is defined
* add query params to `request-handler.js`
* eslint fixes
* add test for no uri specified
* move query params to be local to dynamic badge
* update tests
* dynamic badge gen use same base url as static badge
This piece of work makes sure preference is given to the user defined value if any, by adding missing calls to `getLabel` when the value of `badgeData.text[0]` is reassigned.
- Followup from #1163
- Retire try.html
- Separate build config for dev and production
- Move config for badge examples into the JS build
- Move the prod transform into npm scripts
- In the future this could be handled using a bundler plugin
- make website builds production build as before
- Run the production build in CI to make sure it’s working
- Build the frontend on Heroku
I developed this for #820 to provide the correct cache behavior when a service wants to use custom parameters from the query string.
For safety, only the declared parameters (and the global parameters) are provided to the service. Consequently, failure to declare a parameter results in the parameter not working at all (undesirable, but easy to debug) rather than indeterminate behavior that depends on the cache state (undesirable, but hard to debug).
The quoting style chnaged in b411f08.
This is to fix the production build, in which image links were all broken because they pointed to shields.io instead of img.shields.io.
This pull request sets us up to generate the badge examples dynamically from data and code.
Right now, try.html is still checked in, mostly for the benefit of reading this diff, though it should be removed on the next pass to avoid unnecessary complexity at merge time.
Add simple badge for Jenkins plugins: shows latest version published to Jenkins' repository (fetched from: https://updates.jenkins.io/update-center.actual.json).
Jenkins usually publishes plugin updates one to two times a day, so 4 hours is a reasonable timeout for this large payload.
Close#622
- Add tests to request-handler to prepare for some tweaks to caching for #820
- Clean up code in request-handler: renames, DRY, arrows, imports
- Allow for clean shutdown of `setInterval` code. This requires the ability to cancel autosaving.
- Upgrade to Mocha 4, and clean up so the process exits on its own (see mochajs/mocha#3044)
- Better encapsulate analytics
- `make setup` (i.e. `make`) in the dev tutorial seems an unnecessary step. Badges will load from my local server after a clone, as long as I open try.html.
Add link support to the following badges:
- flat
- flat-square
- plastic
Adjust social badge
- if only 1 link supplied the whole badge will use that link
- only use hover effects if badge contains a link
* Extended usage of the metric validators
* Fixed incorrect Worldpress test data
* Removed usages of Joi.equal for bare string literals
* Switched to proper star formatting and made tests more robust
* Removed debug
- use objects for social badges (excl examples)
- change from <a><img> -> <object>
- use shields.io for the github badge instead of ghbtns.com
- update twitter
This is a rewrite of #1084.
Also touches the implementation of `npm/v` to keep the implementations more consistent with each other.
Clean lint in master.
Closes#723.
This will allow us to create a review app for a pull request. A review app is a transient deploy of Shields with a unique URI. We can use it to interactively test new PRs without needing to run the branch locally.
Review apps would be especially useful, in conjunction with something like Netlify (#960), to test issues affecting SVG badge rendering on different browsers (#1132).
For the review app to be helpful for layout purposes, we're going to need Verdana on the CI machine. The font there is not measuring text correctly.
The Discord API occasionally returns Cloudflare HTML errors or invalid JSON, so in those cases it will fallback to the standard 'inaccessible' message. Some of the returned errors have uppercase letters, so toLowerCase() is used to stay consistent with the rest of shields.
Close#981
Fixes#746Fixes#848
Works by making the font-size `110px` instead of `11px` so the browser doesnt enforce the minimum font size and then scales the text down to 10%.
Also fixes the padding issue on Firefox.
Implements #1113.
Removed extra space in 2 cases (failing tests without this change):
1) Github downloads for latest release
[ GET http://localhost:1111/github/downloads/photonstorm/phaser/latest/total.json ]:
ValidationError: child "value" fails because ["value" with value "63k " fails to match the required pattern: /^[0-9]+[kMGTPEZY]?$/]
--
2) Github downloads-pre for latest release
[ GET http://localhost:1111/github/downloads-pre/photonstorm/phaser/latest/total.json ]:
ValidationError: child "value" fails because ["value" with value "34 " fails to match the required pattern: /^[0-9]+[kMGTPEZY]?$/]
--
3) Github downloads for specific asset from latest release
[ GET http://localhost:1111/github/downloads/atom/atom/latest/atom-amd64.deb.json ]:
ValidationError: child "value" fails because ["value" with value "3k [atom-amd64.deb]" fails to match the required pattern: /^[0-9]+[kMGTPEZY]? \[atom-amd64\.deb\]$/]
--
4) Github downloads-pre for specific asset from latest release
[ GET http://localhost:1111/github/downloads-pre/atom/atom/latest/atom-amd64.deb.json ]:
ValidationError: child "value" fails because ["value" with value "372 [atom-amd64.deb]" fails to match the required pattern: /^[0-9]+[kMGTPEZY]? \[atom-amd64\.deb\]$/]
Also, include `lib/suggest.js` which is part of the server, and rename `vendor` to `service-tests` to match the renames which occurred during the review of #937.
Use the endpoint on img.shields.io added in #1114 to fetch the PR title.
This sidesteps the authentication requirement, and helps with #979 – except for PRs that need to run the Github service tests, which will need a separate solution.
With this patch, the service tests run in a separate Travis job. That makes it easy to see whether a PR failure is resulting from unit tests/lint failures, or service tests, which are inherently flakier.
By running these in a single build stage, they will both run, even if the unit tests + lint fail. This is good, because it's helpful to see the result of a failed integration test, even when there's a lint or unit test failure.
It seems like a mistake from #870. Indeed, the code in that patch
defaults to shields.io for BASE_URL, but the author mentions they
think it defaults to img.shields.io: https://github.com/badges/shields/pull/870#discussion_r115143960
The correct value to maintain the behavior that was present prior
to the patch in question was indeed img.shields.io.
This adds badges for Github issues and pull requests. You can display the state, title, username, number of comments, age, time since last update, and state of checks.
Provides an endpoint the Shields CI can use to fetch PR titles for #979 and resolves#1011.
Because I despise nitpicking stuff like indentation and spacing in pull request comments, I'd like to nudge forward our automated style checking, at least for new files being added.
I don't want to totally rewrite server.js just to get automated style checking… the blame tracking is just too useful. So let's it's just take care of that when we start splitting it out.
More discussion in #948.
The intended behavior of the bracketed [github], [bower], [discord] service names in the pull request title is to trigger the designated service tests. That way, affected services can be proven working during code review, without needing to run tests on a dev machine, nor running all the slow (and flaky) service tests.
Example pull request titles:
- [Travis] Fix timeout issues
- [Travis Sonar] Support user token authentication
- [CRAN CPAN CTAN] Add test coverage
The observed behavior is that, whenever bracketed service names are provided, all of the service tests run.
This is due to a Mocha limitation, which is that exclusive tests (it.only and describe.only) can only be applied synchronously. In other words, if we try to fetch the PR title and then add exclusive tests in the callback, all the tests will run anyway. This is true even when using _mocha --delay, as we are, and is true whether I use request or node-fetch.
Undoubtedly this could be fixed, though it's not worth it. The problem is obscure and therefore low priority for Mocha, which is quite backlogged.
And, there is an easy workaround, which is to generate the list of services to test in a separate process.
The pull request script test:services:pr is now split into two parts. First the :prepare script infers the pull request context, fetches the PR title, and writes the list of affected services to a file. Then the :run script reads the list of affected services and runs the appropriate tests.
In addition to sidestepping the Mocha bug, this setup makes it easier to reason about and debug these two steps of the test runner on a dev machine, and since I can't get pipefail to work – and want to be able to run the steps separately – I'm not using Node's built in pre scripts.
Overall, separating these concerns this makes the test runner easier to reason about.
- Except for social badges, omit logos by default (#983)
- Omit the logo from a social badge using the query string: `?logo=`
(#983)
- Opt in to named logos using the query string: `?logo=appveyor`
- Provide custom logo data as before: `?logo=data:image/png;base64,...`
- Rewrite badge data functions, with unit tests
Unit tests are covering the new code very well, though the underlying
functionality (logos) is untested.
Close#983
- Update 'downloads'->'users' as label,
- added `/u/` as option
- kept `/d/` as an option for backwards compatibility
- moved example from 'Downloads'->'Misc' section
Closes#1016
The original code has been simplified as well, but commented out.
I don't think we need the original code using the issues API, as it has
some limitations (no label support, only up to 30, or 100 issues).
If Verdana.ttf can't be loaded, the font file pointed by the
FALLBACK_FONT_PATH environment variable will be loaded.
This fixes width computation errors that can occur with non-latin
characters when running with Docker.
- use `const` instead of `var` where possible
- use `'` instead of `"` consistently
- replace `forEach` loop with `reduce` call
Thanks to @Daniel15 for review!
* Add template for secret.json
- Move to faster and lighter Alpine base image
* Update documentation
* Update documentation
* Fix Github token config for secret.json
* Extend env file for Docker runtime configuration
- Update documentation
- Add gh_token for GH personal access token to secret template
* Change http to https in infoSite
* Update .dockerignore
* Update .gitignore
* Update dockerignore
* Remove ENV directive from Dockerfile
- Environment is needed at runtime, not at buildtime
* Docker: contain secret.json in private/
- Incorporates fix from 7c8b0e3d
* Use localhost in example env
* Use baseUrl in GitHub redirect
* Move GH personal token retrieval up
- To remove duplicate Promise.then()
* Typo in shields.example.env
According to http://central.sonatype.org/pages/ossrh-guide.html#releasing-to-central:
> Upon release, your component will be published to Central: this typically occurs within 10 minutes, though updates to search can take up to two hours.
So, besides the delay, if the indexing jobs for search.maven.org are paused (see https://issues.sonatype.org/browse/OSSRH-27247), it may take quite some time to see the last artifact version even though it has been actually released on Maven Central.
This uses 'latest' version instead of 'release' version. According to the Maven documentation of the maven-metadata.xml (http://maven.apache.org/ref/3.2.5/maven-repository-metadata/repository-metadata.html):
- 'latest': what the latest version in the directory is, including snapshots;
- 'release': what the latest version in the directory is, of the releases only.
Using the 'release' version would imply altering the behavior of the badge, i.e. getting the release version instead of the latest version, which could also be a snapshot version.
Fixes#846.
According to the [Mozilla documentation about regular expressions](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions), the special character '\w' is equivalent to '[A-Za-z0-9_]', which does not include the hyphen character (i.e. '-'). This cause the matching of services containing a hyphen to fail (e.g. 'maven-central').
Reorg of the tests: move them just alongside their code. The principle relates to grouping by coupling, not by function and is established in best-practice documents (e.g. https://github.com/focusaurus/express_code_structure#underlying-principles-and-motivations), despite its break from the tradition of a separate `test/` tree. All of today's tools can handle tests spread through the repository.
There are some good, if subtle consequences of this change:
- Since files are close at hand, friction is reduced at development time, which encourages that new tests are written to cover new behaviors.
- It's easier to find the tests that cover a particular piece of functionality.
- It's easier to see which code has tests and which doesn't.
- Eliminate manual testing which is error-prone and time consuming, and must be repeated many times through the PR review process
- Make contributing more fun. For many, fixing bugs and making new badges is faster and more satisfying with automated tests than with manual testing.
- Push out the work of testing new badges to a much broader net. The PR originator could write tests, but so could any other contributor who wants to push review along.
- Detect badge failures resulting from changes in vendor contracts without waiting for user reports.
- Detect and prevent regressions in the code.
- Be runnable, readable, writable, and editable by as many developers as possible, including those who may not be familiar with JavaScript test tools.
-- @paulmelnikow, @niccokunzmann, @Daniel15
The website relies on GitHub Pages. When created, that did not support
TLS. However, last year, support for TLS was added, as detailed
in the following blog post:
https://github.com/blog/2186-https-for-github-pages
- Build index.html at deploy time
- Update corresponding documentation references
- Since index.html is untracked, git add needs -f
- Clarify gh-pages generated commit message
- Improve Makefile dependencies related to website generation
As discussed in #936, tracking the index.html causes makes PRs longer / noisier
and causes extra merge conflicts. More importantly, it causes contributors to
inadvertently edit the wrong file, which causes extra work (#949) or
contributions to be lost (#898).
Since there's no need for index.html in development (everything uses try.html) a
logical solution is to generate and commit the index.html at deploy time.
Recording compiled or generated files in a deploy commit is a reasonable
practice for git-based deploys (Heroku, gh-pages, and others).
The old version of this was slightly "unsafe" for my taste, in that it depended
on the local copy of gh-pages (if it existed) and master. The new version just
replaces gh-pages with master + the new commit.
Closes#936.
Fixes#954 (the PR).
While working on some tests, I was having a tricky problem in a test suite. Eventually I tracked it down to an interaction between tests. I suspected the test library, but once I tried to make an isolated test case, I realized the test library was working fine. It turns out it was the server’s request cache. The fix is to clear the cache between tests.
Not needed for this PR, though I’m adding it to this branch because it conflicts with this change.
Running the server in process is necessary for the mock to work. This is an approach I’ve taken in the past. I experimented with this setup quite a bit when I was playing around with a test suite, and it seemed to work well enough. Setting `process.argv` is a admitedly a bit gross, though a cleaner approach would require more involved changes to `server.js`.
Given the chunks coming from imagemagick are getting stored memory and
then tucked into a cache, this function could as easily return a buffer
via callback. Streaming is just making it more complex. (And trickier to
test!)
In ef1a5159, the switch to using imagemagick made a faulty use of the library by
listening for an 'end' event that is never raised. As a result, the cache was
never populated.
In d985f81f, a fix that takes care of the fact that the previously mentioned
dead code relies on a non-existent variable caused it to kill the server when a
raster badge is requested twice, as what it stored in the cache was the pipe
transmitting chunks, not the chunks themselves, and the pipe (a Socket object)
cannot be subsequently sent through a pipe. The following error occured instead:
events.js:163
throw er; // Unhandled 'error' event
^
TypeError: Invalid non-string/buffer chunk
at chunkInvalid (_stream_readable.js:395:10)
at readableAddChunk (_stream_readable.js:150:12)
at DataStream.Readable.push (_stream_readable.js:136:10)
at DataStream._read (/home/m/shields/lib/svg-to-img.js:45:21)
at DataStream.Readable.read (_stream_readable.js:350:10)
at resume_ (_stream_readable.js:739:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
The OpenAPI Specification (formerly known as the Swagger RESTful API
Documentation Specification) defines a format for describing RESTful
APIs. The Swagger project provides a set of tools for working with this
format, including a hosted validator which provides a validation badge
and JSON result.[1] This commit adds shields.io support for this badge.
The service currently only provides validation of files conforming to
version 2.0 of the OpenAPI Specification. This commit adds a path
component for specifying the version under the assumption that the
validator may support version 3.0 or later as they are released.
It accepts the URL to validate as two path components, a scheme followed
by the rest of the URL, to match the convention used for the JIRA host
and webpage online shields.
Changes in v2:
- Use bitbucket in try.html example for clarity.
- Change /v/ in URL to /valid/ to avoid conflict with v=version.
1. https://github.com/swagger-api/validator-badge
Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
The following warning is emitted by Node.js:
> DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new
> Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or
> `Buffer.alloc()` instead.
This patch removes this warning.
Projects that have '0' technical debt would otherwise receive a
lightgrey badge instead of a brightgreen one.
Signed-off-by: Sebastian Hoß <mail@shoss.de>
The old LRU implementation stored a list's indices to reference items in that
list, but deletions from the list made indices point to the wrong slot.
Functionally, it meant that deleted slots were not guaranteed to be the oldest
slot.
Using a linked list fixes that.
Prior to this patch, time spend in badge.js (computing text width and
compressing the SVG with SVGO) averaged 8.4 ms.
After this patch, it clocks at 2.4 ms on average.
Assuming this is the CPU bottleneck, it means that servers used to only be able
to handle 119 req/s (empirically, it is closer to 100 req/s). It should now
handle 416 req/s (although a better guess is at 1/0.004 = 250 req/s).
- Use metric() for the displayed number
- Use encodeURI() for API parameters
- Explicitly use a condition expression instead of a number where a boolean is expected
Part of #790.
As raised by Adriaan (@agboom), the .github-user-tokens.json file was
incorrectly exposed, causing the risk of users' GitHub tokens to be used
by other entities for the purpose of increasing their rate limits by
pretending to be shields.io.
Mozilla's website uses that format.
Also, show star-rating as "4/5" instead of "4 stars" (which looks verbose, less
informative, and grammatically incorrect if there is a single star).
Add a link to the Linux Foundation Core Infrastructure Initiative (CII)
best practices badge, which uses the shields.io spec.
To see this, visit: https://bestpractices.coreinfrastructure.org/
and select "Projects".
.comment(`This pull request was merged to [{{ pull_request.base.ref }}]({{ repository.html_url }}/tree/{{ pull_request.base.ref }}) branch. This change is now waiting for deployment, which will usually happen within a few days. Stay tuned by joining our \`#ops\` channel on [Discord](https://discordapp.com/invite/HjJCwm5)!
After deployment, changes are copied to [gh-pages]({{ repository.html_url }}/tree/gh-pages) branch: `)
This is the home of Shields.io, home to the badge design specification, API documentation, and server code for Badges as a Service.
Shields is a community project. We invite your participation through
financial contributions, issues, and pull requests!
We invite participation through [GitHub Issues][], which we use much like a discussion forum. This repository should only contain non-implementation specific topics: specifications, design, and the web site.
## This implementation
Ways you can help
-----------------
Please see [INSTALL.md][] for information on how to start contributing code to
shields.io.
### Financial contributions
[INSTALL.md]: ./INSTALL.md
We welcome financial contributions in full transparency on our
[open collective](https://opencollective.com/shields). Anyone can file an
expense. If the expense makes sense for the development of the community, it
will be "merged" into the ledger of our open collective by the core
contributors and the person who filed the expense will be reimbursed.
Note that the root gets redirected to <http://shields.io>.
For testing purposes, you can go to `http://localhost/try.html`.
You should modify that file. The "real" root, `http://localhost/index.html`,
gets generated from the `try.html` file with a `make website`.
### Contributing code
## Ground rules
This project has quite a backlog of suggestions! If you're new to the project,
maybe you'd like to open a pull request to address one of them:
Please report **bugs** and discuss implementation specific concerns (performance characteristics, etc.) in the repository for the respective implementation.
## Adding support for a service
Please [open an issue][new issue] if you'd like to use Shields badges for a project that isn't yet supported.
- For services which require a hostname, the badge should be of the form
`/SERVICE/SCHEME/HOST/NOUN/PARAMETERS/QUALIFIERS.format`. For instance,
Function declarations are placed in `lib/`, not directly in `server.js`.
Logos
-----
We support a wide range of logos via [SimpleIcons][] and encourage you to [contribute logos to that project][simple-icons github].
We also accept logos directly. In general, we do this only when we have a corresponding badge on the homepage, (e.g. the Eclipse logo because we support service badges for the Eclipse Marketplace). We may also approve logos for tools widely used by developers (e.g. our Slack logo). We will happily consider all requests, but don't expect systematic approval, it's at the discretion of the maintainers.
Please minimize checked-in SVG files through [SVGO][]. You can use [svgomg][].
If you want to use a logo that does not meet our guidelines, a custom logo can be passed in a URL parameter by base64 encoding it. For example this badge  could be generated by calling: https://img.shields.io/badge/play-station-blue.svg?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEiIHdpZHRoPSI2MDAiIGhlaWdodD0iNjAwIj48cGF0aCBkPSJNMTI5IDExMWMtNTUgNC05MyA2Ni05MyA3OEwwIDM5OGMtMiA3MCAzNiA5MiA2OSA5MWgxYzc5IDAgODctNTcgMTMwLTEyOGgyMDFjNDMgNzEgNTAgMTI4IDEyOSAxMjhoMWMzMyAxIDcxLTIxIDY5LTkxbC0zNi0yMDljMC0xMi00MC03OC05OC03OGgtMTBjLTYzIDAtOTIgMzUtOTIgNDJIMjM2YzAtNy0yOS00Mi05Mi00MmgtMTV6IiBmaWxsPSIjZmZmIi8+PC9zdmc+
You can build and run the server locally using Docker. First build an image:
```console
$ docker build -t shields ./
Sending build context to Docker daemon 3.923 MB
Step 0 : FROM node:0.12.7-onbuild
…
Removing intermediate container c4678889953f
Successfully built 4471b442c220
```
Then run the container:
```console
$ docker run --rm -p 8080:80 shields
> gh-badges@1.1.2 start /usr/src/app
> node server.js
http://[::1]:80/try.html
```
Assuming Docker is running locally, you should be able to get to the application at http://localhost:8080/try.html. If you run Docker in a virtual machine (such as boot2docker or Docker Machine) then you will need to replace `localhost` with the actual IP address of that virtual machine.
# Main Server Sysadmin
- DNS round-robin between https://vps197850.ovh.net/try.html and https://vps244529.ovh.net/try.html.
- Self-signed TLS certificates, but `img.shields.io` is behind CloudFlare, which provides signed certificates.
- Using node v0.12.7 because later versions, combined with node-canvas, give inaccurate badge measurements.
- Using forever (the node monitor) to automatically restart the server when it crashes.
See https://github.com/badges/ServerScript for helper admin scripts.
# Links
See <https://github.com/h5bp/lazyweb-requests/issues/150> for a story of the
project's inception.
This is also available as a gem `badgerbadgerbadger`, [code here][gem].
Shields has been dedicated to the public domain. It is protected by the Creative Commons CC0 Universal Public Domain Dedication license. You can read the entire license below or at http://creativecommons.org/publicdomain/zero/1.0/deed.en.
# CC0 UNIVERSAL PUBLIC DOMAIN DEDICATION LICENSE
## Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
a. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
b. moral rights retained by the original author(s) and/or performer(s);
c. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
d. rights protecting the extraction, dissemination, use and reuse of data in a Work;
e. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
f. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
<p align="center"><sup><strong>An image server for legible and concise information. Our <a href="http://shields.io/">Homepage</a> | <a href="https://twitter.com/shields_io">Twitter</a></strong></sup></p>
As you can see from the zoomed 400% versions of these badges above, nobody is (really) using the same badge file and at normal size, they're hardly legible. Worst of all, they're completely inconsistent. The information provided isn't of the same kind on each badge. The context is blurry, which doesn't make for a straightforward understanding of how these badges are relevant to the project they're attached to and what information they provide.
As you can see below, without increasing the footprint of these badges, I've tried to increase legibility and coherence, removing useless text to decrease the horizontal length in the (likely) scenario that more of these badge thingies crop up on READMEs all across the land.

Examples
--------
This badge design corresponds to an old and now deprecated version which has since been replaced by beautiful and scalable SVG versions that can be found on [shields.io](http://shields.io).
* [SemVer](https://semver.org/) version observance: 
* amount of [Liberapay](https://liberapay.com/) donations per week: 
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/shields#sponsor)]
exports['The badge generator badges with logos should always produce the same badge simple-icons javascript logo custom color (rgba(46,204,113,0.8)) 1']=`
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](https://github.com/badges/shields/edit/master/doc/TUTORIAL.md) while you read it.
(1) Reading
-----------
You should read [CONTRIBUTING.md](../CONTRIBUTING.md)
You can also read previous
[merged pull-requests with the 'service-badge' label](https://github.com/badges/shields/pulls?utf8=%E2%9C%93&q=is%3Apr+label%3Aservice-badge+is%3Amerged)
to see how other people implemented their badges.
(2) Setup
---------
You should have [git](https://git-scm.com/) installed.
If you do not, [install git](https://www.linode.com/docs/development/version-control/how-to-install-git-on-linux-mac-and-windows/)
and learn about the [Github workflow](http://try.github.io/).
1. [Fork](https://github.com/badges/shields/fork) this repository.
7. Visit the website to check the front-end is loaded:
[http://127.0.0.1:3000/](http://127.0.0.1:3000/)
(3) Open an Issue
-----------------
Before you want to implement your service, you may want to [open an issue](https://github.com/badges/shields/issues/new?template=2_Badge_request.md) 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.
(4) Implementing
----------------
### (4.1) Structure and Layout
Service badge code is stored in the [/services](https://github.com/badges/shields/tree/master/services/) directory.
Each service has a directory for its files:
* In files ending with `.service.js`, you can find the code which generates
the badge and handles requests.
Sometimes, code for a service can be re-used.
This might be the case when you add a badge for an API which is already used
by other badges.
Replace `SERVICENAME` with your service name in the following:
* For services with a single badge, the badge code will generally be stored in
`/services/SERVICENAME/SERVICENAME.service.js`.
If you add a badge for a new API, create a new directory.
1. We declare strict mode at the start of each file. This prevents certain classes of error such as undeclared variables.
2. Our service badge class will extend `BaseService` so we need to require it. We declare variables with `const` and `let` in preference to `var`.
3. Our module must export a class which extends `BaseService`
4.`route()` declares a route. We declare getters as `static`.
*`base` defines the static part of the route.
*`pattern` defines the variable part of the route. It can include any
number of named parameters. These are converted into
regular expressions by [`path-to-regexp`][path-to-regexp].
5. All badges must implement the `async handle()` function. This is called to invoke our code. Note that the signature of `handle()` will match the capturing group defined in `route()` Because we're capturing a single variable called `text` our function signature is `async handle({ text })`. Although in this simple case, we aren't performing any asynchronous calls, `handle()` would usually spend some time blocked on I/O. We use the `async`/`await` pattern for asynchronous code. Our `handle()` function returns an object with 3 properties:
*`label`: the text on the left side of the badge
*`message`: the text on the right side of the badge - here we are passing through the parameter we captured in the route regex
*`color`: the background color of the right side of the badge
The process of turning this object into an image is handled automatically by the `BaseService` class.
To try out this example badge:
1. Copy and paste this code into a new file in `/services/example/example.service.js`
2. Quit the running server with `Control+C`.
3. Start the server again.
`npm start`
4. Visit the badge at <http://[::]:8080/example/foo.svg>.
It should look like this: 
The example above was completely static. In order to make a useful service badge we will need to get some data from somewhere. The most common case is that we will query an API which serves up some JSON data, but other formats (e.g: XML) may be used.
This example is based on the [Ruby Gems version](https://github.com/badges/shields/blob/master/services/gem/gem-version.service.js) badge:
1. As with the first example, we declare strict mode at the start of each file.
2. Our badge will query a JSON API so we will extend `BaseJsonService` instead of `BaseService`. This contains some helpers to reduce the need for boilerplate when calling a JSON API.
3. In this case we are making a version badge, which is a common pattern. Instead of directly returning an object in this badge we will use a helper function to format our data consistently. There are a variety of helper functions to help with common tasks in `/lib`. Some useful generic helpers can be found in:
4. We perform input validation by defining a schema which we expect the JSON we receive to conform to. This is done using [Joi](https://github.com/hapijs/joi). Defining a schema means we can ensure the JSON we receive meets our expectations and throw an error if we receive unexpected input without having to explicitly code validation checks. The schema also acts as a filter on the JSON object. Any properties we're going to reference need to be validated, otherwise they will be filtered out. In this case our schema declares that we expect to recieve an object which must have a property called 'status', which is a string.
5. Our module exports a class which extends `BaseJsonService`
6. As with our previous badge, we need to declare a route. This time we will capture a variable called `gem`.
7. We can use `defaultBadgeData()` to set a default `color`, `logo` and/or `label`. If `handle()` doesn't return any of these keys, we'll use the default. Instead of explicitly setting the label text when we return a badge object, we'll use `defaultBadgeData()` here to define it declaratively.
8. Our bage must implement the `async handle()` function. Because our URL pattern captures a variable called `gem`, our function signature is `async handle({ gem })`. We usually separate the process of generating a badge into 2 stages or concerns: fetch and render. The `fetch()` function is responsible for calling an API endpoint to get data. The `render()` function formats the data for display. In a case where there is a lot of calculation or intermediate steps, this pattern may be thought of as fetch, transform, render and it might be necessary to define some helper functions to assist with the 'transform' step.
9. The `async fetch()` method is responsible for calling an API endpoint to get data. Extending `BaseJsonService` gives us the helper function `_requestJson()`. Note here that we pass the schema we defined in step 4 as an argument. `_requestJson()` will deal with validating the response against the schema and throwing an error if necessary.
*`_requestJson()` automatically adds an Accept header, checks the status code, parses the response as JSON, and returns the parsed response.
*`_requestJson()` uses [request](https://github.com/request/request) to perform the HTTP request. Options can be passed to request, including method, query string, and headers. If headers are provided they will override the ones automatically set by `_requestJson()`. There is no need to specify json, as the JSON parsing is handled by `_requestJson()`. See the `request` docs for [supported options](https://github.com/request/request#requestoptions-callback).
* Error messages corresponding to each status code can be returned by passing a dictionary of status codes -> messages in `errorMessages`.
* A more complex call to `_requestJson()` might look like this:
```js
return this._requestJson({
schema: mySchema,
url,
options: { qs: { branch: 'master' } },
errorMessages: {
401: 'private application not supported',
404: 'application not found',
},
})
```
10. The `static render()` method is responsible for formatting the data for display. `render()` is a pure function so we can make it a `static` method. By convention we declare functions which don't reference `this` as `static`. We could explicitly return an object here, as we did in the previous example. In this case, we will hand the version string off to `renderVersionBadge()` which will format it consistently and set an appropriate color. Because `renderVersionBadge()` doesn't return a `label` key, the default label we defined in `defaultBadgeData()` will be used when we generate the badge.
This code allows us to call this URL <https://img.shields.io/gem/v/formatador.svg> to generate this badge: 
It is also worth considering the code we _haven't_ written here. Note that our example doesn't contain any explicit error handling code, but our badge handles errors gracefully. For example, if we call https://img.shields.io/gem/v/does-not-exist.svg we render a 'not found' badge  because https://rubygems.org/api/v1/gems/this-package-does-not-exist.json returns a `404 Not Found` status code. When dealing with well-behaved APIs, some of our error handling will be handled implicitly in `BaseJsonService`.
Specifically `BaseJsonService` will handle the following errors for us:
* API does not respond
* API responds with a non-`200 OK` status code
* API returns a response which can't be parsed as JSON
* API returns a response which doesn't validate against our schema
Sometimes it may be necessary to manually throw an exception to deal with a non-standard error condition. If so, standard exceptions can be imported from [errors.js](https://github.com/badges/shields/blob/master/services/errors.js) and thrown.
### (4.4) Adding an Example to the Front Page
Once we have implemented our badge, we can add it to the index so that users can discover it. We will do this by adding a couple of additional methods to our class.
```js
module.exports = class GemVersion extends BaseJsonService {
// ...
static get category() { // (1)
return 'version'
}
static get examples() { // (2)
return [
{ // (3)
title: 'Gem',
namedParams: { gem: 'formatador' },
staticExample: this.render({ version: '2.1.0' }),
keywords: ['ruby'],
},
]
}
}
```
1. The `category()` property defines which heading in the index our example will appear under.
2. The examples property defines an array of examples. In this case the array will contain a single object, but in some cases it is helpful to provide multiple usage examples.
3. Our example object should contain the following properties:
* `title`: Descriptive text that will be shown next to the badge
* `namedParams`: Provide a valid example of params we can substitute into
the pattern. In this case we need a valid ruby gem, so we've picked [formatador](https://rubygems.org/gems/formatador).
* `staticExample`: On the index page we want to show an example badge, but for performance reasons we want that example to be generated without making an API call. `staticExample` should be populated by calling our `render()` method with some valid data.
* `keywords`: If we want to provide additional keywords other than the title, we can add them here. This helps users to search for relevant badges.
Save, run `npm start`, and you can see it [locally](http://127.0.0.1:3000/).
### (4.5) Write Tests <!-- Change the link below when you change the heading -->
[write tests]: #45-write-tests
When creating a badge for a new service or changing a badge's behavior, tests
should be included. They serve several purposes:
1. They speed up future contributors when they are debugging or improving a
badge.
2. 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.
3. The contributor and reviewer can easily verify the code works as
intended.
4. 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](service-tests.md).
Please follow it to include tests on your pull-request.
## (5) Create a Pull Request
Once you have implemented a new badge:
* Before submitting your changes, please review the [coding guidelines](https://github.com/badges/shields/blob/master/CONTRIBUTING.md#coding-guidelines).
* [Create a pull-request](https://help.github.com/articles/creating-a-pull-request/) to propose your changes.
* CI will check the tests pass and that your code conforms to our coding standards.
* We also use [Danger](https://danger.systems/) to check for some common problems. The first comment on your pull request will be posted by a bot. If there are any errors or warnings raised, please review them.
* We'll work with you to progress your contribution suggesting improvements if necessary. Although there are some occasions where a contribution is not appropriate, if your contribution conforms to our [guidelines](https://github.com/badges/shields/blob/master/CONTRIBUTING.md#badge-guidelines) we'll aim to work towards merging it. The majority of pull requests adding a service badge are merged.
* If your contribution is merged, the final comment on the pull request will be an automated post which you can monitor to tell when your contribution has been deployed to production.
In order to enable integration with [Sentry](https://sentry.io), you need your own [Sentry DSN](https://docs.sentry.io/quickstart/#configure-the-dsn). It’s an URL in format `https://{PUBLIC_KEY}:{SECRET_KEY}@sentry.io/{PROJECT_ID}`.
### How to obtain the Sentry DSN
1. [Sign up](https://sentry.io/pricing/) for Sentry
2. Log in to Sentry
3. Create a new project for Node.js
4. You should see [Sentry DSN](https://docs.sentry.io/quickstart/#configure-the-dsn) for your project. Sentry DSN can be found by navigating to \[Project Name] -> Project Settings -> Client Keys (DSN) as well.
Start the server using the Sentry DSN. You can set it:
- by `SENTRY_DSN` environment variable
```
sudo SENTRY_DSN=https://xxx:yyy@sentry.io/zzz node server
```
- or by `sentry_dsn` secret property defined in `private/secret.json`
```
sudo node server
```
### Prometheus
Shields uses [prom-client](https://github.com/siimon/prom-client) to provide [default metrics](https://prometheus.io/docs/instrumenting/writing_clientlibs/#standard-and-runtime-collectors). These metrics are disabled by default.
You can enable them by `METRICS_PROMETHEUS_ENABLED` environment variable. Moreover access to metrics resource is blocked for requests from any IP address by default. You can provide a regular expression with allowed IP addresses by `METRICS_PROMETHEUS_ALLOWED_IPS` environment variable.
1. Import [Joi][] We'll use this to make assertions. This is the same library we use to define schema for validation in the main badge class.
2. If our `.service.js` module exports a single class, we can `require('../create-service-tester')` and use convention to create a `ServiceTester` object. Calling `createServiceTester()` inside `services/wercker/wercker.tester.js` will create a `ServiceTester` object configured for the service exported in `services/wercker/wercker.service.js`. We will add our tests to this `ServiceTester` object `t`.
1. The `create()` method adds a new test to the tester object.
The chained-on calls come from the API testing framework [IcedFrisby][].
Here's a [longer example][] and the complete [API guide][IcedFrisby API].
2. We use the `get()` method to request a badge. There are several points to consider here:
* We need a real project to test against. In this case we have used [wercker/go-wercker-api](https://app.wercker.com/wercker/go-wercker-api/runs) but we could have chosen any stable project.
* Note that when we call our badge, we are allowing it to communicate with an external service without mocking the reponse. We write tests which interact with external services, which is unusual practice in unit testing. We do this because one of the purposes of service tests is to notify us if a badge has broken due to an upstream API change. For this reason it is important for at least one test to call the live API without mocking the interaction.
* All badges on shields can be requested in a number of formats. As well as calling https://img.shields.io/wercker/build/wercker/go-wercker-api.svg to generate  we can also call https://img.shields.io/wercker/build/wercker/go-wercker-api.json to request the same content as JSON. When writing service tests, we request the badge in JSON format so it is easier to make assertions about the content.
* We don't need to explicitly call `/wercker/build/wercker/go-wercker-api.json` here, only `/build/wercker/go-wercker-api.json`. When we create a tester object with `createServiceTester()` the URL base defined in our service class (in this case `/wercker`) is used as the base URL for any requests made by the tester object.
3.`expectJSONTypes()` is an IcedFrisby method which accepts a [Joi][] schema.
Joi is a validation library that is build into IcedFrisby which you can use to
match based on a set of allowed strings, regexes, or specific values. You can
refer to their [API reference][Joi API].
4.`Joi.object().keys()` defines a Joi object schema containing some defined keys
5. We expect `name` to be a string literal `"build"`
6. Because this test depends on a live service, we don't want our test to depend on our API call returning a particular build status. Instead we should perform a "picture check" to assert that the badge data conforms to an expected pattern. Our test should not depend on the status of the example project's build, but should fail if trying to generate the badge throws an error, or if there is a breaking change to the upstream API. In this case we will use a pre-defined regular expression to check that the badge value looks like a build status. [services/test-validators.js](https://github.com/badges/shields/blob/master/services/test-validators.js) defines a number of useful validators we can use. Many of the common badge types (version, downloads, rank, etc.) already have validators defined here.
When defining an IcedFrisby test, typically you would invoke the `toss()`
method, to register the test. This is not necessary, because the Shields test
The `--only=` option indicates which service or services you want to test. You
can provide a comma-separated list here.
The `--` tells the NPM CLI to pass the remaining arguments through to the test
runner.
Here's the output:
```
Server is starting up: http://lib/service-test-runner/cli.js:80/
Wercker
Build status
✓
[ GET /build/wercker/go-wercker-api.json ] (572ms)
1 passing (1s)
```
That's looking good!
Sometimes if we have a failing test, it is useful to be able to see some logging output to help work out why the test is failing. We can do that by calling `npm run test:services:trace`. Try running
```
npm run test:services:trace -- --only=wercker
```
to run the test with some additional debug output.
### (4) Writing More Tests
We should write tests cases for valid paths through our code. The Wercker badge supports an optional branch parameter so we'll add a second test for a branch build.
```js
t.create('Build status (with branch)')
.get('/build/wercker/go-wercker-api/master.json')
.expectJSONTypes(
Joi.object().keys({
name:'build',
value:isBuildStatus,
})
)
```
```
Server is starting up: http://lib/service-test-runner/cli.js:80/
Wercker
Build status
✓
[ GET /build/wercker/go-wercker-api.json ] (572ms)
Build status (with branch)
✓
[ GET /build/wercker/go-wercker-api/master.json ] (368ms)
2 passing (1s)
```
Once we have multiple tests, sometimes it is useful to run only one test. We can do this using the `--fgrep` argument. For example:
```
npm run test:services -- --only="wercker" --fgrep="Build status (with branch)"
```
Having covered the typical and custom cases, we'll move on to errors. We should include a test for the 'not found' response and also tests for any other cusom error handling. The Wercker integration defines a custom error condition for 401 as well as a custom 404 message:
```js
errorMessages:{
401:'private application not supported',
404:'application not found',
}
```
First we'll add a test for a project which will return a 404 error:
.expectJSON({name:'build',value:'application not found'})
```
In this case we are expecting an object literal instead of a pattern so we should use `expectJSON()` instead of `expectJSONTypes()`. This is more concise and gives us a more helpful error message if the test fails.
We also want to include a test for the 'private application not supported' case. One way to do this would be to find another example of a private project which is unlikely to change. For example:
```js
t.create('Build status (private application)')
.get('/build/wercker/blueprint.json')
.expectJSON({name:'build',value:'private application not supported'})
```
## (5) Mocking Responses
If we didn't have a stable example of a private project, another approach would be to mock the response. An alternative test for the 'private application' case might look like:
Our test suite should also include service tests which receive a known value from the API. For example, in the `render()` method of our service, there is some logic which sets the badge color based on the build status:
```js
staticrender({status,result}){
if(status==='finished'){
if(result==='passed'){
return{message:'passing',color:'brightgreen'}
}else{
return{message:result,color:'red'}
}
}
return{message:status}
}
```
We can also use nock to intercept API calls to return a known response body.
Note that in these tests, we are passing the URL parameter `?style=_shields_test`. This returns a JSON response which also contains the color. This is helpful in a case like this when we want to test custom color logic, but it is only necessary to explicitly test color values if our badge implements custom logic for setting the badge colors. Using the `colorScheme` test helper here allows us to test against named colors instead of literal hex values, so we can write
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.