Compare commits

...

991 Commits
1.3.0 ... 2.1.0

Author SHA1 Message Date
chris48s
6f9dd95a18 cut a v2.1.0 release (#2354) 2018-11-18 17:53:08 +00:00
chris48s
dfa1f408d9 fix [bundlephobia] tests (#2355)
closes #2342
2018-11-18 17:47:00 +00:00
Paul Melnikow
282520041d Add [GitlabPipeline] badge (#2325)
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!
2018-11-18 10:06:47 -05:00
Paul Melnikow
a7efd88ceb Revert to standard CI image and remove lingering references to fonts (#2326)
Follow-on to #2311.
2018-11-18 09:08:23 -05:00
Paul Melnikow
3ad742e79a Example: Canonicalize urlPattern to pattern (#2341)
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.
2018-11-18 09:03:33 -05:00
Paul Melnikow
73fcc1ccac Deprecate old [StaticBadge] using a redirect (#2333)
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.
2018-11-17 15:22:03 -05:00
chris48s
da388b7079 add a smoke test for BadgeFactory (#2338) 2018-11-17 19:21:24 +00:00
chris48s
d3c454e0dd remove dependency on pdfkit (#2337) 2018-11-17 19:19:01 +00:00
dependabot[bot]
765dfacf72 Bump prom-client from 11.1.2 to 11.2.0 (#2316) 2018-11-17 16:31:34 +00:00
Paul Melnikow
9d77c8afe2 Rewrite [codacy] badges; rm unused svg helpers (#2275) 2018-11-17 09:51:20 -05:00
Paul Melnikow
84a5be3946 Declare static examples using namedParams (#2308)
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.
2018-11-17 09:47:25 -05:00
Paul Melnikow
00d5f87a77 BaseService Only accept valid extension sep, and simplify regex; test on [azuredevops] (#2307) 2018-11-17 09:41:08 -05:00
Paul Melnikow
ff9cd20821 Coverage cleanup (#2328)
- 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
2018-11-17 09:37:09 -05:00
Paul Melnikow
547380f794 Allow handle() to return a numeric message (#2332)
This regression from #2284 was causing `{ message: 22 }` to render as `’n/a’`, as in this test run: https://circleci.com/gh/badges/shields/23680
2018-11-17 09:32:57 -05:00
Paul Melnikow
065dd570ad Move [StaticBadge] to own service & add test; also affects [gitter] (#2284)
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.
2018-11-16 19:21:48 -05:00
dependabot[bot]
921adc9939 Bump eslint from 5.7.0 to 5.9.0 (#2329)
Bumps [eslint](https://github.com/eslint/eslint) from 5.7.0 to 5.9.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v5.7.0...v5.9.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-16 22:00:50 +00:00
dependabot[bot]
4c2494f20a Bump danger from 6.0.5 to 6.1.4 (#2324)
Bumps [danger](https://github.com/danger/danger-js) from 6.0.5 to 6.1.4.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/compare/6.0.5...6.1.4)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-16 21:52:49 +00:00
dependabot[bot]
0bf8ebea3a Bump fast-xml-parser from 3.12.5 to 3.12.7 (#2322)
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) from 3.12.5 to 3.12.7.
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-16 21:47:08 +00:00
Caleb Cartwright
6aa45e756b [AzureDevOpsCoverage] Adds Coverage Badge for Azure DevOps (#2327) 2018-11-16 02:40:52 -05:00
dependabot[bot]
3f0ac63ca7 Bump node-fetch from 2.2.1 to 2.3.0 (#2323)
Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.2.1 to 2.3.0.
- [Release notes](https://github.com/bitinn/node-fetch/releases)
- [Changelog](https://github.com/bitinn/node-fetch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bitinn/node-fetch/compare/v2.2.1...v2.3.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-15 18:06:57 -05:00
Paul Melnikow
51897b3c7e Precompute text width using a lookup table (#2311)
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
2018-11-15 17:27:21 -05:00
Paul Melnikow
fe05d00747 Move github examples into services/github (#2309) 2018-11-15 15:57:56 -05:00
Paul Melnikow
5d63effabc Fix a crasher in production (#2313)
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.
2018-11-15 14:25:46 -05:00
chris48s
b68ac16092 Move NPM package files out of /lib ; affects [resharper nuget myget dub chocolatey github] (#2300)
* 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
2018-11-15 18:48:01 +00:00
Emlyn Corrin
aed39bfde9 [Clojars] Add downloads badge (#2305)
Add Clojars downloads badge
2018-11-15 18:32:22 +00:00
dependabot[bot]
83e44b7e7d Bump prettier from 1.15.1 to 1.15.2 (#2321)
* Bump prettier from 1.15.1 to 1.15.2

Bumps [prettier](https://github.com/prettier/prettier) from 1.15.1 to 1.15.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/1.15.1...1.15.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Run prettier
2018-11-15 09:50:48 -05:00
dependabot[bot]
17716953f2 Bump eslint-config-prettier from 3.1.0 to 3.3.0 (#2304) 2018-11-15 00:44:59 +00:00
dependabot[bot]
81691c5bb3 Bump opn-cli from 3.1.0 to 4.0.0 (#2303) 2018-11-15 00:30:53 +00:00
dependabot[bot]
e46a6fbde1 Bump snap-shot-it from 6.1.10 to 6.2.3 (#2301)
Bumps [snap-shot-it](https://github.com/bahmutov/snap-shot-it) from 6.1.10 to 6.2.3.
- [Release notes](https://github.com/bahmutov/snap-shot-it/releases)
- [Commits](https://github.com/bahmutov/snap-shot-it/compare/v6.1.10...v6.2.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-14 19:19:36 -05:00
Paul Melnikow
5e99aad2de Rewrite [NuGet] badges including [myget chocolatey resharper powershellgallery] (#2257)
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
2018-11-14 17:28:15 -05:00
Paul Melnikow
510491f376 Try to fix recent CircleCI failures (#2306)
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.
2018-11-12 12:26:42 -06:00
Tien Pham
29fedc3448 Docs improvement (#2299) 2018-11-11 13:27:37 -06:00
Paul Melnikow
652d2e5611 Remove extra file checked in by mistake (#2298) 2018-11-11 09:48:32 -06:00
Marcin Mielnicki
a039fffe79 Refactor [Jetbrains] service; affects [eclipse-marketplace] (#2232)
* Refactor Jetbrains

* Test that custom parser options are provided

* Code refactoring

* Code refactoring

* url -> route

* package-lock.json updated
2018-11-10 16:05:00 +01:00
chris48s
d0fe97d136 refactor [docker] service (#2263) 2018-11-09 21:57:13 +00:00
chris48s
4b88590619 bump version (#2296) 2018-11-09 21:53:47 +00:00
Paul Melnikow
5dd4ee078b Start on the Github rewrite, with [GithubPullRequestCheckState] (#2253)
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.
2018-11-09 16:22:48 -05:00
Paul Melnikow
2bc2450d19 Fix hex colors in static examples (#2295)
Fix a regression from #2240 which was noticed here:

https://github.com/badges/shields/pull/2253#issuecomment-437415722
2018-11-09 15:26:03 -05:00
Paul Melnikow
3eac8ebbfb Rework GitHub acceptor and move to its own module (#2021)
Continue to merge the work from #1205.
2018-11-09 15:14:01 -05:00
Paul Melnikow
02ec19fd22 BaseService terminology: Rename url to route (#2278)
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`.
2018-11-09 15:11:03 -05:00
Paul Melnikow
c0f9a88719 Website: Tweak footer and usage (#2285) 2018-11-09 14:47:23 -05:00
Paul Melnikow
e4e5628207 Fix suggest on staging in Firefox (#2277)
Fix #2245
2018-11-09 14:06:13 -05:00
Paul Melnikow
c4af2cac53 Convert a bunch of URL formats to patterns (#2293)
Follow-on to #2279
2018-11-09 14:03:00 -05:00
dependabot[bot]
ec65291a11 Bump simple-icons from 1.9.12 to 1.9.13 (#2294)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.12 to 1.9.13.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-09 17:54:41 +00:00
dependabot[bot]
804c4e4a6f Bump danger from 4.4.8 to 6.0.5 (#2291)
Bumps [danger](https://github.com/danger/danger-js) from 4.4.8 to 6.0.5.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/compare/4.4.8...6.0.5)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-09 16:35:26 +00:00
Paul Melnikow
291f35d4ad Reduce duplication in badge regex/url patterns (#2279)
This reduces duplication in badge regex/url patterns, and reduces the need to understand regexes in order to create badges.

Ref: #2050
2018-11-08 15:05:44 -05:00
Paul Melnikow
611e58e43e Make a few github tests more reliable (#2292)
The version test is failing because the shields repo version is not a dotted version.
2018-11-08 14:48:44 -05:00
dependabot[bot]
e240409033 Bump prettier from 1.14.3 to 1.15.1 (#2289)
* Bump prettier from 1.14.3 to 1.15.1

Bumps [prettier](https://github.com/prettier/prettier) from 1.14.3 to 1.15.1.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/1.14.3...1.15.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Run prettier
2018-11-08 14:39:00 -05:00
dependabot[bot]
57e4d82a90 Bump joi from 14.0.3 to 14.0.4 (#2267)
Bumps [joi](https://github.com/hapijs/joi) from 14.0.3 to 14.0.4.
- [Release notes](https://github.com/hapijs/joi/releases)
- [Changelog](https://github.com/hapijs/joi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hapijs/joi/compare/v14.0.3...v14.0.4)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-08 19:31:25 +00:00
dependabot[bot]
c600bf4800 Bump node-fetch from 2.2.0 to 2.2.1 (#2276)
Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.2.0 to 2.2.1.
- [Release notes](https://github.com/bitinn/node-fetch/releases)
- [Changelog](https://github.com/bitinn/node-fetch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bitinn/node-fetch/compare/v2.2.0...v2.2.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-08 19:02:42 +00:00
chris48s
9c658a1345 fix [hexpm] validation (#2282)
closes #2272
2018-11-06 22:28:27 +00:00
chris48s
6199b1a878 add not found tests back in for [depfu hexpm requires] (#2281)
* add not found tests back in for [depfu hexpm requires]
* update the docs
2018-11-06 22:24:50 +00:00
chris48s
33d5f8f772 round [wordpress] rating (#2283)
closes #2280
2018-11-06 22:20:38 +00:00
Paul Melnikow
5019d81642 Add vso keyword to azure badges (#2274) 2018-11-06 16:17:49 -05:00
chris48s
b19d6d0072 refactor [bitbucket] service (#2261)
* refactor [bitbucket] service
2018-11-06 20:27:55 +00:00
dependabot[bot]
88402dd7a8 Bump simple-icons from 1.9.10 to 1.9.12 (#2273)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.10 to 1.9.12.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-06 12:00:09 +13:00
dependabot[bot]
c8ce4fabb4 Bump nock from 10.0.1 to 10.0.2 (#2266)
Bumps [nock](https://github.com/nock/nock) from 10.0.1 to 10.0.2.
- [Release notes](https://github.com/nock/nock/releases)
- [Changelog](https://github.com/nock/nock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nock/nock/compare/v10.0.1...v10.0.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-05 16:58:19 -05:00
Paul Melnikow
3bb392dfae Remove some duplicated URL generation code (#2240)
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
2018-11-05 16:55:49 -05:00
Paul Melnikow
e983f7bf3b Rewrite vso, rename to [AzureDevops], validate SVG [readthedocs] (#2252)
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.
2018-11-05 16:52:53 -05:00
Paul Melnikow
600c369823 Remove some uses of to-be-deprecated url.format and url.parse APIs (#2265)
See #2225
2018-11-05 16:48:04 -05:00
Marcin Mielnicki
ba94610840 package-lock.json aded for files in Now config file (#2264) 2018-11-05 21:07:32 +01:00
Marcin Mielnicki
bc4bd79e90 Metrics with Prometheus (#2069)
* 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
2018-11-04 18:54:43 +01:00
Thaddée Tyl
1460855d6b Upgrade to camp 17.2.2 (#2260)
This fixes remaining vulnerabilities raised by `npm audit`.

Follow-up to https://github.com/badges/shields/pull/2258.

Related issues from dependencies:

- camp upgrade: https://github.com/espadrine/sc/issues/64
- socket.io vulnerability: https://github.com/get/parsejson/issues/4
2018-11-04 12:00:28 +00:00
Paul Melnikow
d55e1c15a6 Enforce using async-await [f-droid] (#2241)
Close #2028
2018-11-04 00:33:47 -04:00
Paul Melnikow
72768d32d9 Fix some npm audit warnings (bump debug) (#2258)
The only remaining vulnerabilites are in scoutcamp: espadrine/sc#64.
2018-11-04 00:23:37 -04:00
Paul Melnikow
83ac6ff1b3 Enforce use of template literals (#2242)
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.
2018-11-02 17:11:44 -04:00
dependabot[bot]
4a298cbcb0 Bump husky from 1.1.2 to 1.1.3 (#2254)
Bumps [husky](https://github.com/typicode/husky) from 1.1.2 to 1.1.3.
- [Release notes](https://github.com/typicode/husky/releases)
- [Changelog](https://github.com/typicode/husky/blob/master/CHANGELOG.md)
- [Commits](https://github.com/typicode/husky/compare/v1.1.2...v1.1.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-02 20:39:38 +01:00
Paul Melnikow
8feb75d97d Move more badge examples into services/ (#2247)
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!
2018-11-01 19:39:28 -04:00
Paul Melnikow
cdb4cb36a4 Improve static example validation message (#2246) 2018-11-01 19:36:25 -04:00
dependabot[bot]
52d642cf91 Bump joi from 14.0.2 to 14.0.3 (#2251)
Bumps [joi](https://github.com/hapijs/joi) from 14.0.2 to 14.0.3.
- [Release notes](https://github.com/hapijs/joi/releases)
- [Changelog](https://github.com/hapijs/joi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hapijs/joi/compare/v14.0.2...v14.0.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-01 20:25:18 +00:00
dependabot[bot]
a5894c5350 Bump sinon from 7.1.0 to 7.1.1 (#2248)
Bumps [sinon](https://github.com/sinonjs/sinon) from 7.1.0 to 7.1.1.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v7.1.0...v7.1.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-01 20:18:21 +00:00
dependabot[bot]
f6b6b66fc2 Bump simple-icons from 1.9.9 to 1.9.10 (#2249)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.9 to 1.9.10.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-01 20:15:18 +00:00
Paul Melnikow
275805e90c Add BaseSvgScrapingService and rewrite [ReadTheDocs]; also affects [codacy vso] (#2229)
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.
2018-11-01 15:09:00 -04:00
piekar294
730dc67cdf Migrate babel 6.x to babel 7.1 (#2222)
* 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
2018-11-01 15:03:50 -04:00
Paul Melnikow
07b282fa1f Enforce property shorthand (#2243)
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.
2018-11-01 13:46:23 -04:00
Paul Melnikow
b7ecbd0a0d Move build badge examples into services/ (#2234)
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.
2018-10-31 17:32:35 -04:00
Paul Melnikow
973eeb0ea7 Make bintray test more reliable (#2239)
See https://circleci.com/gh/badges/shields/19875
2018-10-31 17:28:17 -04:00
Paul Melnikow
07c5f47a73 Rework [suggest] code using async/await (#2029) 2018-10-31 17:19:14 -04:00
Pierre-Yves B
cc843946d0 Readme examples (#2233) 2018-10-31 13:47:58 +00:00
Paul Melnikow
94611fb0e4 Rewrite server deploy script (#1793)
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`.
2018-10-30 17:08:52 -04:00
dependabot[bot]
d22fa6671e Bump snap-shot-it from 6.1.10 to 6.2.2 (#2227)
Bumps [snap-shot-it](https://github.com/bahmutov/snap-shot-it) from 6.1.10 to 6.2.2.
- [Release notes](https://github.com/bahmutov/snap-shot-it/releases)
- [Commits](https://github.com/bahmutov/snap-shot-it/compare/v6.1.10...v6.2.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-30 20:31:02 +00:00
dependabot[bot]
f9384d769b Bump react from 16.5.2 to 16.6.0 (#2213)
* Bump react from 16.5.2 to 16.6.0
* Bump react-dom from 16.5.2 to 16.6.0
2018-10-30 20:23:30 +00:00
chris48s
6fc8744bab Give the NPM package some love (#2200)
* 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()
2018-10-30 18:34:04 +00:00
piekar294
d7a52f3228 Make shippable preview bagde static (#2230) 2018-10-30 18:17:28 +00:00
dependabot[bot]
0a67631f2e Bump joi from 14.0.1 to 14.0.2 (#2235)
Bumps [joi](https://github.com/hapijs/joi) from 14.0.1 to 14.0.2.
- [Release notes](https://github.com/hapijs/joi/releases)
- [Changelog](https://github.com/hapijs/joi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hapijs/joi/compare/v14.0.1...v14.0.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-30 18:04:39 +00:00
dependabot[bot]
505940e194 Bump eslint from 5.7.0 to 5.8.0 (#2226)
Bumps [eslint](https://github.com/eslint/eslint) from 5.7.0 to 5.8.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v5.7.0...v5.8.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-29 22:22:11 -04:00
Danial
2ee98f92ce bump simple-icons version (#2231)
* bump simple-icons version

* require specific version
2018-10-29 21:58:17 -04:00
Tagan Hoyle
b6c851a377 Refactor [Requires]IO (#2220) 2018-10-28 16:19:39 +00:00
Paul Melnikow
e66d92f835 Add some error messages for the developer when .service.js is malformed (#1894)
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.
2018-10-28 15:58:38 +00:00
chris48s
87524976c9 upgrade to Joi 14; affects [elm-package jetbrains npmversion pypi vaadin-directory dynamic-xml] (#2221)
* 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
2018-10-28 15:56:19 +00:00
Paul Melnikow
6e51178e73 Make more consistent use of async/await (#2219)
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.
2018-10-28 11:34:47 -04:00
Tagan Hoyle
60592b8547 Refactor [Wordpress] Service (#2152) 2018-10-27 11:59:43 +01:00
Thomas Démoulins
979a34b831 #2082 Rename VSTS into Azure DevOps + update its documentation (#2206) 2018-10-27 09:54:31 +01:00
dependabot[bot]
c13da3d530 Bump sinon from 7.0.0 to 7.1.0 (#2217)
Bumps [sinon](https://github.com/sinonjs/sinon) from 7.0.0 to 7.1.0.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-27 09:48:14 +01:00
dependabot[bot]
edde74095a Bump nyc from 13.0.1 to 13.1.0 (#2185)
Bumps [nyc](https://github.com/istanbuljs/nyc) from 13.0.1 to 13.1.0.
- [Release notes](https://github.com/istanbuljs/nyc/releases)
- [Changelog](https://github.com/istanbuljs/nyc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/istanbuljs/nyc/compare/v13.0.1...v13.1.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-27 09:43:23 +01:00
dependabot[bot]
59fba5d173 Bump simple-icons from 1.9.7 to 1.9.9 (#2216)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.7 to 1.9.9.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-27 09:32:59 +01:00
Tagan Hoyle
6e8c71b01b Refactor [Swagger] Service (#2215) 2018-10-27 09:30:26 +01:00
chris48s
b866089c64 allow badge maxAge to be set by category; affects [discord] (#2205)
* allow badge maxAge to be set by category
* override default cache length for [discord]
* update maxAge docs
2018-10-26 20:08:02 +01:00
Pierre-Yves B
99ec8fa239 [eclipse-marketplace] License badge (#2212) 2018-10-25 20:53:34 +01:00
chris48s
744ef16009 refactor [depfu] service (#2204) 2018-10-23 18:24:14 +01:00
Pierre-Yves B
efb40fe4c0 Static Code Climate examples (#2201) 2018-10-23 18:12:29 +01:00
chris48s
8ee2701836 refactor [hexpm] service (#2203) 2018-10-23 18:06:57 +01:00
chris48s
aeceb283d8 switch [powershellgallery] to use temp url (#2189) 2018-10-23 18:03:50 +01:00
Anatoli Babenia
9df1da137c Document suggestion API endpoint (#2202) 2018-10-21 14:41:12 +01:00
Lentil Sun
88f10f8079 Fix: colorB override not working for Github Stars (#2171) 2018-10-21 14:33:12 +01:00
piekar294
6c09bc0998 add tests for [cookbook] service (#2197) 2018-10-21 14:21:09 +01:00
Przemo Nowaczyk
95f1b50194 test "static" gitter service behaviour (#2199) 2018-10-20 21:32:40 +02:00
Przemo Nowaczyk
4554f49c1e use most permissive license color (#2196)
* use most permissive license color

* revert to possible non-array licenseToColor argument
2018-10-20 15:15:10 +02:00
Przemo Nowaczyk
6f589a789a [ctan] refactor service (#2194)
* refactor ctan service

* fix service title

* prettier

* add single license test

* move example code to service
2018-10-20 14:51:25 +02:00
piekar294
2bba16c298 Remove use of componentWillReceiveProps() (#2192) 2018-10-20 09:11:36 +01:00
Ted Janeczko
a6fe16c5d1 Add support for private [npm] packages (#2187) 2018-10-20 08:06:36 +01:00
chris48s
32b123671c refactor [ansible] role service (#2158) 2018-10-19 19:23:41 +01:00
chris48s
990a80de49 use FONT_PATH in Dockerfile (#2179) 2018-10-19 19:21:34 +01:00
piekar294
37c317a758 remove react-warning-keys warning in renderNamedLogos (#2193) 2018-10-19 19:18:38 +01:00
Przemo Nowaczyk
999a24320e [ctan] add tests (#2191)
* add ctan tests

* prettier
2018-10-19 11:35:19 +02:00
Marcin Mielnicki
de1eb664ec Precommit hook with Prettier and ESLint (#2178)
* Precommit hook with prettier and eslint added

* Info about running prettier removed from documentation

* Info about a pre-commit hook in documentation
2018-10-19 11:16:30 +02:00
dependabot[bot]
8545d5ae27 Bump sinon from 6.3.5 to 7.0.0 (#2184)
Bumps [sinon](https://github.com/sinonjs/sinon) from 6.3.5 to 7.0.0.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v6.3.5...v7.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-18 20:35:54 +01:00
dependabot[bot]
3a5c5a7642 Bump eslint from 5.6.1 to 5.7.0 (#2182)
Bumps [eslint](https://github.com/eslint/eslint) from 5.6.1 to 5.7.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v5.6.1...v5.7.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-18 20:32:16 +01:00
dependabot[bot]
b230b78b74 Bump simple-icons from 1.9.6 to 1.9.7 (#2188)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.6 to 1.9.7.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-18 20:25:18 +01:00
Jowita Mielnicka
204680ec0a lightgrey color in build-unknown scrutinizer (#2172) 2018-10-15 21:50:30 +01:00
Jowita Mielnicka
9b6ba776f0 [bintray] test (#2175) 2018-10-14 20:55:04 +01:00
dependabot[bot]
5fd6686cce Bump danger from 4.4.7 to 4.4.8 (#2169)
Bumps [danger](https://github.com/danger/danger-js) from 4.4.7 to 4.4.8.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/compare/4.4.7...4.4.8)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-14 20:37:47 +01:00
Jowita Mielnicka
584fc99f54 [beerpay] test (#2174) 2018-10-14 19:49:26 +01:00
Jowita Mielnicka
fb6e91c3b2 standardize label on [cpan] license badge (#2173) 2018-10-14 19:31:47 +01:00
Jowita Mielnicka
89ff0687af standardize label on [bower] license badge (#2168) 2018-10-14 19:28:54 +01:00
Pyves
16dc2ec3a9 [Jenkins] coverage badges rewrite (#2154) 2018-10-11 21:42:47 +01:00
dependabot[bot]
89ca13a5d6 Bump semver from 5.5.1 to 5.6.0 (#2167)
Bumps [semver](https://github.com/npm/node-semver) from 5.5.1 to 5.6.0.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Commits](https://github.com/npm/node-semver/compare/v5.5.1...v5.6.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-11 21:28:45 +01:00
dependabot[bot]
e737666b73 Bump danger from 4.0.2 to 4.4.7 (#2166)
Bumps [danger](https://github.com/danger/danger-js) from 4.0.2 to 4.4.7.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/compare/4.0.2...4.4.7)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-11 21:18:35 +01:00
dependabot[bot]
c838067597 Bump snap-shot-it from 6.1.9 to 6.1.10 (#2165)
Bumps [snap-shot-it](https://github.com/bahmutov/snap-shot-it) from 6.1.9 to 6.1.10.
- [Release notes](https://github.com/bahmutov/snap-shot-it/releases)
- [Commits](https://github.com/bahmutov/snap-shot-it/compare/v6.1.9...v6.1.10)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-11 19:33:31 +01:00
dependabot[bot]
293767f761 Bump 2x react dependencies from 16.5.1 to 16.5.2 (#2099)
* Bump react-dom from 16.5.1 to 16.5.2
* Bump react from 16.5.1 to 16.5.2
2018-10-10 21:20:15 +01:00
Tagan Hoyle
74b6c4a700 Add [Steam] Service (#2140)
* Add Steam Service
2018-10-11 09:04:17 +13:00
dependabot[bot]
0265d4e429 Bump raven from 2.4.2 to 2.6.4 (#2051)
Bumps [raven](https://github.com/getsentry/raven-js) from 2.4.2 to 2.6.4.
- [Release notes](https://github.com/getsentry/raven-js/releases)
- [Commits](https://github.com/getsentry/raven-js/compare/2.4.2...raven-node@2.6.4)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-10 20:44:05 +01:00
dependabot[bot]
d1233a7676 Bump nock from 10.0.0 to 10.0.1 (#2161)
Bumps [nock](https://github.com/nock/nock) from 10.0.0 to 10.0.1.
- [Release notes](https://github.com/nock/nock/releases)
- [Changelog](https://github.com/nock/nock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nock/nock/compare/v10.0.0...v10.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-10 19:34:20 +01:00
dependabot[bot]
706f17a30a Bump simple-icons from 1.9.4 to 1.9.6 (#2162)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.4 to 1.9.6.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-10 19:27:46 +01:00
chris48s
9d7f27d84e add refactoring report (#2163) 2018-10-10 19:22:30 +01:00
chris48s
a74db34853 Allow [GitHub] tag badge to sort by date (#2157)
* add test for tag-pre
* support /releases-pre (but also allow /all for BC)
* allow GH tags to be sorted by date instead of semver
* fix license badge
2018-10-08 18:29:02 +01:00
chris48s
7ea540d3c6 refactor arch user repositories [aur] service (#2086) 2018-10-06 16:51:15 +01:00
chris48s
dea6df0ded bring back the [PyPI] downloads badges (#2131) 2018-10-06 16:38:41 +01:00
chris48s
819202bcf3 treat label as override in static badge (#2116)
closes #2112
2018-10-06 15:09:59 +01:00
Marcin Mielnicki
1d18e1048f bugfix: [CircleCI] uses 'github' as a default VCS (#2137)
* Circle CI uses 'github' as a default VCS

* Prettier code
2018-10-05 22:46:51 +01:00
Marcin Mielnicki
9b5ca7d0ed License's content and filename changed (#2146) 2018-10-05 22:40:46 +01:00
dependabot[bot]
fb76c7098e Bump snap-shot-it from 6.1.8 to 6.1.9 (#2147)
Bumps [snap-shot-it](https://github.com/bahmutov/snap-shot-it) from 6.1.8 to 6.1.9.
- [Release notes](https://github.com/bahmutov/snap-shot-it/releases)
- [Commits](https://github.com/bahmutov/snap-shot-it/compare/v6.1.8...v6.1.9)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-04 19:08:41 +01:00
dependabot[bot]
cb92998d80 Bump simple-icons from 1.9.3 to 1.9.4 (#2148)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.3 to 1.9.4.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-04 18:58:17 +01:00
dependabot[bot]
1d295a5e7e Bump sinon from 6.3.4 to 6.3.5 (#2149)
Bumps [sinon](https://github.com/sinonjs/sinon) from 6.3.4 to 6.3.5.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v6.3.4...v6.3.5)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-04 18:51:07 +01:00
dependabot[bot]
345d6222fc Bump query-string from 6.1.0 to 6.2.0 (#2141)
Bumps [query-string](https://github.com/sindresorhus/query-string) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/sindresorhus/query-string/releases)
- [Commits](https://github.com/sindresorhus/query-string/compare/v6.1.0...v6.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-03 20:30:48 +01:00
dependabot[bot]
ef9f4f9a52 Bump joi from 13.6.0 to 13.7.0 (#2135)
Bumps [joi](https://github.com/hapijs/joi) from 13.6.0 to 13.7.0.
- [Release notes](https://github.com/hapijs/joi/releases)
- [Changelog](https://github.com/hapijs/joi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hapijs/joi/compare/v13.6.0...v13.7.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-03 20:21:20 +01:00
dependabot[bot]
e84cd1f82f Bump eslint from 5.6.0 to 5.6.1 (#2136)
Bumps [eslint](https://github.com/eslint/eslint) from 5.6.0 to 5.6.1.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v5.6.0...v5.6.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-03 20:03:47 +01:00
dependabot[bot]
5d138e237d Bump simple-icons from 1.9.2 to 1.9.3 (#2142)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.2 to 1.9.3.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-10-03 19:35:33 +01:00
Sven Schoenung
c058dbdcd9 Fix: keywords missing from prepared examples (#2143) 2018-10-03 19:08:05 +01:00
chris48s
362db466bb update service tests tutorial (#2075)
* update service tests tutorial
* re-order and re-name tests for clarity
* update documentation examples
* extract boilerplate for testing colours
2018-10-01 20:53:04 +01:00
chris48s
ebe0c71488 require exampleUrl and urlPattern if using staticExample (#2132) 2018-10-01 20:48:05 +01:00
chris48s
aef9a4efd1 remove duplicate PyPI examples (#2133) 2018-10-01 20:44:08 +01:00
chris48s
595212ff78 consistently style Github as GitHub in examples (#2134) 2018-10-01 20:40:39 +01:00
Marcin Mielnicki
4ccd6bf4dc [Dub] downloads badge with available version (#2129)
* Service test for DUB tests the newset version

* Working example of the DUB downloads badge with version
2018-10-01 18:10:43 +02:00
Sven Schoenung
787ab36b6f Add [JenkinsPluginInstalls] service (#2125) 2018-09-30 21:57:53 +01:00
Christian Oliff
33167afa64 correct GitHub capitalization (#2095) 2018-09-30 21:19:34 +01:00
chris48s
10e8232ffa Add multiple issue templates (#2128) 2018-09-30 17:00:09 +01:00
dependabot[bot]
28d75cba81 Bump react-modal from 3.5.1 to 3.6.1 (#2119)
Bumps [react-modal](https://github.com/reactjs/react-modal) from 3.5.1 to 3.6.1.
- [Release notes](https://github.com/reactjs/react-modal/releases)
- [Changelog](https://github.com/reactjs/react-modal/blob/master/CHANGELOG.md)
- [Commits](https://github.com/reactjs/react-modal/compare/v3.5.1...v3.6.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-29 22:10:10 +01:00
dependabot[bot]
a940cb1f11 Bump babel-eslint from 10.0.0 to 10.0.1 (#2126)
Bumps [babel-eslint](https://github.com/babel/babel-eslint) from 10.0.0 to 10.0.1.
- [Release notes](https://github.com/babel/babel-eslint/releases)
- [Commits](https://github.com/babel/babel-eslint/compare/v10.0.0...v10.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-29 22:04:56 +01:00
chris48s
264f5e39dc refactor [discord] service (#2107) 2018-09-28 21:00:21 +01:00
dependabot[bot]
4ef2ea757b Bump simple-icons from 1.9.1 to 1.9.2 (#2123)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.1 to 1.9.2.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-27 19:49:19 +01:00
dependabot[bot]
a28ad3ceaf Bump babel-eslint from 9.0.0 to 10.0.0 (#2118)
Bumps [babel-eslint](https://github.com/babel/babel-eslint) from 9.0.0 to 10.0.0.
- [Release notes](https://github.com/babel/babel-eslint/releases)
- [Commits](https://github.com/babel/babel-eslint/compare/v9.0.0...v10.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-27 19:42:52 +01:00
dependabot[bot]
b18ea6cc85 Bump chai from 4.1.2 to 4.2.0 (#2124)
Bumps [chai](https://github.com/chaijs/chai) from 4.1.2 to 4.2.0.
- [Release notes](https://github.com/chaijs/chai/releases)
- [Changelog](https://github.com/chaijs/chai/blob/master/History.md)
- [Commits](https://github.com/chaijs/chai/compare/4.1.2...4.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-27 19:33:59 +01:00
chris48s
4f47cb348f fixes to [wercker] badge (#2103)
- 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"
2018-09-27 18:47:10 +01:00
chris48s
04290e890b delete snapshots with no corresponding test (#2111) 2018-09-24 21:19:13 +01:00
dependabot[bot]
0b8bfd6895 Bump danger from 4.0.1 to 4.0.2 (#2113)
Bumps [danger](https://github.com/danger/danger-js) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/compare/4.0.1...4.0.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-24 21:11:42 +01:00
dependabot[bot]
83b100184b Bump eslint-config-prettier from 3.0.1 to 3.1.0 (#2114)
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 3.0.1 to 3.1.0.
- [Release notes](https://github.com/prettier/eslint-config-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/compare/v3.0.1...v3.1.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-24 21:04:33 +01:00
dependabot[bot]
1dadd03f16 Bump simple-icons from 1.9.0 to 1.9.1 (#2115)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.9.0 to 1.9.1.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-24 20:58:40 +01:00
dependabot[bot]
58b75f5146 Bump snap-shot-it from 5.0.1 to 6.1.8 (#2072)
Bumps [snap-shot-it](https://github.com/bahmutov/snap-shot-it) from 5.0.1 to 6.1.8.
- [Release notes](https://github.com/bahmutov/snap-shot-it/releases)
- [Commits](https://github.com/bahmutov/snap-shot-it/compare/v5.0.1...v6.1.8)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-23 20:45:42 +01:00
dependabot[bot]
3577327243 Bump danger from 3.9.0 to 4.0.1 (#2090)
Bumps [danger](https://github.com/danger/danger-js) from 3.9.0 to 4.0.1.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/compare/3.9.0...4.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-23 20:33:33 +01:00
Pyves
8e963459cd Deprecated libscore (#2105) 2018-09-22 12:28:54 +01:00
Pyves
a4bec27771 Fixed [Codacy] coverage examples and improved unknown coverage handling (#2102) 2018-09-21 22:49:35 +01:00
dependabot[bot]
3c373b58ac Bump prettier from 1.14.2 to 1.14.3 (#2104)
Bumps [prettier](https://github.com/prettier/prettier) from 1.14.2 to 1.14.3.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/1.14.2...1.14.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-21 19:50:27 +01:00
dependabot[bot]
0b1ed5130e Bump svgo from 1.0.5 to 1.1.1 (#2094)
Bumps [svgo](https://github.com/svg/svgo) from 1.0.5 to 1.1.1.
- [Release notes](https://github.com/svg/svgo/releases)
- [Changelog](https://github.com/svg/svgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/svg/svgo/compare/v1.0.5...v1.1.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-21 19:47:04 +01:00
Sam Harwell
ca69099389 Support [nuget myget] packages using SemVer 2 (#2098)
Support NuGet packages using SemVer 2

Fixes #1044
2018-09-20 20:18:30 +01:00
chris48s
edab5385f8 show examples with logos on index page (#2084) 2018-09-19 22:05:38 +01:00
Christian Oliff
863ee4f2e0 HTTPS link to semver.org (#2093) 2018-09-18 16:30:38 +01:00
dependabot[bot]
a1347e5bf2 Bump nock from 9.6.1 to 10.0.0 (#2088)
Bumps [nock](https://github.com/nock/nock) from 9.6.1 to 10.0.0.
- [Release notes](https://github.com/nock/nock/releases)
- [Changelog](https://github.com/nock/nock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nock/nock/compare/v9.6.1...v10.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-18 16:22:03 +01:00
dependabot[bot]
f75cbf04c8 Bump eslint from 5.5.0 to 5.6.0 (#2089)
Bumps [eslint](https://github.com/eslint/eslint) from 5.5.0 to 5.6.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v5.5.0...v5.6.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-18 16:12:04 +01:00
dependabot[bot]
ac84735ad4 Bump sinon from 6.3.2 to 6.3.4 (#2097)
Bumps [sinon](https://github.com/sinonjs/sinon) from 6.3.2 to 6.3.4.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v6.3.2...v6.3.4)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-18 09:16:19 +01:00
chris48s
d143cac0d7 improve [appveyor] error handling (#2085) 2018-09-18 09:07:20 +01:00
Eugene Zhlobo
c8593c77c4 Handle CircleCI urls with token correctly (#2087) 2018-09-18 09:03:00 +01:00
dependabot[bot]
6d49c762b9 Bump simple-icons from 1.8.3 to 1.9.0 (#2070)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.8.3 to 1.9.0.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-16 21:49:26 +01:00
dependabot[bot]
ee2ce3747f Bump 2x react dependencies to 16.5.1 (#2080)
* Bump react-dom from 16.4.2 to 16.5.1
* Bump react from 16.4.2 to 16.5.1
2018-09-14 20:30:18 +01:00
dependabot[bot]
21dd7cdd16 Bump fast-xml-parser from 3.12.0 to 3.12.5 (#2071)
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) from 3.12.0 to 3.12.5.
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-14 20:16:32 +01:00
dependabot[bot]
a5943f7207 Bump sinon from 6.2.0 to 6.3.2 (#2081)
Bumps [sinon](https://github.com/sinonjs/sinon) from 6.2.0 to 6.3.2.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v6.2.0...v6.3.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-14 20:04:15 +01:00
Pyves
006710e16d Fixed [Codacy] badges (#2066) 2018-09-10 20:32:49 +01:00
Thomas Démoulins
2c04a63dc3 Support VSTS badges on newly created build definitions (#2065) 2018-09-10 19:30:47 +01:00
Pyves
bf0496cd64 Made JSON snapshot test pass on Windows (#2061) 2018-09-10 19:27:05 +01:00
Pyves
3e69873930 [aur packagist php-eye travis vaadin-directory github david jitpack twitter] Enforced lowercase badge labels (#2058) 2018-09-09 11:41:10 +01:00
Paul Melnikow
4a847d2b08 [AppVeyorTests] compact format and custom labels (#2000)
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.
2018-09-08 09:27:59 -07:00
dependabot[bot]
30dcc1fd41 Bump eslint-plugin-promise from 4.0.0 to 4.0.1 (#2063)
Bumps [eslint-plugin-promise](https://github.com/xjamundx/eslint-plugin-promise) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/xjamundx/eslint-plugin-promise/releases)
- [Changelog](https://github.com/xjamundx/eslint-plugin-promise/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xjamundx/eslint-plugin-promise/compare/v4.0.0...v4.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-07 21:55:16 -07:00
Tobias Roeddiger
a265cab354 fixed bug that prevented logo color from being changed (#2059)
closes #2057
2018-09-06 22:11:34 +01:00
dependabot[bot]
322f3ff305 Bump danger from 3.8.9 to 3.9.0 (#2056)
Bumps [danger](https://github.com/danger/danger-js) from 3.8.9 to 3.9.0.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/commits/3.9.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-06 21:11:41 +01:00
Thomas Démoulins
548b509dff [vso] Add support for VSTS releases (#2049) 2018-09-06 19:05:02 +01:00
dependabot[bot]
fc0c785f0e Bump eslint from 5.4.0 to 5.5.0 (#2048)
Bumps [eslint](https://github.com/eslint/eslint) from 5.4.0 to 5.5.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v5.4.0...v5.5.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-05 22:01:04 +01:00
dependabot[bot]
780d7a2470 Bump sinon from 6.1.5 to 6.2.0 (#2052)
Bumps [sinon](https://github.com/sinonjs/sinon) from 6.1.5 to 6.2.0.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v6.1.5...v6.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-05 21:54:52 +01:00
dependabot[bot]
636576aa60 Bump chai-string from 1.4.0 to 1.5.0 (#2047)
Bumps [chai-string](https://github.com/onechiporenko/chai-string) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/onechiporenko/chai-string/releases)
- [Commits](https://github.com/onechiporenko/chai-string/commits/v1.5.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-05 21:48:20 +01:00
chris48s
ef6e601aaa Update tutorial to reflect new service layout (#2042)
update the tutorial for new service class layout
2018-09-05 21:34:41 +01:00
Pyves
7417dc5f6c Delete BaseHTTPService and implement new BaseXmlService (affects [eclipse-marketplace f-droid]; also testing on [uptimerobot circleci]) (#2037) 2018-09-03 19:37:37 +01:00
chris48s
39d05ba817 render category links correctly on initial page load (#2046) 2018-09-02 21:15:07 +01:00
chris48s
4830867a5c add additional test cases for pypi license helper (#2043) 2018-09-02 21:11:28 +01:00
chris48s
bca4c05625 fix wercker examples (#2044) 2018-09-02 21:04:12 +01:00
dependabot[bot]
cc03507875 Bump danger from 3.8.6 to 3.8.9 (#2039)
Bumps [danger](https://github.com/danger/danger-js) from 3.8.6 to 3.8.9.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-09-02 20:59:43 +01:00
Paul Melnikow
1b307864b4 Prettify the files in the project root (#2041)
Follow on to #2009
2018-09-02 12:10:23 -07:00
Nicco Kunzmann
e25e748a03 Obsolete old tutorial and future TODOs (#1983)
This obsoletes the implementation part of the tutorial.
As mentioned in https://github.com/badges/shields/pull/1958#pullrequestreview-149661148, 
old style badges should be avoided and new style badges are preferred.
2018-09-02 11:41:33 -07:00
Y0hy0h
73c954df57 [elm-package] Fix old package name (#2045)
* Update test's package to new name
* Update preview badge's package to new name
2018-09-02 16:20:06 +01:00
Pyves
7153ed0bd1 Deprecate [issuestats] service (#2038) 2018-09-01 20:53:52 +01:00
Sam Lanning
b6ba720fae Add LGTM alerts badge to README (#2035) 2018-09-01 12:33:26 -07:00
Paul Melnikow
454575c4cb Enforce no extensions in require (#1999)
This removes remaining `.js` extensions from `require()` expressions and automatically enforces this rule.
2018-09-01 11:14:01 -07:00
Paul Melnikow
102141123b Unify lint rules and clean lint (#2009)
Now that server.js is emptied out, it makes sense to eliminate the differences between the top-level .js files and everything else.
2018-09-01 11:08:17 -07:00
Paul Melnikow
56bcc04570 Fix unparseable json in [circleci uptimerobot] (#2036)
* Add two tests: one passing, one failing

* Fix the bug
2018-09-01 09:05:14 -07:00
Nicco Kunzmann
11fa6114fe New badge: f-droid (#1965) 2018-08-30 23:02:09 +01:00
tooomm
e37c0b650d tidy danger bot messages (#2013) 2018-08-31 09:51:30 +12:00
Paul Melnikow
9fb540fb28 [pypi]: Fix broken badges (#2023)
- When license is empty, get license from trove classifiers
- Allow empty classifiers array
2018-08-30 14:30:40 -07:00
Paul Melnikow
7ad5eca26e Rewrite deprecated services and add tests (#2018)
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
2018-08-30 10:03:15 -07:00
Paul Melnikow
b602284403 Update coverage scripts (#2008)
As I was testing #1992 I noticed some of the coverage scripts were out of date.
2018-08-29 15:22:38 -07:00
Paul Melnikow
55f4017388 Combined update of eslint dependencies (#2007) 2018-08-29 15:01:25 -07:00
chris48s
7136aac89a update contributing guidance (#2019) 2018-08-29 22:36:24 +01:00
chris48s
17481f144a update logo submission docs (#2020)
add more detail to image submission guidelines
2018-08-29 22:32:46 +01:00
Paul Melnikow
1deeb365a5 Update uri -> url in the front end + examples (#2006)
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
2018-08-29 14:27:50 -07:00
Paul Melnikow
33fbfb374f Use render helpers in existing new-style services (#1998)
This refactors the render methods in these services to use the new helper functions.
2018-08-29 14:06:36 -07:00
Paul Melnikow
f8f2d88b90 Clean up some alerts detected by LGTM (#2010)
https://lgtm.com/projects/g/badges/shields/alerts/?mode=list
2018-08-29 13:37:43 -07:00
tooomm
15beda32b0 Additional tweaks to deployment bot message (#2011) 2018-08-29 19:09:02 +01:00
tooomm
119357333e tutorial: fix headline (#2014) 2018-08-29 11:22:54 -04:00
tooomm
0619e1072c fix identation (#2012) 2018-08-29 10:22:48 -04:00
Pyves
df30785c4b Improved deployment bot message (#1996) 2018-08-29 09:28:34 +01:00
dependabot[bot]
f4789125a7 Bump nyc from 12.0.1 to 13.0.1 (#1992)
Bumps [nyc](https://github.com/istanbuljs/nyc) from 12.0.1 to 13.0.1.
- [Release notes](https://github.com/istanbuljs/nyc/releases)
- [Changelog](https://github.com/istanbuljs/nyc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/istanbuljs/nyc/compare/v12.0.1...v13.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-29 02:52:12 -04:00
dependabot[bot]
16d415769f Bump babel-eslint from 8.2.6 to 9.0.0 (#1991)
Bumps [babel-eslint](https://github.com/babel/babel-eslint) from 8.2.6 to 9.0.0.
- [Release notes](https://github.com/babel/babel-eslint/releases)
- [Commits](https://github.com/babel/babel-eslint/compare/v8.2.6...v9.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-28 22:45:23 +01:00
Paul Melnikow
5bc26eaacf Use Joi 13.6.0 on the servers (#1989)
Ref: #1988
2018-08-28 15:16:14 -04:00
chris48s
e294dc4edc refactor [circleci] integration (#1927)
* refactor [circleci] integration
2018-08-28 15:49:43 +01:00
Y0hy0h
edea36dd10 [elm-package] Fix elm package service (#1986) 2018-08-28 10:25:58 -04:00
Paul Melnikow
64d325b002 Reduce boilerplate in a few more service testers [cdnjs continuousphp node shippable wercker gem] (#1957)
Follow up to #1934.
2018-08-27 16:36:35 -04:00
Paul Melnikow
bedba47d77 Move legacy services from server.js into services/ (#1958)
This builds on the work of #1931 by moving the legacy services into `services/`.
2018-08-27 13:29:54 -04:00
dependabot[bot]
f3037c5e15 Bump glob from 7.1.2 to 7.1.3 (#1981)
Bumps [glob](https://github.com/isaacs/node-glob) from 7.1.2 to 7.1.3.
- [Release notes](https://github.com/isaacs/node-glob/releases)
- [Changelog](https://github.com/isaacs/node-glob/blob/master/changelog.md)
- [Commits](https://github.com/isaacs/node-glob/compare/v7.1.2...v7.1.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-27 17:09:41 +01:00
dependabot[bot]
6b3d1ab010 Bump concurrently from 3.6.1 to 4.0.1 (#1980)
Bumps [concurrently](https://github.com/kimmobrunfeldt/concurrently) from 3.6.1 to 4.0.1.
- [Release notes](https://github.com/kimmobrunfeldt/concurrently/releases)
- [Commits](https://github.com/kimmobrunfeldt/concurrently/compare/3.6.1...v4.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-27 17:04:46 +01:00
Paul Melnikow
302c8606ff Rewrite [pypi]; affects [npm] (#1922) 2018-08-27 07:46:06 -04:00
tooomm
78bb890b52 danger: highlight service in msg (#1928) 2018-08-26 16:16:21 -04:00
Nicco Kunzmann
504b68ef13 Make wercker preview badge static (#1974) 2018-08-26 15:40:24 +01:00
Pyves
f377443585 Fixed Chrome Web Store examples (#1976) 2018-08-26 09:21:17 +01:00
Nicco Kunzmann
ed85e1cb12 Clarify what is used to run the specific tests (#1973) 2018-08-26 09:12:40 +01:00
Nicco Kunzmann
9428c20418 danger: help users to write server tests (#1970)
* danger: help users to write server tests

- fixes https://github.com/badges/shields/issues/1968
- adds the desired notice

* add trailing comma

https://circleci.com/gh/badges/shields/11866?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link
2018-08-25 17:55:02 +02:00
Pyves
ddb3bf4256 Fixed libraries.io error handling (#1964) 2018-08-24 18:32:28 +01:00
Nicco Kunzmann
dad1b4e4f1 Fix link to service tests (#1969) 2018-08-23 22:38:11 +01:00
tooomm
53cf4c1fe9 Remove gratipay from frontend (#1967) 2018-08-23 22:21:53 +01:00
Nicco Kunzmann
147d0e9bcc add examples for documentation contributions (#1962)
The section for documentation contribution is quite short.
This adds examples of when to make a contribution.
2018-08-23 16:32:11 -04:00
chris48s
ae190c5f07 generate static examples without api call [apm appveyor cdnjs clojars gem npm uptimerobot] (#1740)
* 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
2018-08-23 20:22:24 +01:00
Paul Melnikow
a0c43ed219 Reduce boilerplate for creating new testers [npm appveyor gem uptimerobot clojars] (#1934)
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.
2018-08-22 18:07:51 -04:00
Paul Melnikow
452affba15 Sort some more badges (#1948)
- 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
2018-08-22 15:05:11 -04:00
Paul Melnikow
942466aa92 Allow migrating legacy services to services/ (#1931) 2018-08-21 23:38:12 -04:00
dependabot[bot]
b8f81cf405 Bump semver from 5.5.0 to 5.5.1 (#1952)
Bumps [semver](https://github.com/npm/node-semver) from 5.5.0 to 5.5.1.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Commits](https://github.com/npm/node-semver/compare/v5.5.0...v5.5.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-20 21:28:20 +01:00
chris48s
c19695f628 don't run deploy bot on dependabot PRs (#1924)
Don't run deploy bot on dependabot PRs
2018-08-20 21:13:44 +01:00
Pyves
82bc90cec1 Deprecated VersionEye (#1953) 2018-08-20 20:04:11 +01:00
Paul Melnikow
656326d693 Rewrite [appveyor] tests badge (#1940) 2018-08-20 14:49:59 -04:00
dependabot[bot]
77061fe6af Bump eslint-plugin-promise from 3.8.0 to 4.0.0 (#1950)
Bumps [eslint-plugin-promise](https://github.com/xjamundx/eslint-plugin-promise) from 3.8.0 to 4.0.0.
- [Release notes](https://github.com/xjamundx/eslint-plugin-promise/releases)
- [Changelog](https://github.com/xjamundx/eslint-plugin-promise/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xjamundx/eslint-plugin-promise/compare/v3.8.0...v4.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-20 10:00:04 -04:00
dependabot[bot]
fd4637c042 Bump eslint from 5.3.0 to 5.4.0 (#1951)
Bumps [eslint](https://github.com/eslint/eslint) from 5.3.0 to 5.4.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v5.3.0...v5.4.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-20 09:56:28 -04:00
Paul Melnikow
77b54c8c9a Sort some badges (#1945)
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
2018-08-19 17:55:20 -04:00
Paul Melnikow
a16d436602 Optionally persist [Github] tokens in Redis (#1939)
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
2018-08-19 10:27:23 -04:00
Paul Melnikow
edb7d82500 Change format of [npm] type definitions badge (#1897)
Based on feedback at chalk/chalk#286.
2018-08-19 09:27:23 -04:00
Paul Melnikow
365f2cff5f Run tests by prefix e.g. [librariesio] (#1933)
Close #1923
2018-08-19 00:40:02 -04:00
Paul Melnikow
b10a6a4aa7 Refactor [github] token persistence, again (#1906)
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
2018-08-18 23:54:53 -04:00
Paul Melnikow
a252239018 Fix and test trace logging in BaseJsonService (#1944)
This fixes a regression introduced in #1929 which was caught by service tests post-merge.
2018-08-18 17:45:46 -04:00
Paul Melnikow
12be1bd747 Service logging tweaks (#1929)
- 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.
2018-08-18 11:25:40 -04:00
Paul Melnikow
544d2c538a Disable CircleCI cache (#1938)
See #1937
2018-08-18 10:34:48 -04:00
Marcin Mielnicki
96188c2f01 Example command for starting server with SENTRY_DSN after sudo (#1935) 2018-08-17 22:50:16 +02:00
Paul Melnikow
85de601024 Avoid warning during linting (#1930)
```
Warning: React version not specified in eslint-plugin-react settings. See https://github.com/yannickcr/eslint-plugin-react#configuration.
```
2018-08-16 21:59:31 -07:00
Pyves
886cde72d5 Rewrite [Wercker] service (#1920) 2018-08-16 22:03:15 +01:00
Paul Melnikow
9119c235a9 Prevent merging exclusive service tests (#1926)
* Remove an .only() left behind previously
2018-08-16 11:06:08 -07:00
dependabot[bot]
30d746653b Bump request from 2.87.0 to 2.88.0 (#1911)
Bumps [request](https://github.com/request/request) from 2.87.0 to 2.88.0.
- [Release notes](https://github.com/request/request/releases)
- [Changelog](https://github.com/request/request/blob/master/CHANGELOG.md)
- [Commits](https://github.com/request/request/compare/v2.87.0...v2.88.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-15 21:44:24 +01:00
dependabot[bot]
97c6795e4e Bump danger from 3.8.4 to 3.8.6 (#1917)
Bumps [danger](https://github.com/danger/danger-js) from 3.8.4 to 3.8.6.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-15 21:04:45 +01:00
dependabot[bot]
bcf3aca74e Bump eslint-plugin-react from 7.11.0 to 7.11.1 (#1921)
Bumps [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) from 7.11.0 to 7.11.1.
- [Release notes](https://github.com/yannickcr/eslint-plugin-react/releases)
- [Changelog](https://github.com/yannickcr/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yannickcr/eslint-plugin-react/compare/v7.11.0...v7.11.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-15 08:33:39 -07:00
Pyves
b0070ff861 [GitHub] Error message customisation for all status codes (#1888) 2018-08-14 18:57:24 +01:00
dependabot[bot]
b0f1d99e13 Bump eslint-plugin-react from 7.10.0 to 7.11.0 (#1915)
Bumps [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) from 7.10.0 to 7.11.0.
- [Release notes](https://github.com/yannickcr/eslint-plugin-react/releases)
- [Changelog](https://github.com/yannickcr/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yannickcr/eslint-plugin-react/compare/v7.10.0...v7.11.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-14 08:30:18 -07:00
dependabot[bot]
8e27ae0f2a Bump eslint-plugin-import from 2.13.0 to 2.14.0 (#1918)
Bumps [eslint-plugin-import](https://github.com/benmosher/eslint-plugin-import) from 2.13.0 to 2.14.0.
- [Release notes](https://github.com/benmosher/eslint-plugin-import/releases)
- [Changelog](https://github.com/benmosher/eslint-plugin-import/blob/master/CHANGELOG.md)
- [Commits](https://github.com/benmosher/eslint-plugin-import/compare/v2.13.0...v2.14.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-14 08:19:21 -07:00
dependabot[bot]
3b9d2325b8 Bump eslint-plugin-mocha from 5.1.0 to 5.2.0 (#1919)
Bumps [eslint-plugin-mocha](https://github.com/lo1tuma/eslint-plugin-mocha) from 5.1.0 to 5.2.0.
- [Release notes](https://github.com/lo1tuma/eslint-plugin-mocha/releases)
- [Changelog](https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/lo1tuma/eslint-plugin-mocha/compare/5.1.0...5.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-14 08:10:18 -07:00
dependabot[bot]
8b34a927dd Bump eslint-config-prettier from 2.9.0 to 3.0.1 (#1916)
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 2.9.0 to 3.0.1.
- [Release notes](https://github.com/prettier/eslint-config-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/compare/v2.9.0...v3.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-14 08:05:20 -07:00
dependabot[bot]
9c64589944 Bump nock from 9.5.0 to 9.6.1 (#1913)
Bumps [nock](https://github.com/nock/nock) from 9.5.0 to 9.6.1.
- [Release notes](https://github.com/nock/nock/releases)
- [Changelog](https://github.com/nock/nock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nock/nock/compare/v9.5.0...v9.6.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-13 19:14:04 +01:00
dependabot[bot]
909776ad6d Bump eslint-plugin-standard from 3.0.1 to 3.1.0 (#1909)
Bumps [eslint-plugin-standard](https://github.com/xjamundx/eslint-plugin-standard) from 3.0.1 to 3.1.0.
- [Release notes](https://github.com/xjamundx/eslint-plugin-standard/releases)
- [Commits](https://github.com/xjamundx/eslint-plugin-standard/compare/v3.0.1...v3.1.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-13 18:58:34 +01:00
dependabot[bot]
801bcf5bb8 Bump joi from 13.5.2 to 13.6.0 (#1912)
Bumps [joi](https://github.com/hapijs/joi) from 13.5.2 to 13.6.0.
- [Release notes](https://github.com/hapijs/joi/releases)
- [Changelog](https://github.com/hapijs/joi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hapijs/joi/compare/v13.5.2...v13.6.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-13 18:47:19 +01:00
Paul Melnikow
0c703c11b5 Rewrite [uptimerobot] (#1891) 2018-08-12 21:47:30 -07:00
Paul Melnikow
66d444aa40 Clean up our callback style and enforce no exclusive tests and remove an exclusive test (#1900)
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.
2018-08-12 20:45:43 -04:00
Paul Melnikow
0a7c833452 Fix an edge case in NpmBase (#1904)
I noticed this when I copied this code while I was working on #1895.
2018-08-12 19:13:31 -04:00
chris48s
0f534cefc0 use fetch/render pattern in [apm appveyor cdnjs clojars gem] (#1901)
* remove tests we don't need
* use fetch/render pattern in [apm appveyor cdnjs clojars gem]
2018-08-12 18:27:47 +01:00
Paul Melnikow
67193ce09b Add [librariesio-sourcerank] (#1898)
It seems like 30+ is great; under 10 pretty bad. I picked some values for a color scheme.

Closes #1532
2018-08-12 12:58:03 -04:00
Paul Melnikow
1a71acfa2e Add badge for dependents and dependent repos using Libraries.io (#1895)
See #1845
2018-08-12 11:05:43 -04:00
Paul Melnikow
2c646ae6ca Create Monitoring category (#1903) 2018-08-12 09:12:47 -04:00
Paul Melnikow
2a035d9111 ServiceTester: Minor readability tweak (#1893)
Was debugging this just now, and think this is easier to read and understand than the previous version.
2018-08-12 07:43:12 -04:00
Danial
b2af8f7a04 [GitHub] support issue tags with "/" character (#1902)
* support tags with "/" character
2018-08-12 15:20:30 +12:00
Paul Melnikow
9007658fd0 Refactor and test [github] token persistence (#1863)
Ref #1848 #1205
2018-08-11 20:13:40 -04:00
Paul Melnikow
39d393028d Fix and test the github admin route (#1886)
Fix regressions in the github admin and token acceptor endpoints, introduced in #1813.
2018-08-11 19:48:43 -04:00
Paul Melnikow
cd6c38a616 Add InvalidParameter runtime error and return inaccessible for 5xx errors (#1890)
* InvalidParameter: New error type
* Return inaccessible for 5xx errors from services
* Add test for Inaccessible on 5xx
* Add tests for named error types
2018-08-11 21:05:56 +01:00
Paul Melnikow
db4bffb300 Split BaseService and BaseJsonService into separate modules (#1889)
There’s a lot of behavior here, and going to be even more, so I think it makes sense to split these up as I’ve done with the tests.
2018-08-11 10:43:05 -04:00
Paul Melnikow
ed81dcbb36 npm downloads: Better experience for new projects (#1892)
When a new project is created, the download badge shows “project not found” as reported in #1882. This gives a more informative message in that case.
2018-08-11 10:18:41 -04:00
Danial
39776d5814 support for colorA + logo when no label specified (#1896)
* support for colorA + logo

* adjust spacing when no label present but logo is present
2018-08-11 15:33:29 +12:00
Paul Melnikow
09be682963 BaseService: Make it easier to add more config options (#1884)
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.
2018-08-10 16:02:58 -04:00
chris48s
f05a3496ee Validate response json in [apm appveyor cdnjs clojars gem] (#1883)
* split gem service into multiple files
* add validation to apm, appveyor, cdnjs, clojars & gem services
* fix the apm examples
2018-08-10 20:52:09 +01:00
dependabot[bot]
15a1449407 Bump redis from 2.6.5 to 2.8.0 (#1855)
Bumps [redis](https://github.com/NodeRedis/node_redis) from 2.6.5 to 2.8.0.
- [Release notes](https://github.com/NodeRedis/node_redis/releases)
- [Changelog](https://github.com/NodeRedis/node_redis/blob/master/changelog.md)
- [Commits](https://github.com/NodeRedis/node_redis/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-10 15:38:03 -04:00
Paul Melnikow
0db88d33e0 Add debug logging to BaseService and BaseJsonService (#1867)
Invoke this using `npm run test:services:trace`.
2018-08-10 15:22:13 -04:00
Paul Melnikow
ada1dec815 Lengthen timeout on a flaky service test (#1885) 2018-08-10 15:10:31 -04:00
dependabot[bot]
2ebb173a62 Bump simple-icons from 1.7.1 to 1.8.3 (#1877)
Bumps [simple-icons](https://github.com/simple-icons/simple-icons) from 1.7.1 to 1.8.3.
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-10 13:33:17 -04:00
dependabot[bot]
be8fbc2308 Bump babel-eslint from 8.0.2 to 8.2.6 (#1878)
Bumps [babel-eslint](https://github.com/babel/babel-eslint) from 8.0.2 to 8.2.6.
- [Release notes](https://github.com/babel/babel-eslint/releases)
- [Commits](https://github.com/babel/babel-eslint/compare/v8.0.2...v8.2.6)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-10 12:38:16 +01:00
dependabot[bot]
049530c7a9 Bump node-fetch from 2.0.0 to 2.2.0 (#1873)
Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.0.0 to 2.2.0.
- [Release notes](https://github.com/bitinn/node-fetch/releases)
- [Changelog](https://github.com/bitinn/node-fetch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bitinn/node-fetch/compare/v2.0.0...v2.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-10 12:36:26 +01:00
dependabot[bot]
96be0a94f9 Bump joi from 13.3.0 to 13.5.2 (#1879)
Bumps [joi](https://github.com/hapijs/joi) from 13.3.0 to 13.5.2.
- [Release notes](https://github.com/hapijs/joi/releases)
- [Changelog](https://github.com/hapijs/joi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hapijs/joi/compare/v13.3.0...v13.5.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-10 12:34:32 +01:00
dependabot[bot]
872fbf68b0 Bump eslint from 5.2.0 to 5.3.0 (#1876)
Bumps [eslint](https://github.com/eslint/eslint) from 5.2.0 to 5.3.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v5.2.0...v5.3.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-10 12:29:13 +01:00
dependabot[bot]
1640ff98c2 Bump sinon from 6.1.4 to 6.1.5 (#1875)
Bumps [sinon](https://github.com/sinonjs/sinon) from 6.1.4 to 6.1.5.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v6.1.4...v6.1.5)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-10 12:28:31 +01:00
Paul Melnikow
27170f85fc Rm greenkeeper config (#1871) 2018-08-09 11:07:14 -04:00
dependabot[bot]
fabc9f2b41 Bump nock from 9.3.2 to 9.5.0 (#1865)
Bumps [nock](https://github.com/nock/nock) from 9.3.2 to 9.5.0.
- [Release notes](https://github.com/nock/nock/releases)
- [Changelog](https://github.com/nock/nock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nock/nock/compare/v9.3.2...v9.5.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-09 10:34:10 -04:00
dependabot[bot]
8d669385e1 Bump classnames from 2.2.5 to 2.2.6 (#1850)
Bumps [classnames](https://github.com/JedWatson/classnames) from 2.2.5 to 2.2.6.
- [Release notes](https://github.com/JedWatson/classnames/releases)
- [Changelog](https://github.com/JedWatson/classnames/blob/master/HISTORY.md)
- [Commits](https://github.com/JedWatson/classnames/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-09 10:00:40 -04:00
dependabot[bot]
c7851e2d38 Bump prop-types from 15.6.0 to 15.6.2 (#1851)
Bumps [prop-types](https://github.com/facebook/prop-types) from 15.6.0 to 15.6.2.
- [Release notes](https://github.com/facebook/prop-types/releases)
- [Changelog](https://github.com/facebook/prop-types/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/prop-types/commits/v15.6.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-09 09:59:02 -04:00
dependabot[bot]
72d017d9ad Bump query-string from 6.0.0 to 6.1.0 (#1853)
Bumps [query-string](https://github.com/sindresorhus/query-string) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/sindresorhus/query-string/releases)
- [Commits](https://github.com/sindresorhus/query-string/compare/v6.0.0...v6.1.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-09 09:53:32 -04:00
dependabot[bot]
efe639a0c7 Bump js-yaml from 3.11.0 to 3.12.0 (#1860)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.11.0 to 3.12.0.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.11.0...3.12.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-09 09:52:44 -04:00
dependabot[bot]
68e6ed9d5a Bump prettier from 1.14.0 to 1.14.2 (#1869)
Bumps [prettier](https://github.com/prettier/prettier) from 1.14.0 to 1.14.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/1.14.0...1.14.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-09 09:47:07 -04:00
Paul Melnikow
8af48c0a21 Minor tweaks in [github] auth code (#1862)
* Move / rework is-valid-token

* TokenPool: Add allValidTokenIds method

* Minor cleanup in server.js
2018-08-09 07:22:54 -04:00
Paul Melnikow
c11d97a192 Refactor [github] initialization (#1861)
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
2018-08-09 07:20:57 -04:00
Paul Melnikow
7a664ca3e8 Run prettier (#1866)
Merging this separately so the commit with the tooling change is readable. This is a follow-on to #1167 which turned prettier on.
2018-08-08 17:57:14 -04:00
Paul Melnikow
ab051b3804 Turn on prettier (except repo root) (#1167)
* Use prettier-check
* Update semi option
    See discussion https://github.com/badges/shields/issues/948#issuecomment-349205606
* Developer documentation
* Run the same steps in both `main` jobs
* Move integration tests from `danger` to `main` where they belong
2018-08-08 17:49:06 -04:00
dependabot[bot]
ff15e9bdab Bump mocha from 5.0.0 to 5.2.0 (#1864)
Bumps [mocha](https://github.com/mochajs/mocha) from 5.0.0 to 5.2.0.
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v5.0.0...v5.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-08 17:28:59 -04:00
Paul Melnikow
e3b100504d Add Joi-based request validation to BaseJsonService and rewrite [NPM] and [node] badges (#1743)
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.
2018-08-08 17:08:16 -04:00
Pyves
e1affea266 [GitHub] Fix undefined badges (#1816) 2018-08-08 20:57:57 +01:00
dependabot[bot]
11cb3e3929 Bump danger from 3.8.3 to 3.8.4 (#1857)
Bumps [danger](https://github.com/danger/danger-js) from 3.8.3 to 3.8.4.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/compare/3.8.3...3.8.4)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-07 23:28:11 -04:00
Paul Melnikow
c7e28de025 Show test status on master, not latest build (#1859) 2018-08-07 23:27:35 -04:00
Paul Melnikow
56fcb2e5ba GithubApiProvider: injectible interface for code that calls github (#1812) 2018-08-07 16:46:12 -04:00
Pyves
da403b7e3a Increased default BADGE_MAX_AGE_SECONDS (#1846)
* Added note about default on website
2018-08-06 22:36:10 -04:00
chris48s
7cd0cb65d7 don't run danger on dependabot PRs (#1843) 2018-08-04 22:53:29 +01:00
dependabot[bot]
c69642a4e5 Bump eslint-plugin-react from 7.7.0 to 7.10.0 (#1837)
Bumps [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) from 7.7.0 to 7.10.0.
- [Release notes](https://github.com/yannickcr/eslint-plugin-react/releases)
- [Changelog](https://github.com/yannickcr/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yannickcr/eslint-plugin-react/compare/v7.7.0...v7.10.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-03 19:14:44 +01:00
dependabot[bot]
e20ab7c412 Bump sinon from 6.0.0 to 6.1.4 (#1832)
Bumps [sinon](https://github.com/sinonjs/sinon) from 6.0.0 to 6.1.4.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v6.0.0...v6.1.4)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-03 19:13:57 +01:00
dependabot[bot]
4e5b6d077f Bump concurrently from 3.5.1 to 3.6.1 (#1835)
Bumps [concurrently](https://github.com/kimmobrunfeldt/concurrently) from 3.5.1 to 3.6.1.
- [Release notes](https://github.com/kimmobrunfeldt/concurrently/releases)
- [Commits](https://github.com/kimmobrunfeldt/concurrently/compare/3.5.1...3.6.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-03 19:12:54 +01:00
dependabot[bot]
dee9524bd6 Bump check-node-version from 3.1.1 to 3.2.0 (#1828)
Bumps [check-node-version](https://github.com/parshap/check-node-version) from 3.1.1 to 3.2.0.
- [Release notes](https://github.com/parshap/check-node-version/releases)
- [Changelog](https://github.com/parshap/check-node-version/blob/master/CHANGELOG.md)
- [Commits](https://github.com/parshap/check-node-version/compare/v3.1.1...v3.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-03 19:08:21 +01:00
dependabot[bot]
89493f0eaf Bump eslint-plugin-import from 2.9.0 to 2.13.0 (#1836)
Bumps [eslint-plugin-import](https://github.com/benmosher/eslint-plugin-import) from 2.9.0 to 2.13.0.
- [Release notes](https://github.com/benmosher/eslint-plugin-import/releases)
- [Changelog](https://github.com/benmosher/eslint-plugin-import/blob/master/CHANGELOG.md)
- [Commits](https://github.com/benmosher/eslint-plugin-import/compare/v2.9.0...v2.13.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-03 19:05:23 +01:00
dependabot[bot]
672631a2d6 Bump eslint-plugin-promise from 3.6.0 to 3.8.0 (#1829)
Bumps [eslint-plugin-promise](https://github.com/xjamundx/eslint-plugin-promise) from 3.6.0 to 3.8.0.
- [Release notes](https://github.com/xjamundx/eslint-plugin-promise/releases)
- [Changelog](https://github.com/xjamundx/eslint-plugin-promise/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xjamundx/eslint-plugin-promise/compare/v3.6.0...v3.8.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-03 19:05:01 +01:00
dependabot[bot]
258fdd0fbc Bump sinon-chai from 3.0.0 to 3.2.0 (#1830)
Bumps [sinon-chai](https://github.com/domenic/sinon-chai) from 3.0.0 to 3.2.0.
- [Release notes](https://github.com/domenic/sinon-chai/releases)
- [Commits](https://github.com/domenic/sinon-chai/compare/v3.0.0...v3.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-03 19:02:11 +01:00
chris48s
cdce0b45e0 upgrade react and related dependencies (#1840) 2018-08-03 18:59:54 +01:00
Paul Melnikow
5d102dabb3 Update several lockfile dependencies using npm audit fix (#1833) 2018-08-03 18:46:12 +01:00
Paul Melnikow
2ff71dab6a Start cleaning up github auth routes (#1813)
- Move github token debug route to separate module
- Use crypto.timingSafeEqual
- Rename getTokenDebugInfo -> serializeDebugInfo
2018-08-01 21:58:11 -04:00
dependabot[bot]
2008623ba3 Bump gm from 1.23.0 to 1.23.1 (#1821)
Bumps [gm](https://github.com/aheckmann/gm) from 1.23.0 to 1.23.1.
- [Release notes](https://github.com/aheckmann/gm/releases)
- [Changelog](https://github.com/aheckmann/gm/blob/master/History.md)
- [Commits](https://github.com/aheckmann/gm/compare/1.23.0...1.23.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-01 22:22:39 +01:00
dependabot[bot]
dfdffa599c Bump moment from 2.19.3 to 2.22.2 (#1824)
Bumps [moment](https://github.com/moment/moment) from 2.19.3 to 2.22.2.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.19.3...2.22.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-01 22:19:22 +01:00
dependabot[bot]
d15250afcc Bump danger from 3.7.14 to 3.8.3 (#1822)
Bumps [danger](https://github.com/danger/danger-js) from 3.7.14 to 3.8.3.
- [Release notes](https://github.com/danger/danger-js/releases)
- [Changelog](https://github.com/danger/danger-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/danger/danger-js/commits/3.8.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-01 22:15:21 +01:00
dependabot[bot]
e4af2d485c Bump pretty-bytes from 5.0.0 to 5.1.0 (#1825)
Bumps [pretty-bytes](https://github.com/sindresorhus/pretty-bytes) from 5.0.0 to 5.1.0.
- [Release notes](https://github.com/sindresorhus/pretty-bytes/releases)
- [Commits](https://github.com/sindresorhus/pretty-bytes/compare/v5.0.0...v5.1.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-08-01 22:11:06 +01:00
Danial
317e19ea2a Add support for simple-icons, colored icons with ?logoColor (#1810)
* 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
2018-08-02 09:07:23 +12:00
greenkeeper[bot]
8020ff00e3 Update eslint to the latest version 🚀 (#1746)
* Work around upstream issue https://github.com/standard/standard/issues/1156#issuecomment-400048419
2018-08-01 16:55:42 -04:00
Paul Melnikow
7e04f25fc5 Tweak layout of services to conveniently handle large service families 2018-08-01 16:49:07 -04:00
chris48s
df8877ac71 don't try to run greenkeeper-lockfile-upload in CI build (#1819) 2018-08-01 21:23:47 +01:00
chris48s
7b10ba2f11 update dependabot tests (#1820) 2018-08-01 21:23:36 +01:00
chris48s
901a7b8a43 Split front end into one page per category (#1808)
- 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.
2018-08-01 21:02:55 +01:00
greenkeeper[bot]
ca01b99e9f Update prettier to the latest version 🚀 (#1814)
* chore(package): update prettier to version 1.14.0

* Update package-lock
2018-08-01 15:11:27 -04:00
Caleb Maclennan
547ea162ab Add Gitlab logo (#1804) 2018-08-01 14:49:00 -04:00
Pyves
9335f607aa [conda] Fixed wrong variable name (#1817) 2018-07-31 22:27:06 +01:00
Danial
3a54b5dc84 eslint enable comma-dangle always-multiline (#1818)
https://eslint.org/docs/rules/comma-dangle
2018-08-01 08:38:04 +12:00
chris48s
241cac7100 Fix [circleci] badge (#1815)
require all jobs in the build to pass in order for the status to be 'passing'
Closes #1792
2018-07-30 17:14:08 +01:00
Danial
c974b1b931 throw if given invalid version, refactor [apm] (#1785)
* throw if given invalid version

* refactor service

* add test

* fixup

* move service

* split up module

* update test

* add keywords

* remove from all-badge-examples

* update category [license → miscellaneous]

* Error → InvalidResponse

* minor style fix

* InvalidResponse

* reduce some code duplication

* fixup

* update category

* invalid → unparseable json response
2018-07-30 14:46:47 +12:00
Danial
409bcd1870 Add logo style badges - popout, popout-square (#1478)
* add logo style badges

add new styles:
- flat-logo
- flat-square-logo

* rename flat-logo -> popout

flat-logo -> popout
flat-square-logo -> popout-square

* default centered, add logoAlign param

* fix test

* logoAlign -> logoPosition

* reverse logoPosition direction

* fixup
2018-07-28 16:35:24 +12:00
Danial
329db7ddab loosely detect semver versions (#1628)
* 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
2018-07-27 08:27:48 +12:00
Danial
b216bcc17e Hide left hand of badge if no label (#1585)
* 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
2018-07-27 08:27:32 +12:00
Danial
bbfd75a203 increase timeout for colorscheme PNG badge test (#1811) 2018-07-26 17:54:23 +12:00
Paul Melnikow
f850126146 Bump icedfrisby version (#1803) 2018-07-25 13:47:33 -05:00
Paul Melnikow
fd58a5bdd0 Fix [bundlephobia] tests and rm errant inspectJSON (#1798)
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.
2018-07-25 13:46:14 -05:00
chris48s
d572abff4f re-organise badge examples (#1800)
Re-organise badge examples into categories:

- Build
- Chat
- Dependencies
- Downloads
- Funding
- Issue Tracking
- License
- Rating
- Social
- Version
- Other
2018-07-23 19:36:24 -05:00
Paul Melnikow
6e09a93cf0 Provide a descriptive message when json can’t be parsed (#1796)
* Test handling of invalid JSON on BaseJsonService
* Remove invalidJSON tests from new-style services
2018-07-23 19:35:42 -05:00
Danial
f5fe85cda2 Fix colorB override not working for static badges (#1801) 2018-07-23 18:33:32 -05:00
Paul Melnikow
5a62ed59fe List the named logos in the frontend (#1794)
Fix #1787
2018-07-23 15:19:55 -05:00
Paul Melnikow
5359adfb3f Do not prettify package.json (#1795)
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!
2018-07-23 14:35:52 -05:00
Paul Melnikow
91c3626aac Fix time service (#1791) 2018-07-22 08:26:36 -07:00
Danial
6711119bbb update eslint enable object-curly-spacing (#1789)
https://eslint.org/docs/rules/object-curly-spacing
2018-07-22 14:37:47 +12:00
Paul Melnikow
f9545af81d Fix edge case for service detection in PR titles [cran] [crates] (#1790)
Service detection didn’t work correctly for PR titles with multiple bracketed entries.

https://circleci.com/gh/badges/shields/6797
2018-07-21 09:53:55 -07:00
chris48s
b9db222c8a send longer cache headers by default (#1725)
* 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`
2018-07-20 20:24:02 +01:00
Thaddée Tyl
fd76819c62 Log request data when Travis errors (#1631)
Related: https://sentry.io/shields/shields/issues/503517592/
2018-07-19 19:29:39 -07:00
Paul Melnikow
e39b280d44 Fixes for github deploy (#1774)
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.
2018-07-18 19:46:27 -07:00
greenkeeper[bot]
6462cc49d5 Update eslint-plugin-node to the latest version 🚀 (#1786)
* chore(package): update eslint-plugin-node to version 7.0.0

* Update lockfile

* Update call to deprecated API
2018-07-18 18:36:54 -07:00
Danial
6a1f0f60b1 handle malformed url [dynamic-json] (#1782) 2018-07-17 12:50:36 +12:00
Hans Brende
3c594e8bcc fix for invalid [jenkins] tests (#1777)
* fix for invalid [jenkins] tests
2018-07-17 11:43:23 +12:00
Pyves
66c678e0dd [appveyor bitbucket buildkite circleci codeship continuousphp docker readthedocs scrutinizer shippable travis] Extracted isBuildStatus test validator (#1767) 2018-07-13 09:21:02 +01:00
Marcin Mielnicki
6f9f723d92 invalidJSON fixture documented (#1755) 2018-07-12 12:01:34 -04:00
greenkeeper[bot]
01f4bab4f6 Update prettier to the latest version 🚀 (#1749)
* chore(package): update prettier to version 1.13.6

* Update lockfile
2018-07-12 11:54:34 -04:00
chris48s
7de10783fa Deprecate [magnumci bithound] (#1770)
* deprecate Magnum CI badge

* deprecate BitHound badges
2018-07-11 23:30:52 -04:00
Brian Quinlan
c76090ac7f Add a reference to pybadges (#1773) 2018-07-11 23:17:54 -04:00
chris48s
0ec35ec9f8 add tests for composer version compare function (#1771) 2018-07-11 23:14:26 -04:00
Paul Melnikow
b3ec3e7a96 Generalized rotating token pool (#1736)
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.
2018-07-11 23:08:56 -04:00
Danial
d8cf836264 Add support for rgb, rgba, hsl, hsla, css named colors (#1635)
* 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
2018-07-12 10:26:17 +12:00
Marcin Mielnicki
9ca74740fa Using invalidJSON instead of other ways to mock an invalid JSON (#1756) 2018-07-11 22:43:32 +02:00
Thibault Jamet
6f54c1638e Add docker logo (#1750)
* Add docker logo
2018-07-11 13:12:13 +12:00
Marcin Mielnicki
8385f3ad7a Probot uses badges from img.shields.io (#1754) 2018-07-10 19:04:35 +02:00
Stanley Ng
85dd5f0809 Add [Jenkins] Jacoco coverage badge ☘ (#1593)
* 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
2018-07-10 18:12:26 +12:00
chris48s
036b191996 fix ansible galaxy role name badge (#1763) 2018-07-08 12:50:31 +01:00
chris48s
dc8bc9c5b4 update [bitrise] URL (#1764) 2018-07-08 12:50:19 +01:00
Pyves
8ad3bc7e90 [scrutinizer] Fix #1739, add tests and refactor (#1759)
* Added tests for Scrutinizer service

* Refactored service and fixed NaN bug

* Updated example

* Improved badge regex
2018-07-08 10:32:13 +01:00
chris48s
b05d93c9c1 fix [waffle] labels badge (#1745)
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
2018-07-05 19:06:06 +01:00
Grey Baker
e1e2a2ff2b Rename semver compatibility to semver stability (#1744) 2018-06-25 19:13:05 +01:00
Paul Melnikow
ec6d9031f0 Test in now-released Node 10 instead of Node 9 (#1738)
Also update `engines`.

Closes #1660
2018-06-19 16:37:02 -04:00
chris48s
def1bc331c fix [sonar] legacy/unsupported service tests (#1741) 2018-06-18 17:34:05 +01:00
Grey Baker
ca58d84447 Add [dependabot] SemVer compatibility badge (#1734)
* Add [dependabot] SemVer compatibility badge

* Add dependabot logo

* Clean up and additional tests
2018-06-17 21:32:57 +02:00
Paul Melnikow
028d8d7691 Fix sinon deprecation warning (#1737)
`sandbox.create()` is deprecated. Use default sandbox at `sinon.sandbox` or create new sandboxes with `sinon.createSandbox()`
2018-06-17 12:58:59 -04:00
Ivan de la Beldad Fernandez
4308b60c8f [Travis] Add travis-ci.com support (#1711) 2018-06-17 10:14:00 +02:00
greenkeeper[bot]
7cd3720edc Update prettier to the latest version 🚀 (#1641) 2018-06-16 16:45:02 -04:00
Paul Melnikow
fa61247dba Rewrite [npm] typedefs badge using new-style service (#1735)
For #1358
2018-06-16 16:38:52 -04:00
chris48s
f78e6f1f8a [gem cdnjs appveyor clojars] refactor clojars, establish BaseJsonService (#1702)
* refactor clojars integration

* DRY up services that request data from JSON endpoints
2018-06-16 20:50:14 +01:00
Paul Melnikow
20b8d0c3b8 BaseService: Query params (#1589)
Provide support for query parameters, in parity with the functionality in old-style services.
2018-06-16 13:10:02 -04:00
tooomm
fc3b793155 extend for pr in title (#1720) 2018-06-16 12:33:48 -04:00
greenkeeper[bot]
9612d5c6bb Update sinon to the latest version 🚀 (#1733)
* chore(package): update sinon to version 6.0.0

* update package-lock
2018-06-16 12:32:32 -04:00
Marcin Mielnicki
12e0164182 Probot workflow configuration with deployment status (#1724) 2018-06-15 17:17:20 +02:00
Marcin Mielnicki
2683f74a56 Required files added to now.json config (#1718) 2018-06-15 17:16:22 +02:00
chris48s
1f928281f2 allow 0 in all [cocoapods] download tests (#1728)
It appears this does not only
happen on the weekly stats.
refs https://github.com/badges/shields/pull/1713
2018-06-13 21:03:42 +01:00
chris48s
124748ecde Fix [codeclimate] tests (#1727)
* 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.
2018-06-10 22:20:21 +01:00
chris48s
67eb92e583 fix [dub] service test (#1729)
The version we were testing against
seems to have gone away - spooky 👻
https://code.dlang.org/api/packages/vibe-d/0.7.23/stats

Switch to a version that exists:
https://code.dlang.org/api/packages/vibe-d/0.7.27/stats
2018-06-10 22:18:15 +01:00
chris48s
e8980f70e8 fix 'not found' case in [node] badge (#1730)
NPM changed the error body,
breaking the not found case

Fix this by checking the status
code instead of relying on
the errror message in the body.
2018-06-10 22:17:52 +01:00
Marcin Mielnicki
b418235c7f Standard name in nuget v2 downloads badge (#1726) 2018-06-10 21:36:40 +02:00
Matthias Koch
7f9102dbb5 Add ReSharper gallery badge. (#1722) 2018-06-09 21:51:58 +02:00
chris48s
fa52c04439 allow 0 for cocoapods weekly downloads (#1713) 2018-06-07 20:08:53 +01:00
greenkeeper[bot]
707ada3718 Update snap-shot-it to the latest version 🚀 (#1715)
* chore(package): update snap-shot-it to version 5.0.1

* update package-lock
2018-06-03 15:09:58 +01:00
greenkeeper[bot]
83007a0c43 Update nyc to the latest version 🚀 (#1716)
* chore(package): update nyc to version 12.0.1

* update package-lock
2018-06-03 15:09:31 +01:00
chris48s
f4ea029e52 service tests for Arch Linux [aur] (#1707) 2018-06-02 19:04:23 +01:00
chris48s
e6559a0889 fix typescript regex in [npm] tests (#1712)
- Expect `TypeScript vX.Y | Flow vX.Y`
  instead of `TypeScript vX.Y Flow vX.Y`
- Allow version numbers to have more than >1 digit
  after the point
2018-06-02 19:03:55 +01:00
chris48s
57a1bf2f08 add more rules to dangerfile (#1703)
* upgrade danger.js to latest version

* If PR contains tests using assert, suggest expect syntax

* if PR touches service, check service tester also touched
2018-05-30 18:39:27 +01:00
Marcin Mielnicki
9d90bd1f95 [github] Commit merge status badge (#1709)
* 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
2018-05-30 18:51:52 +02:00
Eric Lordahl
7c7c9f5f04 Ensure both docker CMDs are invoked (#1686) 2018-05-30 09:10:58 +01:00
chris48s
de4e527f57 service tests for [libscore], improve error handling (#1706) 2018-05-29 09:41:42 +01:00
chris48s
8ba33d419f [bower clojars] version() should throw on invalid inputs (#1705)
Throw Error in version() on invalid inputs
2018-05-28 20:08:30 +01:00
chris48s
960c5bf72d upgrade sinon (#1697)
update sinon to version 5.0.7
2018-05-22 15:21:11 +01:00
chris48s
5d4ab86b1b upgrade to Joi 13.3.0 (#1696) 2018-05-22 15:20:51 +01:00
chris48s
3ff98bf038 update request (#1695)
update request to version 2.87.0
2018-05-22 15:20:34 +01:00
greenkeeper[bot]
c6b6183ee4 Update pretty-bytes to the latest version 🚀 (#1676)
* fix(package): update pretty-bytes to version 5.0.0

* update package-lock
2018-05-22 10:14:41 +12:00
Sebastian Staudt
498684cf24 Adapt to new JSON API of formulae.brew.sh (#1684) 2018-05-21 19:48:33 +01:00
mattbk
37617c1d4e Add Liberapay logo (#1692)
* Add Liberapay logo.

* Add variations.

* Optimize SVG.

* Remove logo testing variants.
2018-05-19 10:53:24 +12:00
Raziel
c76e221b47 [david] add support for path (#1687)
* Example with a path query parameter

* Support for David path query parameters

* David path not found test

* [david] updated invalid path test
2018-05-18 11:50:04 +12:00
Marcin Mielnicki
d51ae90270 Bugfix: override colorB in [docker] badges (#1690)
* 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
2018-05-16 18:11:26 +02:00
chris48s
bf53e612f5 [cdnjs gem] make exception classes more consistent (#1683)
make exception classes more consistent
2018-05-15 18:57:33 +01:00
Sam Lanning
4f8414c003 Add grade badge for [lgtm] (#1681)
* Add LGTM Grade badge

* Add new tests for LGTM Grade badge

* Add lgtm grade example to homepage
2018-05-12 10:30:48 +01:00
chris48s
b5635bf55a [gem cdnjs appveyor] refactor ruby gems service (#1680)
* 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'
2018-05-10 17:32:45 +01:00
Sam Lanning
f43096a2dd replace lgtm logo with improved one (#1679) 2018-05-10 19:19:38 +12:00
Marcin Mielnicki
6dab822a9c checkErrorResponse documented in the tutorial (#1675)
* 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
2018-05-09 18:01:51 +02:00
Pyves
3518b642e7 [MicroBadger] Fixed tests (#1677) 2018-05-07 21:47:36 +01:00
Sam Lanning
726dc9d916 Add LGTM logo (#1673) 2018-05-05 20:39:21 +01:00
chris48s
0ef1c947e2 open badge links in new tab (#1667) 2018-05-05 19:15:21 +01:00
Sam Lanning
45ff94d5a3 Add [LGTM] service (#1672) 2018-05-05 19:14:58 +01:00
chris48s
8fcc13d5bc refactor [cdnjs] integration (#1668)
* 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
2018-05-04 21:55:51 +01:00
Marcin Mielnicki
b126b4ebdc checkErrorResponse documented in service tests (#1670)
* Travis integration uses checkErrorResponse

* checkErrorResponse added to service tests doc
2018-05-02 16:06:09 +02:00
chris48s
714df8fac5 change CC0 example in GH service tests (#1634) 2018-04-28 20:59:27 +01:00
Danial
2e87ed9d46 add codeship logo (#1663)
* add codeship logo

* minify codeship logo
2018-04-28 14:25:56 +12:00
Zsófia Balogh
14bdaf378a [Codeship] fix status checking regexp & add new statuses (#1662)
* [Codeship] fix status checking regexp

we don't need to match the file extension to determine the status

* [Codeship] handle new build statuses

based on https://documentation.codeship.com/general/account/notifications/#webhook
2018-04-27 10:48:05 +12:00
Andrea Peruffo
a24d42a5bc minor links fix (#1658) 2018-04-25 10:05:08 +12:00
Raul Riera
f607ad787e Add [buildkite] service (#1657)
* 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
2018-04-24 08:13:24 +12:00
Omri
da108966cd Add NPM logo (#1656) 2018-04-23 10:47:16 +12:00
Danial
8fda86fcf1 set expires header corresponding to maxAge (#1651)
* set expires header corresponding to maxAge

* add tests
2018-04-22 13:48:01 +12:00
Thomas Broadley
2ded83f8a6 Documentation typos (#1647) 2018-04-15 20:43:51 +01:00
chris48s
d2a144e80f update [pypi] to use warehouse (closes #1569) (#1648) 2018-04-15 09:46:45 +01:00
Pyves
ac13fdb8d4 [librariesio] Missing try/catch block and tests (#1644) 2018-04-14 08:35:47 +01:00
Binh Bui
e1755df212 [vaadin-directory] Support star and stars endpoints (#1603) 2018-04-09 20:14:21 +01:00
Jacob Tomlinson
d56b6961da Add [dynamic-yaml] badge (#1623)
* 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
2018-04-08 21:47:28 +02:00
Rafał Pocztarski
47614e5bbc Add Stack Exchange logos (#1636)
* Add Stack Exchange logos

* Optimize Stack Exchange logos with svgomg

closes #1637
2018-04-06 04:07:26 +02:00
Danial
c0bdf54e4b optimize cssColor check regex (#1602)
* optimize cssColor regex

* Add comment & tests

* update test to not export cssColor

* [0-9] -> \d
2018-04-05 00:31:58 +02:00
Pyves
f98d17e00d [SourceForge] Fixes, tests and cleaning up (#1626) 2018-04-02 21:51:41 +01:00
Paul Melnikow
f2efd751b5 Minor refactor of examples preparation (#1632)
This cleans up the work from #1582, clarifying concerns, removing a bit of duplication, and renaming for clarity.
2018-04-02 07:03:52 -05:00
Pyves
a168072cd5 [DotnetStatus] Service deprecation (#1630) 2018-04-02 09:40:50 +01:00
Pyves
3aa21301ff [Ansible] Handle no data responses (#1629) 2018-04-02 09:38:25 +01:00
Paul Melnikow
416d433fa0 [appveyor] Error handling in BaseService (#1590)
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.
2018-04-01 22:04:22 -05:00
greenkeeper[bot]
724abd06dc Update svgo to the latest version 🚀 (#1473)
* fix(package): update svgo to version 1.0.5
* Update package-lock
* Update invocation for SVGO 1.x
* Remove helper
2018-04-01 21:57:20 -05:00
Paul Melnikow
f9b0aed8c9 package-lock fixes for glob (#1633)
Missing from #1619
2018-04-01 21:31:43 -05:00
Pyves
dd35739c5c [CodeClimate] Added missing try-catch block (#1613)
* Added missing try-catch block

* Added tests to cover malformed responses
2018-04-01 17:32:43 +02:00
Pyves
c5884b1915 Handled capitalization with empty keys (#1625) 2018-04-01 09:46:13 +01:00
Danial
57008d28a3 Test path escaping - mocha windows fix (#1627) 2018-04-01 08:28:30 +02:00
Marcin Mielnicki
0d5b48bc64 "commits to be deployed" replaced "last deployed" (#1605) 2018-03-30 12:42:10 +02:00
Pyves
66c5d914c7 [CircleCI] Extended existing try-catch block (#1614) 2018-03-30 09:34:20 +01:00
Paul Melnikow
ac7c418222 Extract examples from new-style services (#1582)
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
2018-03-30 03:07:44 -05:00
Pyves
1dff491a24 Added number support to version text formatter (#1620) 2018-03-29 10:08:23 -07:00
Pyves
16eea6d7db Number support for version color formatter (#1615) 2018-03-29 18:04:42 +01:00
Philip I. Thomas
01646ded72 upgrade glob to be a prod dependency (#1619) 2018-03-28 08:40:25 -07:00
greenkeeper[bot]
7e239f78c0 chore(package): update semver-regex to version 2.0.0 (#1596) 2018-03-27 17:13:15 -07:00
Pyves
ed419b0a77 [microbadger] Fix tests (#1600) 2018-03-27 11:15:51 +01:00
Thaddée Tyl
17ddd180bb Skip Twitter suggestion if URL does not have protocol (#1604)
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);
```
2018-03-26 15:33:59 -07:00
Thaddée Tyl
0a248998f2 Only compute user/repo if suggesting badges for GitHub (#1601)
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('/');
```
2018-03-25 14:47:54 -07:00
ayatk
400ae013a7 Add circleci logo (#1595) 2018-03-25 22:31:04 +02:00
Marcin Mielnicki
fe4ac0bf1c Log errors to Sentry (#1422) 2018-03-24 20:30:51 +01:00
Paul Melnikow
ea4b758612 Move service tests alongside code (#1563)
Per discussion in #1543
2018-03-20 18:32:48 -07:00
Paul Melnikow
71ef474afc Add tests for BaseService + fix hex colors (#1581) 2018-03-20 15:04:55 -07:00
Paul Melnikow
e37668b392 We have no more pull requests to adopt (#1587)
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.
2018-03-19 20:27:47 -04:00
Paul Melnikow
0654abe2b2 Fix colors for new appveyor badge (#1583) 2018-03-19 20:16:47 -04:00
Darren Labithiotis
a497ccabf7 [dynamic-xml dynamic-json] Set request options for dynamic json badges. (#1575)
* 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
2018-03-19 19:23:13 -04:00
Paul Melnikow
5582485dc5 Try to fix greenkeeper-lockfile not updating (#1562) 2018-03-18 21:30:07 -04:00
Paul Melnikow
7d90391b05 Housekeeping after upgrade to Node 8 (#1564) 2018-03-18 13:34:15 -04:00
Ville Skyttä
0710c3b8f4 Spelling fixes (#1580) 2018-03-18 16:30:32 +00:00
Paul Melnikow
3a47bb38ac Searches with regex control characters should not crash (#1579)
Fix #1578
2018-03-17 16:52:41 -04:00
Paul Melnikow
6c2ce413b1 Adopt async-await for most promise-based code (#1565)
* Address todo for Node 8 upgrade
2018-03-15 09:36:40 -04:00
greenkeeper[bot]
2adb0e7d52 Update request to the latest version 🚀 (#1566)
* fix(package): update request to version 2.84.0

* fix(package): update request to version 2.85.0

Closes #1566

* update package-lock
2018-03-14 22:57:24 -04:00
greenkeeper[bot]
3a5563d27f Update query-string to the latest version 🚀 (#1572)
* fix(package): update query-string to version 6.0.0

* update package-lock
2018-03-14 22:57:05 -04:00
Paul Melnikow
6750115b79 Add [npm] type definitions badge (#1541)
Let a package show off its type definitions based on devDependency data in the published npm package.

Close #1252
2018-03-11 18:00:41 -07:00
Paul Melnikow
2d651533aa New API for registering services: #963 #1423 #1425 #1450 #1451 #1544 #1543
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)
2018-03-11 17:53:01 -07:00
Eli Perelman
7545dcfe42 Add [Bugzilla] bugstatus badge (#1492) 2018-03-11 21:50:14 +01:00
chris48s
f8d511fae2 Add some more rules to dangerfile (#1560)
* warn if the target branch is not master
* link to the logo guidance if PR modifies a SVG file in /logo/
2018-03-11 20:05:49 +00:00
Paul Melnikow
ae848f38f4 Add snapshot tests for SVG and JSON (#1557)
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.
2018-03-11 09:07:03 -07:00
chris48s
d5fc786ad3 service tests for [dub] (#1559)
- add tests
- improve error handling
- switch to https
2018-03-09 21:37:33 +00:00
Pyves
276f821317 Update contributing guidelines (#1551)
* Added logo acceptance criteria

* Added repository starring section

* Added logo approval expectation sentence

* Extended to spreading the word section

* Rearranged sections
2018-03-09 19:10:03 +00:00
Florian Munz
54afdc189c Add Depfu dependencies badge (#1537) 2018-03-08 11:42:25 -08:00
Paul Melnikow
8fde79b793 Make tests more resilient to time zone (#1558)
These tests were failing locally and I suspect it’s because I’m in a different time zone.
2018-03-08 11:09:26 -08:00
greenkeeper[bot]
dd90d2aced Update sinon-chai to the latest version 🚀 (#1547)
* chore(package): update sinon-chai to version 3.0.0

* Update package-lock
2018-03-08 09:24:38 -08:00
greenkeeper[bot]
2d5a088d6f Update next to the latest version 🚀 (#1490)
* chore(package): update next to version 5.0.0

* Update package-lock

* Get build + tests passing
2018-03-08 09:18:52 -08:00
Danial
a89b6bb163 remove whitespace from data URIs (#1546)
* 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
2018-03-08 03:09:29 +01:00
chris48s
1fab9d70de [gratipay gemnasium snap-ci cauditor] add deprecation helpers, deprecate gemnasium (#1524) 2018-03-07 09:08:51 +00:00
chris48s
06fe43c51f [chocolatey powershellgallery myget nuget] tests for NuGet v3 services (#1542) 2018-03-07 09:08:14 +00:00
Danial
be09cee1f2 User defined XML source badge [dynamic-xml dynamic-json] (#1494)
* 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
2018-03-06 22:43:02 +01:00
Danial
f4d5c41009 [Cauditor] Replace with error message (#1502)
* Depreciate Cauditor

* explicitly set color to lightgray, update test

* add message for date of badge depreciation
2018-03-05 05:55:52 +01:00
Marcin Mielnicki
0640356f2c Travis service tests from tutorial (#1531)
Service tests for Travis CI from tutorial
2018-03-04 21:03:01 +00:00
Pyves
9b564424ba [Snap-CI] Replace with error message (#1468)
* Depreciated Snap CI

* Updated badge color to light gray
2018-03-04 09:32:02 +00:00
greenkeeper[bot]
22ff288eac Update eslint, eslint-config-standard, and friends to the latest versions 🚀 (#1512) 2018-03-03 20:45:12 -05:00
greenkeeper[bot]
ab5514651f Update eslint-plugin-node to the latest version 🚀 (#1489) 2018-03-03 20:36:46 -05:00
greenkeeper[bot]
4a3f1eda9a Update fetch-ponyfill to the latest version 🚀 (#1488) 2018-03-03 20:25:18 -05:00
Danial
49574df0d1 [README.md] add logos (#1507) 2018-03-03 20:14:04 -05:00
greenkeeper[bot]
af04068ffa chore(package): update node-fetch to version 2.0.0 (#1486) 2018-03-03 19:55:13 -05:00
greenkeeper[bot]
4e5669d2eb Update prettier to the latest version 🚀 (#1528) 2018-03-03 19:44:03 -05:00
Paul Melnikow
3b08d9cb35 [Gratipay] Replace with error message (#1449)
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)
```
2018-03-03 19:42:54 -05:00
Pyves
abc6e3f181 [microbadger] Handle no DownloadSize (#1536) 2018-03-02 21:48:12 +00:00
Danial
5ded37b5ff logo data uri encoding (#1527)
* logo datauri encode

no longer need to replace `+` with `%2B`

* add comment & tests for spaces
2018-02-27 21:57:06 +01:00
Marcin Mielnicki
ff24bf3ff8 [travis] Updated an expected value in a service test of Travis PHP version badge (#1526)
* Updated an expected value in a service test of Travis PHP version badge

* Use the isPhpVersionReduction in a service tests of Travis PHP version
2018-02-27 04:11:50 +01:00
Marcin Mielnicki
6b76a6ef24 Use 'default' as default JSON style (#1429)
* Use 'default' as a default JSON style

* Using expect instead of assert

* Assert badge is valid svg in test

* Assert badge is valid json in test
2018-02-26 00:41:30 +01:00
Fuzz Stati0n
3f933594a0 Uncaught TypeError crashes server on numeric or boolean 'link' parameter (#1520) 2018-02-25 22:46:35 +01:00
Thaddee Tyl
0ae322b524 Commit index.html and _next on gh-page deployment
Fixes #1458.
2018-02-25 01:14:26 +01:00
Thaddee Tyl
36a22549e5 Add build folder for gh-pages deployment
Fixes #1458.
2018-02-25 01:14:26 +01:00
Brad Kent
ae6dd7101c [hhvm] #1499 - update hhvm service (#1508)
* 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
2018-02-19 22:53:32 +01:00
Patrick Streule
57c7279540 [Bitbucket] #1509 - Add Bitbucket Pipelines service (#1510)
* [Bitbucket] #1509 - Add Bitbucket Pipelines service

* Use ES6 const and error helper
2018-02-19 21:33:09 +01:00
chris48s
75503ec514 [hackage] switch to the /licenses endpoint (#1506)
* switch to /licenses endpoint to check if package exists

refs #1498

* trim whitespace from version string
2018-02-17 06:00:13 +01:00
Danial
3cb71037fd checkErrorResponse update default (#1501) 2018-02-15 23:34:38 +01:00
chris48s
581546d58e [chocolatey powershellgallery] add service tests for NuGet v2 services (#1487)
* 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
2018-02-13 22:09:04 +01:00
Binh Bui
143ec95bf0 Update [Vaadin-Directory] previewUri in all-badge-examples.js (#1496)
* Changed previewUri in all-badge
2018-02-13 03:18:10 +01:00
Binh Bui
e773a9f47d Added [Vaadin-Directory] badge service (#1474)
* 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
2018-02-13 00:52:46 +01:00
Marcin Mielnicki
17b4a70411 [npm bountysource cdnjs circleci clojars docker gem homebrew itunes microbadger nexus requires shippable suggest uptimerobot] Service tests for NPM total downloads + invalidJSON helper (#1471)
* 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
2018-02-12 21:36:23 +01:00
Tomek Łaziuk
8ad176d014 [bundlephobia] add badge for the npm package size (#1481)
* 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
2018-02-03 08:31:10 -08:00
chris48s
cbb263b102 service tests for [cocoapods] (#1472)
* 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
2018-02-03 08:11:28 -08:00
chris48s
e4199bc806 service tests for [david] (#1465)
* service tests for [david]

* update 500 handling
2018-02-02 15:11:50 -08:00
greenkeeper[bot]
ef038b8049 Update mocha to the latest version 🚀 (#1459)
* chore(package): update mocha to version 5.0.0

* Update package-lock
2018-02-02 14:58:14 -08:00
greenkeeper[bot]
4ffdd85177 Update semver to the latest version 🚀 (#1457)
* fix(package): update semver to version 5.5.0

* Update package-lock
2018-02-02 14:54:26 -08:00
greenkeeper[bot]
1314258913 Update is-svg to the latest version 🚀 (#1483)
* chore(package): update is-svg to version 3.0.0

* Update package-lock
2018-02-02 14:44:29 -08:00
Paul Melnikow
e6de92c6ba Upgrade to next.js patched for CVE-2018-6184 (#1485)
This clears the GitHub warning for the vulnerability that shows up for maintainers. Note the vulnerability does not affect our deployment, which is static, using `next export`.

https://github.com/zeit/next.js/releases/tag/4.2.3
https://nvd.nist.gov/vuln/detail/CVE-2018-6184
2018-02-02 14:40:59 -08:00
Danial
cec40ad46c update tests (#1482) 2018-02-02 10:10:40 +13:00
Pyves
435903ae4a [CodeClimate] Fix remaining badges (#1387)
* 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
2018-02-01 09:33:29 +13:00
chris48s
b7228ae89e update codacy urls (#1477) 2018-02-01 09:24:42 +13:00
George Hopkins
0fd69332bd Add Windows logo (#1467) 2018-01-24 09:54:51 +13:00
chris48s
ec38c2e4da [shippable] add tests for shippable service (#1362)
* 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
2018-01-22 19:28:59 -08:00
chris48s
3c551a6156 clarify default for Uptime Robot ratio (#1463)
Fix #1462
2018-01-21 18:01:31 -05:00
Danial
9aafe86247 Show logos by default on social badges (regression fix) (#1456)
* 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
2018-01-21 23:57:58 +01:00
chris48s
e3ac9c3db5 service tests for [itunes] (#1464) 2018-01-21 17:50:04 -05:00
Paul Melnikow
1d8926672c Fix PR metadata auth [cran] (#1454)
Match work done in #1453 to our CI setup.
2018-01-16 13:15:15 -05:00
chris48s
7c6723a79d service tests for [docker] (#1428) 2018-01-15 22:03:52 -05:00
Paul Melnikow
eacfc1497a For service tests, get PR metadata from Github API (#1453)
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.
2018-01-15 21:53:15 -05:00
Danial
65e1d69f53 [badge/dynamic/json] fix colorscheme on error (#1445)
* [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()
2018-01-16 13:53:30 +13:00
chris48s
e1f0e2598d tests for ruby [gem] service (#1444)
* 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
2018-01-15 15:20:48 -05:00
Vladimir Starkov
a681fdaa87 Fix docker run (#1439)
* 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
2018-01-15 15:19:28 -05:00
Paul Melnikow
6b26affb5f Uptime Robot: Use regex that accepts decimals (#1448)
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)
```
2018-01-15 15:15:23 -05:00
Paul Melnikow
e358ebe6b3 Refactor LRU cache test asserts (#1418) 2018-01-15 14:15:27 -05:00
greenkeeper[bot]
b422e880c1 Update prettier to the latest version 🚀 (#1434) 2018-01-15 14:14:08 -05:00
Paul Melnikow
606946f24a Log + fail tests on unhandled promise rejections (#1424) 2018-01-14 16:57:40 -05:00
chris48s
be3bc45d66 service tests for [homebrew] (#1443)
* add tests and 'not found' handling for homebrew service

* add test with mocked response
2018-01-14 16:51:24 -05:00
Thaddee Tyl
09a2ca144d Tweak IP and badge type rate limits 2018-01-13 18:34:48 +01:00
Thaddee Tyl
61fa22b7e4 Showcase logos in social badges on the front page 2018-01-13 15:33:41 +01:00
Vladimir Starkov
db39093fa7 fix: add missing git to apk installation script. close #1435 (#1436) 2018-01-11 16:55:33 -05:00
Paul Melnikow
864b194e5c Add Joi to greenkeeper ignore (#1430) 2018-01-09 11:50:43 -05:00
Thaddee Tyl
ac8935cecb Add rate limiting
We now rate limit IPs, referers and badge type.
2018-01-09 02:35:51 +01:00
Thaddee Tyl
0da212b7de Upgrade to camp 17.2.1 2018-01-09 01:25:10 +01:00
Paul Melnikow
7c1a3fef69 Adopt Chai for assertions (#1419) 2018-01-08 14:18:07 -07:00
chris48s
2de53ce7bd add tests for [hackage] (#1416)
* add tests for hackage, handle 'not found'

* add 'not found' case for hackage-deps

* use es6 declarations

* change badge label to 'dependencies'
2018-01-06 22:02:34 -07:00
Michael
a55ab15de2 fix inline image path (#1427) 2018-01-06 08:44:11 -07:00
greenkeeper[bot]
2013968990 Update danger to the latest version 🚀 (#1414) 2018-01-05 22:09:25 -07:00
chris48s
e614d19355 service tests for [uptimerobot] (#1426)
* use the same error handling on /status and /ratio endpoints

* add service tests for uptime robot
2018-01-05 20:51:05 -07:00
Daniel Lo Nigro
02683afd04 Don't crash when logo passed as integer (#1319) 2018-01-04 17:11:59 -07:00
chris48s
e91c9fc7ab Add tests for Circle-CI (#1421) 2018-01-05 12:16:25 +13:00
Paul Melnikow
ccb3eb8fdf Fix January unit test (#1417) 2018-01-03 20:37:35 -07:00
chris48s
9cb9d5984d [requires] add tests for requires.io service, review error handling (#1361) 2018-01-02 20:13:10 -07:00
Danial
503618443e Add Discord logo (#1413) 2018-01-03 10:09:01 +13:00
Sebastian Staudt
e62c085922 Update URL for Homebrew formula versions (#1408)
braumeister.org is now part of Homebrew and available at formulae.brew.sh.
2018-01-01 17:40:05 -05:00
chris48s
e2ee997f07 service tests for [clojars] (#1410) 2018-01-01 17:15:55 -05:00
chris48s
21b1ad73e7 Service tests for [cdnjs] (#1409) 2018-01-01 17:14:16 -05:00
chris48s
438e47adfb Add tests for codeship service (#1411) 2018-01-01 17:10:02 -05:00
Paul Melnikow
60959bf7e7 Use github auth in php-v badges (#1403)
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
2017-12-28 21:30:30 -05:00
Paul Melnikow
84c60c8730 Optimization + cleanup in makeBadge (#1405)
- Avoid mutating the inputs
- Declare all the input and output keys
- Avoid recomputing escapeXml on the same values
- Capitalize social badge labels before measuring
2017-12-28 21:28:47 -05:00
Danial
3281005c26 Add [twitter] tests (#1394)
* 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
2017-12-29 09:54:08 +13:00
Paul Melnikow
09cf211786 Fix tests for [suggest] endpoint (#1398) 2017-12-28 14:21:16 -05:00
Peter Gribanov
f719705518 Get tested PHP version from PHP-Eye (#1372) 2017-12-28 13:44:50 -05:00
Paul Melnikow
cc9a6db853 Speed up font-width computation in most cases (#1390)
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.
2017-12-26 23:57:46 -05:00
Paul Melnikow
105e383d93 Improve search performance (#1393)
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
2017-12-26 23:53:15 -05:00
Paul Melnikow
0a2a80415c Increase the timeout on a test that often runs out of time (#1392)
e.g. #1391
2017-12-26 16:24:14 -05:00
Paul Melnikow
46a05e42b8 Add list of critical services (#1386)
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.
2017-12-25 22:21:37 -05:00
Pravdomil
e4fed8d178 Copyedit and add link in footer (#1366) 2017-12-21 18:34:48 -05:00
Danial
b48091a198 [FIX] Bower service tests (#1383) 2017-12-22 12:02:04 +13:00
Paul Melnikow
78bb20dc6a Danger: badge examples are not lib/ + wordsmith (#1381) 2017-12-20 21:11:59 -05:00
Zhmayev Yaroslav
2f9307ae2c Add Scrutinizer CI logo (#1380) 2017-12-21 11:24:11 +13:00
Marcin Mielnicki
cc84240b61 Prettier updated to 1.9.2 in package-lock (#1375) 2017-12-19 13:26:44 -05:00
Pyves
9c2645b41e Fixed Code Climate coverage and maintainability score badges (#1368) 2017-12-18 18:20:29 +13:00
Pyves
32671dfd87 Removal of hasPrefix function in badge-data.js (#1376)
* Removed hasPrefix method and added tests to cover prependPrefix
2017-12-18 17:58:28 +13:00
Daniel Cazzulino
432024db30 Added TFS/VSO logo (#1369)
Extracted from the TFS built-in badges that are already SVG.
2017-12-13 11:08:35 +01:00
greenkeeper[bot]
31fb96e4ac chore(package): update prettier to version 1.9.2 (#1367) 2017-12-11 22:47:38 -05:00
Thaddée Tyl
ea405e04e6 Default to not logging GitHub token debugging (#1364)
As argued for in
https://github.com/badges/shields/issues/1314#issuecomment-350564524.

It populates large quantities of text in the logs, where I wish to only
see errors.
2017-12-10 13:02:03 -05:00
Paul Melnikow
b35cb71ed6 Upgrade IcedFrisby (#1360)
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.
2017-12-09 12:03:57 -05:00
Paul Melnikow
ec3971b984 Update contributing guidelines (#1357) 2017-12-09 12:02:45 -05:00
chris48s
20c29db7a6 [bountysource] tests and fixes for bountysource service integration (#1354)
* Add service tests for bountysource badge
* switch to use ES6 style variable declarations
* Fail cleanly on bad responses.
2017-12-08 14:34:33 -05:00
Paul Melnikow
d97f07c263 Install Danger (#1352)
… 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)
2017-12-08 10:38:41 -05:00
Krutov Alexander
b1ca6391d0 Add MicroBadger (#1340) 2017-12-07 17:30:42 -05:00
Danial
a087b28d06 [vscode-marketplace] Update to be more consistent with other badges (#1284)
* fix vs market colors

* fix tests & update formatting

Fix tests
Update tests file formatting to be consistant with other tests

* update tests labels

* switch case formatting

* add stars rating

* add tests for stars
2017-12-08 11:07:40 +13:00
Paul Melnikow
847d178f9e Remove Travis leftovers after move to Circle (#1353) 2017-12-07 13:10:10 -05:00
Danial
e243959420 add spacing between badges in footer (#1347) 2017-12-07 10:28:34 +13:00
Paul Melnikow
81560cb0c6 Set up CircleCI (including [github] tests) (#1338)
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.
2017-12-06 15:45:09 -05:00
Paul Melnikow
212903d0e1 Fix dynamic badge URL generator (#1344)
Fix #1339
2017-12-06 14:38:41 -05:00
chris48s
350a9819cd check status code before parsing body (#1343) 2017-12-06 14:03:32 -05:00
Paul Melnikow
5527d9d642 Fix validateDOMNesting warning (#1342)
Using fix from mapbox/react-click-to-select#15.

From #1273
2017-12-06 13:04:03 -05:00
tooomm
b33b8d5b53 uri --> url (#1341) 2017-12-06 11:05:18 -05:00
Peter Gribanov
962cf61b82 PHP version from .travis.yml (#1258)
Reference: #819
2017-12-06 11:04:24 -05:00
Danial
18f6d44e8d remove extra whitespace in social style badge (#1337) 2017-12-06 17:05:55 +13:00
mattbk
2028251ca0 Add [Liberapay] (#1251) 2017-12-05 23:01:02 -05:00
greenkeeper[bot]
8bdd5b90d2 chore(package): update prettier to version 1.9.1 (#1335) 2017-12-05 19:22:18 -05:00
Paul Melnikow
7c1b1fc621 Fix style picker in markup modal (#1331)
- Restore correct list of styles to markup modal
- DRY lists of styles

Fix #1330
2017-12-05 18:08:13 -05:00
Krutov Alexander
81b38e6069 Update TUTORIAL.md (#1333)
Fix a couple of misspellings
2017-12-05 17:43:11 -05:00
Eric Berry
3581efe5e1 Add [Discourse] status/stats shield (#1326)
Close #1325
2017-12-05 17:34:59 -05:00
Marcin Mielnicki
0570a9e920 License badge colour corresponding to license type (#1190) 2017-12-05 16:43:29 -05:00
chris48s
433d69b684 Fixes and tests for BitBucket + GitHub (#1315)
* 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`
2017-12-05 15:39:08 -05:00
greenkeeper[bot]
58437ec72e Update dependencies to enable Greenkeeper 🌴 (#1328) 2017-12-05 11:49:12 -05:00
Paul Melnikow
8014aa351a Upgrade jsonpath (#1327) 2017-12-05 11:23:58 -05:00
tooomm
f700502c4f webpage: add missing titles + more badge previews (#1305) 2017-12-05 11:17:46 -05:00
Paul Melnikow
342e71ee65 Update docs re production builds (#1316) 2017-12-04 19:08:48 -05:00
Paul Melnikow
9882a44e56 Configure for deployment with zeit now (#1308)
I'm experimenting with Zeit Now as another hosting option. These changes enable a working deployment.
2017-12-04 18:25:16 -05:00
Paul Melnikow
1eedd458b8 Fix and refactor front-end URL generation (#1322)
- 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)
2017-12-04 10:08:54 -05:00
chris48s
8f7f16d7f1 improve test suite for packagist service integration 2017-12-03 21:02:24 -05:00
Danial
ad00f5cde5 Fix depcheck's in Windows (#1320)
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"
```
2017-12-03 19:46:52 -05:00
Paul Melnikow
33690c5555 Fix missing whitespace in usage + footer
Use Fragment support added in React 16.2:

https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html
2017-12-03 15:12:22 -05:00
Paul Melnikow
1d313bdd19 Github admin endpoint: use basic auth password instead of username (#1317) 2017-12-03 15:07:58 -05:00
Thaddee Tyl
7e668c74b6 Add monitoring platform 2017-12-03 19:06:02 +01:00
Thaddee Tyl
9cb9113a34 Add endpoint to obtain logs
It goes through a WebSocket; the secret is sent, and if valid, the logs
are sent back.
2017-12-03 18:48:31 +01:00
Thaddee Tyl
e61373e739 Add system endpoint to fetch network information
This is part of an effort to set up an admin monitoring platform.
2017-12-03 18:48:31 +01:00
Paul Melnikow
8d0b1347d7 Fix markup modal when baseUri is unset (#1307) 2017-12-01 16:51:15 -05:00
Paul Melnikow
2be271c22b Frontend: Allow BASE_URL to be unset (#1306)
- Do not use bogus `'undefined'` as base URI
2017-12-01 16:34:31 -05:00
chris48s
56b82e1665 [pypi] Add badge for django version support (#1286)
Closes #1018
2017-12-01 16:10:34 -05:00
Paul Melnikow
aecec144fd Use a better OpenCollective link 2017-12-01 10:09:41 -05:00
Paul Melnikow
6f632224c1 Fix some example and preview URLs 2017-12-01 09:42:19 -05:00
Paul Melnikow
ce2ca922b2 Readme: Fix logo link
For #1301
2017-12-01 09:28:21 -05:00
tooomm
cda9dd35a1 readme: fix link (#1300)
- fixed link to github contributors from Open Collective template
- adjusted brackets around [contribute] to match style for backers and sponsors
2017-12-01 09:10:37 -05:00
Pyves
bf13792633 Optimisation of makeBadge key width computation (#1298)
* Added cache to text width for badge keys.
2017-11-30 22:25:08 -05:00
Paul Melnikow
af0799a312 Use template strings in make-badge (#1296)
c.f. https://github.com/badges/shields/pull/1167#discussion_r145313407
2017-11-30 17:16:08 -05:00
Paul Melnikow
8fa751d0c5 Activating Open Collective (#1295)
See comments in #1250. Gratipay is shutting down.
2017-11-30 14:19:50 -05:00
Paul Melnikow
127b46aef8 Github auth admin endpoint and logging (#1267)
- 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)
2017-11-30 13:21:27 -05:00
Paul Melnikow
f403c2b5d3 Configure frontend tests (#1293)
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.
2017-11-29 18:19:05 -05:00
Paul Melnikow
c5e31b5de1 Fix frontend deploy and Heroku staging (#1288)
- 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.
2017-11-29 17:59:01 -05:00
Paul Melnikow
f3965ae9a5 Upgrade moment (#1294)
Fix moment/moment#4163.
2017-11-29 15:47:17 -05:00
chris48s
a579d2eaec Add test suite for PyPi service (#1289) 2017-11-29 15:22:12 -05:00
Paul Melnikow
9d1efae47f Upgrade check-node-version and print error in Node 9 (#1291)
Refs:

- https://github.com/parshap/check-node-version/issues/18
- https://github.com/badges/shields/issues/1290
- https://github.com/espadrine/sc/issues/65
2017-11-29 13:11:25 -05:00
Paul Melnikow
4b5bf03fea Rewrite frontend in React (#1273)
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
2017-11-28 11:34:17 -05:00
Paul Melnikow
a0cd93080e Upgrade sazerac
Fix https://github.com/mikec/sazerac/pull/12
2017-11-27 17:47:54 -05:00
Paul Melnikow
f0e6181ec4 CONTRIBUTING: Add code review to ways to help (#1269) 2017-11-25 21:05:54 -05:00
Paul Melnikow
1af1f497bb Allow configuring allowed CORS origins for suggest (#1282)
- 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.
2017-11-25 18:27:02 -05:00
Danial
a4bce73da6 For-the-badge | Convert labels to string then uppercase (#1281) 2017-11-22 23:35:33 -05:00
Vladimir Starkov
e588bef199 Support custom npm registry URLs (#1277) 2017-11-20 19:22:42 -05:00
Danial
ea061e55c6 Add Travis-CI logo (#1276) 2017-11-20 10:05:07 +13:00
Paul Melnikow
bca6d15728 Upgrade camp
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!
2017-11-17 18:26:19 -06:00
Paul Melnikow
d91b904b82 Redirect the root only when configured (#1270)
- Fix `’INFOSITE' is not recognized` in `npm start` on Windows

Close #1259
2017-11-17 13:42:38 -06:00
Hiram Levitch
1a36054b46 Add Bitcoin + PayPal Logo (#1217)
* Add Minimized Bitcoin Logo And Minimized Blue PayPal Logo

* Center The PayPal Logo

xMinYMin → xMidYMid
2017-11-15 10:01:34 +13:00
PyvesB
b61a3968ef Cleaned up Elm Package version text and colour 2017-11-12 12:14:42 -05:00
Pyves
7039e68018 Consistent version formatting (#1246)
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).
2017-11-11 17:54:38 -05:00
Danial
8c2de04d99 [sonar] support new SonarQube api (#1239)
* update sonarqube

* parse value as int

* Add tests

* Update example & Add depreciated API example

* eslint

* tidyup & depreciated -> legacy
2017-11-12 09:26:15 +13:00
rnons
178376ddf0 add [elm-package] badge 2017-11-11 14:17:30 -05:00
Thaddee Tyl
59c0662874 Fix bug saving GitHub tokens from other servers
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.
2017-11-11 10:27:24 +01:00
Pyves
28947dc89e Add Eclipse logo (#1257)
* Added Eclipse logo

* Optimised Eclipse logo further
2017-11-11 09:15:28 +13:00
Paul Melnikow
8733a8b8f2 Use GitHub token rotation in production :P (#1266) 2017-11-10 13:51:39 -05:00
tooomm
9e864f1660 fix "flat-square" style badge example 2017-11-10 13:10:37 -05:00
Peter Gribanov
0d3d33bf1b Get PHP version from [Packagist] (#1256) 2017-11-10 12:46:52 -05:00
George
4ec806e6e5 Spec: Fix "Open Sans" space typo 2017-11-09 23:37:54 -05:00
Danial
ab9be32f35 Update Homepage - Styles & Badge Size (#1242)
* Add social & for-the-badge to dropdown list

* badge minimum height 20px
2017-11-09 11:51:14 +13:00
Tyler Nickerson
632c70b6b5 Added support for new Code Climate scores (#1236) 2017-11-06 18:53:40 -05:00
Tatsuya Saito
6788a31ed5 Adds new badge for [Redmine] plugin rating (#1247) 2017-11-06 10:59:26 -05:00
Paul Melnikow
4d22799962 Fix Github base url again
Fix #1243.
2017-11-02 10:35:22 -04:00
Paul Melnikow
7ca2e97155 Use sazerac for our data-driven tests (#1228)
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.
2017-11-01 20:15:19 -04:00
Paul Melnikow
a2f5cbb03a Push frontend to production servers at /index.html (#1222)
* 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
2017-11-01 20:48:01 +01:00
Danial
ebcfb105a0 [badge/dynamic/json] User defined JSON source badge (#820)
* 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
2017-11-01 17:02:37 +13:00
Pyves
12dcdc14da Consistent overriding of labels set by the user (#1218)
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.
2017-10-31 23:16:02 -04:00
Paul Melnikow
7eb9bb5209 Promisify svg2img 2017-10-31 23:13:23 -04:00
Paul Melnikow
550012a09c Fix a couple badge examples 2017-10-31 23:12:50 -04:00
Paul Melnikow
c22e8965f8 Revert "github issue/pr support labels with spaces (#1240)"
This reverts commit 0d1e4c0923.
2017-10-31 23:12:07 -04:00
Danial
0d1e4c0923 github issue/pr support labels with spaces (#1240) 2017-11-01 12:08:40 +13:00
freezy
ad4a8b4406 [bitrise] Added new build service Bitrise.io (#1227)
Close #574.
2017-10-31 13:23:33 -04:00
Paul Melnikow
37fbef5504 Clean up the outer scope of server.js (#1235) 2017-10-31 13:21:43 -04:00
Paul Melnikow
b458faee1a Change makeBadge() to a synchronous function 2017-10-31 00:10:45 -04:00
Paul Melnikow
a54338afa8 Rename badge() -> makeBadge() (#1232) 2017-10-30 22:08:33 -04:00
Paul Melnikow
91eaa2958c Move gh-badges CLI into lib/ 2017-10-30 21:46:50 -04:00
Paul Melnikow
905a148d66 Add documentation for gh_token when self-hosting (#1230)
Close #747.
2017-10-30 19:36:54 -04:00
RealCerealKiller
8ae30f9d47 Add Telegram Logo 2017-10-30 19:04:19 -04:00
Paul Melnikow
b16122d9a4 When a global gh_token is configured, always use it (#1118)
If I configure a global gh_token, I expect it to be used all the time. I expect to see predictable failures when that token is exhausted.
2017-10-29 22:36:39 -04:00
Paul Melnikow
090454a828 Cache keys should not be the same (#1223)
Fix the cache bug introduced in #1186 that blocked today's deploy.
2017-10-29 22:11:10 -04:00
Paul Melnikow
9d84d2fec1 Fix Sourcegraph preview URI 2017-10-29 21:29:22 -04:00
Paul Melnikow
05402ef45c Fix Herkou staging deploy
- Dangerous semver range (>) in engines.node
https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version
2017-10-28 16:13:47 -04:00
Paul Melnikow
3c37dbd3dc [maven-metadata] Add support for maven-metadata.xml (#1214)
Based on ArsenArsen's work in #953.
2017-10-28 15:12:44 -04:00
Paul Melnikow
9f918dbee1 Use destructuring 2017-10-28 14:32:11 -04:00
Paul Melnikow
bde4d925f2 Retire try.html and create new dev + prod builds (#1194)
- 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
2017-10-28 14:02:45 -04:00
freezy
cf14ab1464 Added Funding category 2017-10-28 11:07:35 -04:00
Kieran Hunt
d9860991ed Fix style issue with iTunes App Store on homepage (#1211)
References:
- https://en.wikipedia.org/wiki/ITunes
- https://www.apple.com/itunes/
2017-10-28 08:03:55 +13:00
Marcin Mielnicki
f89b317542 Latest tag with any prefix + tests (#1188) 2017-10-26 16:31:13 -04:00
Pyves
ffb6fdb884 [eclipse-marketplace] New last updated Eclipse badge (#1204)
Implement a fifth Eclipse Marketplace badge, which displays the "date" when the plugin was last updated on the marketplace.
2017-10-25 22:23:22 -04:00
Paul Melnikow
446d4ce21e Correct cache behavior for custom query parameters (#1186)
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).
2017-10-24 23:00:23 -04:00
Paul Melnikow
7153490ef9 Use the npm lock file (#1182) 2017-10-24 22:41:34 -04:00
古永忠 (Yung-Chung Ku)
c5cde67991 Create postgresql.svg
The svg file is taken and optimized from https://wiki.postgresql.org/wiki/Logo
2017-10-24 20:22:00 -04:00
Paul Melnikow
366c939cdc Fix downloads and commit activity badges showing zero (#1201)
- `isMetric` tests must be > 0 to pass.
- Fix downloads badge bug introduced in #1140. (So much for [being clever](https://github.com/badges/shields/pull/1140#discussion_r143544396)!)
- Fix 1 week activity badge by returning the previous week instead of the current week.
2017-10-22 10:42:10 -04:00
Paul Melnikow
a3b5dcbee8 Fix more badge links in the production build 2017-10-22 09:42:49 -04:00
Paul Melnikow
ef86288eab Fix production build for quoting style of generated frontend
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.
2017-10-22 09:39:09 -04:00
Tesla Ice Zhang
f7cecf7eda Add JetBrains plugin version to the front page (#1197) 2017-10-21 12:06:41 -04:00
Paul Melnikow
6aae294b28 Avoid errors when offline 2017-10-21 11:29:30 -04:00
Paul Melnikow
6c9a91a6b0 Fix Bower service test (#1187)
- Fix failing test
- Tidy up test titles (no need to repeat what is in the assertion)
2017-10-21 01:46:04 -04:00
Pyves
5a1e994296 Better test coverage of text formatters + fix thousand case (#1185) 2017-10-20 21:25:04 -04:00
Paul Melnikow
b411f08ad1 Generate badge examples from data + code (#1163)
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.
2017-10-20 17:33:12 -04:00
piekar294
8ac0605e12 [Coveralls] Bitbucket support + service tests (#1189)
Close #793
2017-10-20 12:45:48 -04:00
Paul Melnikow
f52385f16d Test on Node 8 2017-10-19 12:17:19 -04:00
Paul Melnikow
748f80b438 Add new maintainer and update history
Based on info in https://github.com/badges/shields/pull/1129#discussion_r144972746
2017-10-18 15:10:21 -04:00
Mikko Piuhola
396fd494b1 Support for Jenkins plugin version (#1158)
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
2017-10-18 13:00:50 -04:00
Paul Melnikow
dc44ba7725 Clean up request-handler, github-auth, and analytics; upgrade to Mocha 4 (#1142)
- 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
2017-10-17 22:01:46 -04:00
Marcin Mielnicki
f371c8fb07 On [Github] issues badge, add quotes around multi-word labels (#1178)
- Fix an alt name in readme
2017-10-17 18:11:27 -04:00
Paul Melnikow
6edb198334 Optimize standard npm start script for dev usage (#1157)
- `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.
2017-10-16 23:41:27 -04:00
RedSparr0w
a83d43a485 Add link support for all badges
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
2017-10-16 23:30:31 -04:00
Pyves
7fa38c3335 More precise star display with test (#1179) 2017-10-16 16:30:40 -04:00
Paul Melnikow
4020929482 Upgrade dot (#1168)
Reviewing the commits, it doens’t appear anything of significance has changed.
2017-10-16 20:15:05 +02:00
Pyves
81b9f6ac53 [dotnetstatus github gratipay hexpm wordpress] General test improvements (#1177)
* 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
2017-10-15 16:58:54 -04:00
Danial
c026ebf235 for the badge style badges (#1166)
https://forthebadge.com/ style of badges, with link support

Close #818
2017-10-15 16:52:28 -04:00
Danial
3465e7a17b Use shields.io for the fork badge & use objects for social badges (#1173)
- 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
2017-10-15 09:25:34 -04:00
Pyves
66dbc04bdb [eclipse-marketplace] Eclipse marketplace integration (#1175)
Close #1165
2017-10-14 18:44:09 -04:00
Paul Melnikow
8e47ae93d4 Refactor and test the SVG badge parser (#1147)
- Add one todo
2017-10-14 15:41:56 -04:00
Paul Melnikow
5fbdc5e773 Docs: Cosmetic, link fixes, and copyedits (#1176) 2017-10-14 15:01:45 -04:00
Paul Melnikow
16045fdff8 Update documentation (#1129)
I wrote a new readme and contributing guidelines, and took a rough pass through the rest of the documentation.
2017-10-14 11:43:52 -04:00
Pyves
b0f2eed0cb [GitHub] Repository size badge (#1174) 2017-10-14 11:38:28 -04:00
tooomm
14286e14d1 Expand documentation of querystring parameters (#1171)
Close #1170
2017-10-13 16:32:11 -04:00
Daniel Bankhead
a073a2b9a4 [NSP] badge with tests (#1156)
A continuation of #803. Scoped to `nsp/npm/:package:format` for future-proofing.
2017-10-13 11:58:47 -04:00
Jared Nance
25115ae738 Add [dotnetstatus] integration (#1028) 2017-10-12 22:55:42 -04:00
Danial
7945db8f57 Fix letter spacing on Windows Firefox, Badge padding to spec (#1161)
Update of #1132
Fix #746 #848
2017-10-12 18:35:29 -04:00
Tesla Ice Zhang
8e180a0cc5 [JetBrains] Plugin version badge (#1164)
Close #1162
2017-10-12 17:56:01 -04:00
Paul Melnikow
c5a8087ceb Node version for scoped packages and tags (#1144)
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.
2017-10-12 16:06:28 -04:00
Paul Melnikow
7f385fb361 Upgrade dev dependencies, clean lint (#1151)
Looks like eslint 4 adds `no-useless-escape` and `no-self-compare` to `eslint:recommended`.
2017-10-12 15:57:29 -04:00
Paul Melnikow
200bb11ed3 Upgrade dependencies (#1149)
These don’t appear to make any API changes that affect us.
2017-10-12 15:55:29 -04:00
Marcin Mielnicki
a7ed4b244f [suggest] Badge suggestions show incorrect license (#1159)
Fix #821
2017-10-12 15:54:34 -04:00
Pyves
71531b81ef [GitHub] Top language, languages count and code size badges (#1160)
Close #1139
2017-10-12 15:16:10 -04:00
Paul Melnikow
e375406b9a Set up Heroku review apps (#1155)
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.
2017-10-12 14:41:33 -04:00
Paul Melnikow
37bcddb23e Revert letter spacing adjustment until we can track down the problem (#1154)
See #1132
2017-10-11 14:14:03 -04:00
Paul Melnikow
4f48031551 Upgrade coverage CLI from istanbul to nyc (#1148)
Per a note posted to the istanbul readme in May, this version of istanbul is deprecated.

https://github.com/gotwarlost/istanbul
2017-10-11 13:53:24 -04:00
Sihan Li
134efb864a Add Slack logo. (#1153)
The svg file is taken and optimized from Slack_Mark_Monochrome_White.svg on https://brandfolder.com/slack
2017-10-11 10:36:34 -04:00
Delgan
088f307ddf [ReadTheDocs] Add initial support (#1150)
Close #136
2017-10-10 12:11:24 -04:00
Paul Melnikow
6f24a1ec5c Github: Fix issue label in example badges 2017-10-10 11:20:40 -04:00
Paul Melnikow
d48ebe2636 Upgrade IcedFrisby to version supporting only() (#1143) 2017-10-10 11:19:47 -04:00
Ben Gundersen
8f802f6230 Add [Wordpress] theme support (#1138)
- Added badges for Wordpress theme downloads (total) and theme rating
- Add missing dev dependency (minimist)

Close #869
2017-10-10 11:02:42 -04:00
abal
af0f338373 Attempt to show [Discord]-provided error message (#1145)
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
2017-10-09 21:31:23 -04:00
Danial
7db325c640 Fix enlarged text when min-font-size is enabled (#1132)
Fixes #746 
Fixes #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.
2017-10-09 15:29:08 -04:00
Marcin Mielnicki
848422c645 [Github] download count for latest pre-release (#1140)
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  &#x5b;atom-amd64.deb&#x5d;" 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  &#x5b;atom-amd64.deb&#x5d;" fails to match the required pattern: /^[0-9]+[kMGTPEZY]? \[atom-amd64\.deb\]$/]
2017-10-09 15:21:22 -04:00
Paul Melnikow
c579ed71e8 [Github] issues: Accommodate multi-word labels (#1135)
Fix #1134
2017-10-09 15:03:05 -04:00
Paul Melnikow
271bb4b99c Add tests for [npm] version (#1128) 2017-10-09 14:52:52 -04:00
Paul Melnikow
40f7147037 Exclude tests from coverage (#1136)
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.
2017-10-09 14:52:10 -04:00
Paul Melnikow
2809ff6888 Configure prettier and eslint-config-standard (#1123) 2017-10-09 14:46:30 -04:00
Paul Melnikow
c3636e7549 Clean up service tests (#1127)
- Consolidate regexes
- Use slimmer syntax where possible
- Fix bug caught by failing amo tests
2017-10-09 14:41:18 -04:00
Paul Melnikow
08524b639b Document named logos
From #1092.
2017-10-09 14:38:21 -04:00
Ritwick Dey
c1087c6162 " => ' 2017-10-06 15:55:33 -04:00
Ritwick Dey
2d157b3928 [GitHub] badge for (pre-)release date (#1133) 2017-10-06 15:18:25 -04:00
Paul Melnikow
f3a03c379a Get pull request metadata from shields.io (#1120)
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.
2017-10-06 14:09:21 -04:00
Paul Melnikow
dbe3ce9759 Run service tests in a separate Travis job (#1116)
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.
2017-10-06 14:08:11 -04:00
Paul Melnikow
5a3516c687 Clean up some helpers (#1117)
Address comments from #1109 and make several code-quality fixes which were caught by a local run of eslint-config-standard.
2017-10-06 13:11:29 -04:00
Ritwick Dey
e7f1f57b6b [GitHub] Latest release badge (#1122)
Reopen of #905.
2017-10-04 10:21:52 -04:00
Stefan M
67cbf4ada9 Fix colorscheme link 2017-10-03 14:51:25 -04:00
Thaddee Tyl
95ef1da7a5 Change BASE_URL to img.shields.io
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.
2017-10-03 00:21:17 +02:00
Thaddee Tyl
39a084d7c6 Log GitHub OAuth authentication failure 2017-10-02 23:50:16 +02:00
Ritwick Dey
7ae29932a5 [Github] Commits since latest release (#1115)
Close #993.
2017-10-02 14:17:41 -04:00
Paul Melnikow
bb66a99a66 [GitHub] Issue and pull request detail and check state (#1114)
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.
2017-10-02 13:26:42 -04:00
Paul Melnikow
8e08b374a4 [Github] Last commit date and commit activity (#1112)
Reopen of #928 by mskonovalov. Closes #897.
2017-10-02 10:47:14 -04:00
Paul Melnikow
c62534b5fd Move remaining helper functions to lib/ (#1109)
- Clear the regular update cache between unit tests
2017-10-01 22:08:30 -04:00
Paul Melnikow
f271b82670 Nudge forward style checks a la eslint-config-standard (#1082)
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.
2017-10-01 21:09:43 -04:00
Paul Melnikow
820b72c4c4 Always allow overriding the label (#1108)
Audit all the badges with test coverage, looking for badges which assign `badgeData.text[0]`.
2017-10-01 20:20:13 -04:00
Paul Melnikow
0068f31af2 In PR's, exclusively run the designated service tests e.g. [cran discord] (#1111)
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.
2017-10-01 20:03:29 -04:00
Paul Melnikow
5d68488426 New http endpoint for [Codecov] badges (#1037) 2017-10-01 19:56:12 -04:00
Danial
31afb007d9 [Github] manifest/package.json version support (#739) 2017-10-01 18:39:23 -04:00
Paul Melnikow
d1906598dd /ansible/role-download -> /ansible/role/d + update try.html 2017-09-30 17:42:33 -04:00
Federico Capoano
32c5ec8a6e Added ansible-galaxy role download count badge + tests #1004
Closes #1004.
2017-09-30 17:42:16 -04:00
Ritwick Dey
f6a2e2c9e3 [Bower] Add tests and prerelease badge (#1099) 2017-09-30 12:10:37 -04:00
Roman Vaughan
ea107fc76e Add AppVeyor tests badge + new tests (#1065) 2017-09-30 12:07:21 -04:00
Ritwick Dey
79174d4cfc [waffle] colorB fixes & test added (#1110)
Close #1008
2017-09-29 12:49:46 -04:00
Paul Melnikow
47ba81a007 Support named logos and omit logos by default (#1092)
- 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
2017-09-28 10:47:39 -04:00
Paul Melnikow
450d861ee5 Fix Github rate limiting in CI, again
The test harness calls out to Github too.
2017-09-28 10:04:03 -04:00
Mike Kobit
949c50d328 Add in text snippet for AsciiDoc image macro
closes https://github.com/badges/shields/issues/1104
2017-09-27 21:33:31 -04:00
James Z.M. Gao
e2ee910383 Add support for sonatype nexus (#1017)
Close #783
2017-09-27 20:48:51 -04:00
Paul Melnikow
6287c65104 mkdir first 2017-09-28 10:42:57 +10:00
Paul Melnikow
254c55f630 Fix Github rate limits in CI
Close #979
2017-09-28 10:42:57 +10:00
Marcin Mielnicki
5278816229 Badge to show downloads count from [jetbrains] plugin repository v2 (#1025)
Close #895
2017-09-27 20:39:13 -04:00
Danial
f8829475e7 [chrome-web-store] Add tests, update labels (#1100)
- 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
2017-09-27 20:34:15 -04:00
RedSparr0w
76a963369a Fix Windows coverage errors
Provide relative path to `_mocha`
2017-09-27 20:22:31 -04:00
Pierre Tomasina
6e20ca20c7 fix(continuousphp) link badge example 2017-09-27 20:05:12 -04:00
Ritwick Dey
c1425e6f44 Discord social button added at very bottom of the page (#1096)
Close #985
2017-09-26 23:30:59 -04:00
Thaddee Tyl
fa499da05f Remove automatic Travis CI email notification 2017-09-26 21:12:04 +02:00
Ritwick Dey
8476024c6c fixed ColorB issue for Docker Badge 2017-09-26 11:00:22 -04:00
Ritwick Dey
3e6ba16265 Add badge for Visual Studio Marketplace (#1074) 2017-09-25 23:05:18 -04:00
Danial
557269304c [amo] Custom labels & tests (#1090)
Add tests

Fix #996 #1026
2017-09-25 22:54:11 -04:00
un.def
4104f822fd [LuaRocks] package version badge (#1087) 2017-09-25 20:28:14 -04:00
Danial
65d6dc27cd Fix maintenance badge (#1089)
Solves #1073
Add test
2017-09-25 18:57:22 -04:00
Thaddee Tyl
ea6acb0c5e Mention loss of service for download PyPI badges
As suggested by
https://github.com/badges/shields/issues/716#issuecomment-301335162
2017-09-24 22:50:29 +02:00
Paul Melnikow
8e6fe01d20 Add test for measure-text 2017-09-24 22:36:14 +02:00
Thaddee Tyl
3d39cda984 Detail open / close on raw GitHub badges 2017-09-24 22:30:56 +02:00
Thaddee Tyl
8046a44842 Merge branch 'github-fullsupport' 2017-09-24 22:13:27 +02:00
Thaddee Tyl
26093d86d3 Add raw GitHub badges for closed issues and pr 2017-09-24 22:13:19 +02:00
Dag Wieers
4f2623aea4 Get rid of repeated "closed"
This PR includes:
- Getting rid of the option that includes 2x closed
- Using -closed-raw is no longer useful
2017-09-24 22:05:38 +02:00
Kevin Yap
c1a8166af2 Fix [crates] license badge (#1062)
License data was moved to crate versions in rust-lang/crates.io#803.
2017-09-23 23:36:34 -04:00
triggerman722
20ab540fb2 Added [codetally] (#1069) 2017-09-23 21:08:50 -04:00
Dag Wieers
22694e6cb7 Add the label to the badge when not using -raw
As requested, we now add the GitHub label to the badge, only if not
specifying `-raw` in the URL.
2017-09-23 10:05:05 +02:00
Dag Wieers
e0ecadd9fe Github: Support PR/issues with labels, full count
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).
2017-09-23 10:04:24 +02:00
Réda Housni Alaoui
13502b3a22 [maven-central] Add the ability to filter by version prefix (#1014) 2017-09-22 15:16:51 -04:00
Paul Melnikow
8ec2b6be51 Populate Github service tests (#976)
Work by webcaetano (cherry-picked by paulmelnikow)
2017-09-22 14:29:57 -04:00
Paul Melnikow
eefca67f14 Avoid inadvertently invoking unwrapped request in vendor helper functions (#924)
- Tweak a couple names to improve readability
2017-09-22 14:08:45 -04:00
Nico Schlömer
60105e1099 github "star" -> "stars" 2017-09-22 13:57:24 -04:00
Theodore Dubois
56566efd57 Add GitHub search hit counter badge 2017-09-22 13:41:49 -04:00
Abdelkrime Aries
0f65d86486 Add JitPack version badge; fixes #900 2017-09-22 13:35:10 -04:00
Christophe Bliard
cafb66bd93 Add fallback font and missing libs for .png generation
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.
2017-09-22 13:27:59 -04:00
Pascal Paulis
c7b782b014 Add [continuousphp] integration (#1051) 2017-09-22 13:19:55 -04:00
teppeis
9a3bbcdb2a fix: contributors for GitHub Enterprise 2017-09-22 01:11:50 -04:00
Paul Melnikow
852784b1a2 Fetch Bower data using libraries.io (#919)
- Avoid downloading bower packages via git
- Service is well resourced: https://libraries.io/team
- Same service used by https://bower.io/search/
2017-09-17 23:55:07 +02:00
Igor Šarčević
bce78921c8 Changing 'semaphoreapp.com' to 'semaphoreci.com' 2017-09-10 15:45:11 -07:00
Andre Caetano
46072e641d file-size path fix 2017-09-10 15:40:56 -07:00
Thaddee Tyl
fc6c5852b2 Use a ternary statement in logging code
See https://github.com/badges/shields/pull/1040#discussion_r136196343.

Closes #1040.
2017-09-03 20:04:41 +02:00
Thaddee Tyl
d032090038 Use a custom logging mechanism
This mechanism eases knowing when a message was logged while keeping the
simplicity of the logging mechanism.
2017-08-30 22:03:30 +02:00
mattbk
c023e23e0f Change Gratipay 'tips' to 'receives'
Pull request: #1053.
2017-08-30 21:58:08 +02:00
Elmar Pruesse
10566c3c0d Add Conda unit tests 2017-08-23 21:27:43 -07:00
Elmar Pruesse
94baa3a298 Cleanup conda shields
- use `const` instead of `var` where possible
 - use `'` instead of `"` consistently
 - replace `forEach` loop with `reduce` call

Thanks to @Daniel15 for review!
2017-08-23 21:27:43 -07:00
Elmar Pruesse
43b39c05c3 Add conda badges 2017-08-23 21:27:43 -07:00
Simone Vittori
2aeed7e2a9 Add tests for hex.pm integration 2017-08-13 15:51:05 -07:00
Andres Villarroel
f24093d287 Update INSTALL.md
documentation says secret.example.env file is named shields.example.env, update documentation.
2017-08-05 14:59:30 -07:00
Marcin Mielnicki
38b1168e8e Removed info about index.html
index.html has been removed
2017-07-09 18:05:42 -07:00
Tair Assimov
6534a2a1a8 Add dockbit.com badge (#1022)
* Add dockbit.com badge

* Add missing semicolon

* Remove empty and unneeded tags in SVG file

* Use ES6 consts and template string

* Add Dockbit badge tests and handle server error
2017-07-02 12:59:30 -07:00
Daniel Shumway
31aad05943 fix(gratipay): distinguish between anonymous and 0 dollar projects (#1007)
* fix(gratipay): distinguish between anonymous and 0 dollar projects

* test(gratipay): add service test

* test(gratipay): test $0
2017-07-01 22:43:11 -07:00
Marcin Mielnicki
59c91ef967 Up-to-date ServiceTester's constructor in example (#1023) 2017-07-01 22:37:19 -07:00
Eugene Bekker
ce0eb7b336 Adding support for PowerShell Gallery (#1024)
* Adding support for PowerShell Gallery

PS Gallery is nuget v2 based.  Fixes #1013.

* Updating examples with PowerShell Gallery
2017-07-01 22:35:30 -07:00
Dave Cross
79c24c569b MetaCPAN API v0 has been switched off. Change to use v1. 2017-06-14 13:50:50 +02:00
Thaddee Tyl
42a5de9cab Return when a vendor request fails
Otherwise, this creates cryptic error messages in the server logs.
2017-06-02 20:41:02 +02:00
David Tolnay
66635c510c Eliminate padding on social badges if rhs is empty (#998) 2017-06-01 23:35:56 +02:00
Adriaan Groenenboom
15f24fbcce Improve Docker run (envsubst, Alpine, documented env file) (#870)
* 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
2017-05-07 11:13:02 -07:00
Rohan Pai
f97d5a6bd4 add Sourcegraph.com badge (#828) 2017-05-05 21:30:38 -07:00
Nathan Rennie-Waldock
6031711180 Support [GitHub] releases containing a / in the tag (#756)
- Add tests for download counts
2017-05-04 16:34:44 -04:00
Paul Melnikow
80ace97bb0 Bump icedfrisby-nock to stable release (#986) 2017-05-04 09:47:13 -07:00
Daniel Lo Nigro
896b2aab2f Add Discord badge to README 2017-05-01 14:30:44 -04:00
Andre Caetano
a6d81f2391 [Github] File size badge (#745)
Closes #730
2017-05-01 14:28:45 -04:00
Daniel Lo Nigro
87af3bf672 Add [Discord] badge (#977)
Add Discord badge
2017-04-30 21:54:36 -07:00
Paul Melnikow
653f79fbde Tests: Convert to ES6, use node-fetch, refactor, and clean up style (#971) 2017-04-30 10:51:18 -04:00
Fabrizio Cucci
138c1ea4d5 [maven-central] Maven Central badge based on repo1.maven.org rather than search.maven.org (#957)
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.
2017-04-30 10:11:56 -04:00
Fabrizio Cucci
0c477524a5 Fix regexp used for matching services in pull requests (#978)
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').
2017-04-30 10:01:37 -04:00
Paul Melnikow
8233a0ba38 Fix service coverage script and linting (#975)
* Fix "callback is not a function" in coverage:test:services

* Don't lint /coverage
2017-04-29 17:31:07 -07:00
drdamour
02fc1a1a21 [sonar] Invert colors for public_documented_api_density (#974)
Fix the logic from #724.
2017-04-29 13:54:39 -04:00
Thaddee Tyl
e17c15c00b Set the coverage npm script to use current specs
The coverage script was introduced in 5c147b8d91,
and the spec files were moved in c3ef232bf7.

Also, correct a small typo.
2017-04-28 16:39:17 -04:00
drdamour
a086dca4de [sonar] Support public_documented_api_density metric as a percentage (#724)
See http://docs.sonarqube.org/display/SONAR/Metric+Definitions
2017-04-28 16:19:39 -04:00
Paul Melnikow
bd8a04141e Record minimum Node version 2017-04-28 21:16:08 +02:00
anatoly techtonik
6c34191fcf Add logo to AppVeyor badge and change logo color (#812)
Fixes #507
2017-04-28 01:35:19 -04:00
Paul Melnikow
f47aa968cd Prepare to modify / refactor analytics (#970)
- Move analytics into their own file
- Add test of analytics endpoint
2017-04-28 01:06:06 -04:00
Paul Melnikow
c3ef232bf7 Place tests alongside their code (#969)
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.
2017-04-28 00:55:15 -04:00
Saugat Acharya
df9bbbf11b Add npm weekly and npm yearly downloads badge (#958)
Add new badges npm weekly and npm yearly
2017-04-27 21:51:05 -07:00
Paul Melnikow
5c147b8d91 Service tests (#937)
- 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
2017-04-27 23:13:14 -04:00
Thaddee Tyl
a0663d8da5 Reduce page jumping while all the badges are loading
Commit c486c0dcd1 missed a large number of badges
on the webpage. This includes all relevant badges.
2017-04-27 13:14:01 -04:00
Paul Melnikow
112669e074 Remove unused / unnecessary test fixtures (#951)
`server-test.js` is not used anymore, and `gh-badge.js` can be used directly.
2017-04-26 14:26:30 -04:00
Georges Dupéron
db2aafaf2a Removed ability to specify the badge's label for the “website” service, as this is already possible with ?label=some-text 2017-04-26 14:25:15 -04:00
anatoly techtonik
65fc2a7f56 Update request to 2.81.0 (#961)
Fix deprecated uuid warning
2017-04-25 23:47:48 -04:00
Thaddee Tyl
182018be76 Redirect root to https://shields.io
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
2017-04-25 23:43:09 -04:00
Paul Melnikow
cca46b7e94 Generate index.html only on gh-pages when deploying
- 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).
2017-04-25 23:40:08 +02:00
G. Roggemans
9b8c1c806d GitHub (pre-)releases (#959)
Added the `/github/release/user/repo/all.svg` endpoint that shows the latest release, including pre-releases.
2017-04-25 12:16:28 -04:00
Daniel Lo Nigro
ccbdad69ba Split various utilities into standalone files (#952) 2017-04-24 18:37:22 -04:00
Thibaud Lepretre
108533e08e [SonarQube] Support user token authentication (#854)
- new secret: `sonarqube_token`
2017-04-24 11:21:09 -04:00
Georges Dupéron
832aaaf11d Added installation steps for Node.js 6 2017-04-20 14:38:05 -04:00
Georges Dupéron
571f46f16a Website badge: Fix color and subdirs, allow specifying label (#949) 2017-04-20 14:21:27 -04:00
Cr@zy
a079b682e3 Add badges for Uptime Robot (#947)
* numberOfDays optional (default 30) for Uptime Robot ratio
* Require a monitor key, not a user key
* Update gitignore for Jetbrains
2017-04-20 09:31:03 -04:00
Daniel Lo Nigro
c5bd4a4f5a Add badge for NuGet download count, again (#945)
Switched from SearchAutocompleteService to SearchQueryService as this service also provides download counts.

Closes #678.
2017-04-20 09:26:56 -04:00
Georges Dupéron
c6f4f57cd1 Closes #946 “maintenance badge doesn't need a question mark” (#950) 2017-04-19 19:14:56 +02:00
Paul Melnikow
07cedee321 Update index.html for recent changes 2017-04-19 00:04:56 -04:00
Georges Dupéron
26847dca80 Fix website badge for deep links (#720)
Works: https://img.shields.io/website/http/github.com.svg
Does not work: https://img.shields.io/website/http/github.com/badges.svg

Regexp was too greedy and included the beginning of the path in the protocol
2017-04-18 23:55:19 -04:00
Maël Nison
5a8b565ebb Fix NPM license badge for scoped packages (#796)
Closes #757
2017-04-18 22:42:14 -04:00
Paul Melnikow
1ffd5d949c Build branches
When merging someone else's PR with edits, it's helpful to to push a branch
and make sure the tests are also passing in CI.
2017-04-17 14:51:49 +02:00
Paul Melnikow
a3429a316a Add cauditor.org badge (#704) 2017-04-16 23:44:30 -04:00
Paul Melnikow
1ff0d9217f Fix express repository owner name (#721)
Closes #721
2017-04-13 15:48:58 -04:00
Paul Melnikow
64f8f11026 Allow specifying the key and cert for SSL (#844) 2017-04-13 15:30:30 -04:00
Paul Melnikow
59ec4a420c Check explicitly that license is an array 2017-04-13 08:17:47 +02:00
Paul Melnikow
1ae490a218 Improve CTAN error handling and fix non-svg 404 badges
Fix #921
2017-04-13 08:17:47 +02:00
Paul Melnikow
ee9ba82969 Run tests even if lint fails 2017-04-13 00:03:38 +02:00
Paul Melnikow
c7c92f12fd Clarify that secrets are optional
- Quit witih an error when secrets can’t be loaded
- Refactor duplicated code

Resolves #894
2017-04-13 00:02:18 +02:00
Paul Melnikow
9e4476d1b6 Use standard version color for clojars 2017-04-12 23:58:37 +02:00
Paul Melnikow
64e9d13e76 Disallow unused variables and turn on a few recommended rules 2017-04-12 23:55:13 +02:00
Paul Melnikow
de18dce94a Add more test helpers
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.
2017-04-12 23:13:16 +02:00
Paul Melnikow
5a45003bc3 Test server logic for img2svg error, and run the server in-process
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`.
2017-04-12 23:13:16 +02:00
Paul Melnikow
8b77d16a72 Always call the callback + reliable erroring
Fixes #914
2017-04-12 23:13:16 +02:00
Paul Melnikow
0760d17d82 Return data from svg2img via callback
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!)
2017-04-12 23:13:16 +02:00
Paul Melnikow
ad1e419d42 Add tests for svgToImg 2017-04-12 23:13:16 +02:00
Paul Melnikow
3905424d1c Add a test for badge.js and refactor 2017-04-12 23:13:16 +02:00
Thaddee Tyl
2d71e844a2 Store raster badges in the LRU cache
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)
2017-04-12 23:13:16 +02:00
Paul Melnikow
6e07fd0098 Update index.html with recent changes 2017-04-10 14:42:09 -04:00
Javier González
aa981cba84 iTunes app store version (#840) 2017-04-10 14:40:16 -04:00
Olivier Lacan
6f4c1fc3e3 Add more Shields users [ci skip] 2017-04-08 02:33:51 +02:00
Olivier Lacan
99c4c52f03 Create list of notable OSS projects using Shields
Talk about a proud daddy moment...
2017-04-08 02:27:46 +02:00
Paul Melnikow
9669c9cacf Disambiguate provider vs package: Package Control
Correctly apply changes from #898, and update build of index.html.
2017-04-07 08:28:13 -04:00
Eddie Webb
b791ffda09 Add Docker Hub build status (#856) 2017-04-07 08:07:26 -04:00
Markus Wamser
3febfe234e Add support for CRAN/METACRAN (#837) 2017-04-05 17:30:47 -04:00
Paul Melnikow
5a1e53254e Update website for April 2 deploy of 522e09f 2017-04-03 15:17:47 -04:00
Casey Webb
d462111370 Enable npm version for specific tag (#926)
* Enable npm version for specific tag
* Show tag in badge
2017-04-02 01:01:46 -04:00
Thaddee Tyl
522e09f509 Add missing var
It was fogotten when rebasing 5f945d48.
2017-03-30 23:40:49 +02:00
Nicco Kunzmann
21a3aef427 Add tutorial on how to add a new service (#889) 2017-03-30 11:46:10 -04:00
Kevin Locke
ced7f16645 [PATCH v2] Add support for swagger.io validator
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>
2017-03-30 11:41:21 -04:00
Pavel Djundik
84e2d6d7e3 Use spaces in "up to date" and "out of date" statuses 2017-03-30 00:04:37 -04:00
Peter Dave Hello
75f7f047a2 Add link in cdnjs badge example 2017-03-29 22:35:16 -04:00
Thaddee Tyl
a0e6a6aeba Use new Buffer() instead of Buffer()
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.
2017-03-29 18:28:48 -04:00
Paul Melnikow
1930d9fdd9 Change some .on to .once to make tests less flaky 2017-03-30 00:18:30 +02:00
Paul Melnikow
076bd384d5 Use a glob pattern instead of hard-coding filenames 2017-03-30 00:18:30 +02:00
Paul Melnikow
6985a778a0 Prevent lint errors 2017-03-30 00:18:30 +02:00
Paul Melnikow
5f945d4856 Use Mocha to make tests more reliable 2017-03-30 00:18:30 +02:00
Peter Dave Hello
2e4721ea1f Migrate to the new container based infra on Travis-ci
Use the "apt" add-on to install apt packages instead of using "apt-get"
command directly, and then move to the new container-based
infrastructure, which can speed up the build process.

PS: package "g++" removed from the list since it's already the
dependency of package "build-essential", no need to duplicate it.

Reference:
 - https://docs.travis-ci.com/user/ci-environment/
 - https://docs.travis-ci.com/user/installing-dependencies/
 - https://github.com/travis-ci/apt-package-whitelist/
2017-03-29 23:55:52 +02:00
Paul Melnikow
b410b0b7e7 Remove Talk.ai which no longer exists
No response at guest.talk.ai talk.ai, and nothing in google either
2017-03-29 20:14:26 +02:00
Paul Melnikow
d985f81f8e Disallow undefined variables 2017-03-29 20:09:30 +02:00
Paul Melnikow
5a83b6c4a6 Show correct hostname and port in try.html URL 2017-03-29 19:58:14 +02:00
Paul Melnikow
7c4b2b67e6 Add github standard node gitignores 2017-03-29 19:49:19 +02:00
Sebastian Hoß
7fad7268ef use greater-equals for SonarQube tech_debt colors
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>
2017-03-29 13:24:39 -04:00
Akihiro Uchida
7eeef988ba Fix imagelayers.io badges (#706)
Resolves #712
2017-03-28 00:30:32 -04:00
Paul Melnikow
e8988a985c Clean lint from #1275 2017-03-27 17:18:50 -04:00
Michael Howell
3dd0f96f77 Add docs.rs as a standard-compliant service
![mio on docs.rs](https://docs.rs/mio/badge.svg)
2017-03-27 17:05:17 -04:00
Pavel Djundik
c486c0dcd1 Reduce page jumping while all the badges are loading 2017-03-27 17:00:59 -04:00
Danial
7843331f5f Add badge "404 | badge not found"
For invalid url specified ending in "svg, png, gif, jpg or json"
2017-03-27 16:58:24 -04:00
Frode Knutsen
2133ff9d1f fix default value for githubUserTokens 2017-03-27 16:56:58 -04:00
Nicco Kunzmann
499c3ea724 add format documentation links
Problem: I wanted to know what color schema is available
Solution: Add links to directly reach the predefined schemes and templates
2017-03-27 16:56:10 -04:00
Francisco Lourenço
9b24ef7dbe Disambiguate provider vs package: Package Control
Spent some time trying to figure out how this was supposed to work :P
2017-03-27 16:54:39 -04:00
Paul Melnikow
0def6470a7 Disallow variable redeclaration 2017-03-26 20:02:56 -04:00
Thaddee Tyl
5dd58142cb Fix LRU cache index stalling
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.
2017-03-26 23:00:31 +02:00
Thaddee Tyl
11b6e06f2f Organize local modules in lib 2017-03-26 22:57:55 +02:00
Paul Melnikow
47a8bf51dc First pass for linting on PRs 2017-03-20 16:54:27 -04:00
Thaddee Tyl
ecd30480de Update maintenance badge for 2017 2017-02-26 20:57:35 +01:00
Thaddee Tyl
076cb14b3b Perform constant equal comparison for shared Shields secret
This should prevent timing attacks.
2017-02-25 18:20:07 +01:00
Thaddee Tyl
2f97be9118 Pre-compress badge templates with SVGO
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).
2017-02-25 18:20:07 +01:00
Thaddee Tyl
38cf7a60b5 Use path.extname() to fetch template file name extension 2017-02-19 22:59:41 +01:00
Thaddee Tyl
bf373d11cd Fix incorrect sendBadge() parameter order 2017-02-18 22:58:46 +01:00
Thaddee Tyl
4d937d859a Fix readme logo path 2017-02-16 23:19:33 +01:00
Thaddee Tyl
0758595b57 website: bitbucket open pull requests
Part of #790.
2017-02-15 23:57:19 +01:00
Thaddee Tyl
982bcf62aa Add s2 server
Part of #868.
2017-02-13 00:54:23 +01:00
Thaddee Tyl
a4a46b070c Foolproof Bitbucket pull request
- 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.
2017-02-11 00:09:44 +01:00
Thaddee Tyl
4c2b2f4852 Merge branch 'bitbucket' 2017-02-10 23:50:41 +01:00
chapulina
976e5f2ee0 Bitbucket open pull requests 2017-02-10 23:50:34 +01:00
Thaddee Tyl
6ebd626973 Fix Shield.io (should be Shields.io)
Fixes #871.
2017-02-08 00:21:02 +01:00
Thaddee Tyl
7c8b0e3d32 Contain all private files in private/ 2017-02-05 16:24:35 +01:00
Thaddee Tyl
efc9ce8eed Ensure that logo.svg is at the root
That is necessary for GitHub's gh-pages website to work.
2017-02-05 16:24:15 +01:00
Thaddee Tyl
6258968d66 Restrain public files to the public/ folder
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.
2017-02-05 13:40:06 +01:00
Thaddee Tyl
8272913d5e website: Jenkins format extension 2017-02-02 23:39:39 +01:00
Thaddee Tyl
bc34b6060d Merge branch 'nuget' 2017-02-01 23:59:51 +01:00
Thaddee Tyl
7f79712f0d Set Nuget version endpoint update to 42 minutes 2017-02-01 23:59:08 +01:00
Maarten Balliauw
361a6e344a Update NuGet v3 implementation to not show unlisted versions
Fixes #795.
2017-02-01 23:58:10 +01:00
Thaddee Tyl
f834bbbb88 Merge branch 'jenkins' 2017-01-30 23:34:25 +01:00
Thaddee Tyl
5eb9eb2bb5 Improve consistency of spacing in code 2017-01-30 23:34:15 +01:00
Thaddee Tyl
eb74626f52 Resize PNG images correctly 2017-01-29 19:14:31 +01:00
Federico Zivolo
8dccc153cf preserve transparent background 2017-01-29 19:14:31 +01:00
Federico Zivolo
ef1a51590e Use gm instead of phantom to create pngs 2017-01-29 19:14:31 +01:00
Thaddee Tyl
79eb256b75 Twitter badge: allow ?colorB override 2017-01-27 23:36:51 +01:00
Thaddee Tyl
225ed98663 Mention the need to minimize .svg images
As suggested by https://github.com/badges/shields/pull/861#discussion_r96729020.
2017-01-24 23:03:12 +01:00
Masahiro Fujiwara
32f4d6d4da Update Jenkins job path to contain ‘/‘ in try.html examples. 2017-01-17 06:43:25 +09:00
Masahiro Fujiwara
70efc96b11 Take ’/job’ prefix out only if ‘/‘ appears. For backward compatibility. 2017-01-17 06:36:48 +09:00
Masahiro Fujiwara
7ac216456a Fix regexp for Jenkins build badges to allow “/“ in the job name. 2017-01-17 06:07:05 +09:00
Thaddee Tyl
21ae49ad85 Merge remote-tracking branch 'aspyker/master'
Fixes #741.
2017-01-11 23:57:10 +01:00
Thaddee Tyl
4924bd6098 website: JIRA sprint 2017-01-10 23:54:03 +01:00
Thaddee Tyl
62ecc175ca Merge branch 'jira-sprint'
Fixes #770.
2017-01-09 23:56:37 +01:00
Thomas VIAL
83da3fefef Added JIRA agile sprint completion 2017-01-09 23:56:09 +01:00
Thaddee Tyl
8d5e18e727 Mention that colorA/B only allow hex colors in URL 2017-01-08 17:39:24 +01:00
Thaddee Tyl
a440c0840b Register colorA/B as part of the cache index 2017-01-08 17:26:26 +01:00
Thaddee Tyl
2ba7ded391 Prioritize colorA/B over colorscheme colors
The wrong priority order was made in 29a4803e4b.
When a user enters ?colorB=007ec6, they want that color to override the default.
2017-01-08 17:21:35 +01:00
Thaddee Tyl
9816a5010f Allow CORS for suggestions on https://shields.io
Issue raised here: https://twitter.com/igoradamenko_/status/818095292146941952
2017-01-08 16:48:02 +01:00
Thaddee Tyl
78494dd6ff Fix blurry rounded corners on WebKit
WebKit bug: https://bugs.webkit.org/show_bug.cgi?id=135616
Fixes #732
2016-12-15 02:09:07 +01:00
Thaddee Tyl
036107c30e Fix the size of the Shields.io logo 2016-12-14 22:44:33 +01:00
Thaddee Tyl
c9d94aaf1a More compressed logo
Courtesy of Oleg Kikin: https://news.ycombinator.com/item?id=13139573
2016-12-09 21:47:58 +01:00
Thaddee Tyl
da6dd3cbfe website: chrome web store, mozilla add-ons 2016-11-25 23:29:59 +01:00
Thaddee Tyl
052740ff15 Improve Chrome Web Store: price with currency, rating over 5 2016-11-25 00:08:49 +01:00
Thaddee Tyl
1b699773ba Factorize star rating string generation
There was duplicated code in d10764a8f5.

Related to #831.
2016-11-24 23:56:31 +01:00
RedSparr0w
868c7f8a5a update try.html 2016-11-24 23:54:49 +01:00
RedSparr0w
d10764a8f5 add 5 star ratings 2016-11-24 23:54:49 +01:00
Thaddee Tyl
2b63d62242 Re-remove the ass testing dependency
It was mistakenly added by 2cb82a4a.
2016-11-20 18:53:51 +01:00
Thaddee Tyl
10e49ac743 website: Mozilla add-ons, colorA/B 2016-11-01 20:05:27 +01:00
Thaddee Tyl
29a4803e4b Support combining colorA and colorscheme 2016-10-30 15:36:10 +01:00
Konstantin Zudov
52b0369c14 Allow specifying the color of left/right part
Specifying `colorA`/`colorB` parameters allows
to change the background color of the left/right
part of the badge.
2016-10-30 15:36:05 +01:00
Thaddee Tyl
7403b61e25 Mozilla Add-ons: say "add-on" instead of addon
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).
2016-10-30 10:51:52 +01:00
Józef Sokołowski
2cb82a4ab3 Add Mozilla Addons support 2016-10-30 10:47:56 +01:00
Danial
3edd0df04c CircleCI: show vendor error messages on badges
example:
https://github.com/badges/shields/pull/798#issuecomment-255621160
2016-10-26 00:10:44 +02:00
Thaddee Tyl
6e5904df0a Match CircleCI project host with trailing /
This prevents from misparsing /circleci/project/githubuser/repo.svg as user
"user".

Related to #798.
2016-10-23 17:26:47 +02:00
Thaddee Tyl
dce818a7d2 Merge remote-tracking branch 'redsparrow/Circle_CI' 2016-10-23 17:23:18 +02:00
RedSparr0w
2b0d688d09 Update With Changes 2016-10-22 22:56:40 +13:00
Thaddee Tyl
20407267ad Merge remote-tracking branch 'david-a-wheeler/cii' 2016-10-16 11:28:58 +02:00
Thaddee Tyl
9e66a48621 Merge remote-tracking branch 'tomav/fix-dockerfile' 2016-10-16 10:47:27 +02:00
Peter Dave Hello
251c792d74 Add CDNJS version integration 2016-10-15 23:16:25 +08:00
Thaddee Tyl
1996a5399f Ensure GitHub contributors can have a metric prefix 2016-10-15 16:38:43 +02:00
Thaddee Tyl
670867098d Send false instead of Nan to GitHub contributors-anon 2016-10-15 16:35:39 +02:00
Thaddee Tyl
18bc0be3e5 Merge remote-tracking branch 'qzb/bugfix/contributors-badge' 2016-10-15 16:34:33 +02:00
Thaddee Tyl
ef0d53d444 Merge remote-tracking branch 'nishanthvijayan/chrome-label' 2016-10-15 15:47:21 +02:00
Thaddee Tyl
8c6fb7088d Merge remote-tracking branch 'peterdavehello/bumpDependencies' 2016-10-15 15:30:05 +02:00
Thaddee Tyl
37740cc648 website: Twitter follow, style selector fix 2016-10-15 15:21:13 +02:00
Thaddee Tyl
f0273ff797 Merge remote-tracking branch 'techtonik/patch-1' 2016-10-15 15:15:26 +02:00
Thaddee Tyl
2b44bcc7c2 Use maintainer's twitter account 2016-10-15 14:48:43 +02:00
Peter Dave Hello
6c21450c46 bump dependencies 2016-10-10 16:52:01 +08:00
RedSparr0w
e31f9ac2bd Fix Circle CI Integration 2016-09-27 11:16:18 +13:00
Thaddee Tyl
b74107eb3d Stop using a link for default badge template
npm cannot handle links.
See https://github.com/npm/npm/issues/13884.
2016-09-08 23:23:43 +01:00
Nishanth Vijayan
25fb85e397 Allow label overriding in all Chrome web store badges 2016-09-06 16:46:41 +05:30
anatoly techtonik
64c01c3c1f Also correctly strip maxAge from initial link 2016-08-30 14:24:08 +03:00
anatoly techtonik
9ba76602c1 Fix badge preview on style change
This was broken by 89affa49fe
2016-08-30 13:06:20 +03:00
Thomas VIAL
e374eeab80 Fixed Dockerfile and improved doc regarding secret.json. 2016-08-18 13:28:37 +02:00
Józef Sokołowski
dfb4804973 Fix contributors badge
Fixes #764
2016-08-16 10:52:49 +02:00
David A. Wheeler
4dc16c3019 Add CII Best Practices
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".
2016-08-12 10:52:01 -04:00
Andrew Spyker
925c314ffd add NetflixOSS OSSMETADATA osslifecycle support 2016-07-09 20:57:35 -07:00
Andrew Spyker
8754cdc7e3 fix docker command 2016-07-09 19:54:27 -07:00
622 changed files with 59246 additions and 10376 deletions

259
.circleci/config.yml Normal file
View File

@@ -0,0 +1,259 @@
version: 2
jobs:
npm-install:
docker:
- image: circleci/node:8
steps:
- checkout
- restore_cache:
keys:
- v2-dependencies-{{ checksum "package.json" }}
# fallback to using the latest cache if no exact match is found
- v2-dependencies-
- run:
name: Install dependencies
command: npm install
- save_cache:
paths:
- node_modules
key: v2-dependencies-{{ checksum "package.json" }}
main:
docker:
- image: circleci/node:8
- image: redis
steps:
- checkout
- restore_cache:
key: v2-dependencies-{{ checksum "package.json" }}
# https://github.com/badges/shields/issues/1937
key: v2-dependencies-
- run:
name: Install dependencies
command: npm install
- run:
name: Linter
when: always
command: npm run lint
- run:
name: Server unit tests
when: always
command: npm run test:js:server
- run:
name: Integration tests
when: always
command: npm run test:integration
- run:
name: Tests for gh-badges package
when: always
command: npm run test:js:package
- run:
name: 'Prettier check (quick fix: `npm run prettier`)'
when: always
command: npm run prettier-check
main@node-latest:
docker:
- image: circleci/node:latest
- image: redis
steps:
- checkout
- restore_cache:
key: v2-dependencies-{{ checksum "package.json" }}
# https://github.com/badges/shields/issues/1937
key: v2-dependencies-
- run:
name: Install dependencies
command: npm install
- run:
name: Linter
when: always
command: npm run lint
- run:
name: Server unit tests
when: always
command: npm run test:js:server
- run:
name: Integration tests
when: always
command: npm run test:integration
- run:
name: Tests for gh-badges package
when: always
command: npm run test:js:package
- run:
name: 'Prettier check (quick fix: `npm run prettier`)'
when: always
command: npm run prettier-check
danger:
docker:
- image: circleci/node:8
steps:
- checkout
- restore_cache:
key: v2-dependencies-{{ checksum "package.json" }}
# https://github.com/badges/shields/issues/1937
key: v2-dependencies-
- run:
name: Install dependencies
command: npm install
- run:
name: Danger
when: always
command: npm run danger ci
frontend:
docker:
- image: circleci/node:8
steps:
- checkout
- restore_cache:
key: v2-dependencies-{{ checksum "package.json" }}
# https://github.com/badges/shields/issues/1937
key: v2-dependencies-
- run:
name: Install dependencies
command: npm install
- run:
name: Frontend unit tests
when: always
command: npm run test:js:frontend
- run:
name: Frontend build completes successfully
when: always
command: npm run build
services:
docker:
- image: circleci/node:8
steps:
- checkout
- run:
name: Prepare service tests
command: |
mkdir private
echo "{\"gh_token\":\"$GITHUB_TOKEN\"}" > private/secret.json
- restore_cache:
key: v2-dependencies-{{ checksum "package.json" }}
# https://github.com/badges/shields/issues/1937
key: v2-dependencies-
- run:
name: Install dependencies
command: npm install
- run:
name: Identify services tagged in the PR title
command: |
if [[ ! -z $CI_PULL_REQUEST ]]; then
npm run test:services:pr:prepare
else
echo 'This is not a pull request. Skipping.'
fi
- run:
name: Run tests for tagged services
command: |
if [[ ! -z $CI_PULL_REQUEST ]]; then
npm run test:services:pr:run
else
echo 'This is not a pull request. Skipping.'
fi
services@node-latest:
docker:
- image: circleci/node:latest
steps:
- checkout
- run:
name: Prepare service tests
command: |
mkdir private
echo "{\"gh_token\":\"$GITHUB_TOKEN\"}" > private/secret.json
- restore_cache:
key: v2-dependencies-{{ checksum "package.json" }}
# https://github.com/badges/shields/issues/1937
key: v2-dependencies-
- run:
name: Install dependencies
command: npm install
- run:
name: Identify services tagged in the PR title
command: |
if [[ ! -z $CI_PULL_REQUEST ]]; then
npm run test:services:pr:prepare
else
echo 'This is not a pull request. Skipping.'
fi
- run:
name: Run tests for tagged services
command: |
if [[ ! -z $CI_PULL_REQUEST ]]; then
npm run test:services:pr:run
else
echo 'This is not a pull request. Skipping.'
fi
workflows:
version: 2
on-commit:
jobs:
- npm-install:
filters:
branches:
ignore: gh-pages
- main:
requires:
- npm-install
- main@node-latest:
requires:
- npm-install
- frontend:
requires:
- npm-install
- services:
requires:
- npm-install
- services@node-latest:
requires:
- npm-install
- danger:
requires:
- npm-install
filters:
branches:
ignore: /dependabot\/.*/

4
.dockerignore Normal file
View File

@@ -0,0 +1,4 @@
node_modules/
shields.env
.git/
.gitignore

3
.eslintignore Normal file
View File

@@ -0,0 +1,3 @@
/build
/coverage
/__snapshots__

24
.eslintrc-frontend.yml Normal file
View File

@@ -0,0 +1,24 @@
env:
browser: true
plugins:
- import
parser: "babel-eslint"
parserOptions:
sourceType: "module"
extends:
- "standard-jsx"
- "standard-react"
- "./.eslintrc.yml"
settings:
react:
version: "16.4"
rules:
no-console: "error"
import/extensions: ["error", "never", { "json": "always" }]

49
.eslintrc.yml Normal file
View File

@@ -0,0 +1,49 @@
extends:
- standard
- prettier
env:
node: true
mocha: true
parserOptions:
# Override eslint-config-standard, which incorrectly sets this to "module",
# though that setting is only for ES6 modules, not CommonJS modules.
sourceType: "script"
plugins:
- mocha
- no-extension-in-require
- "chai-friendly"
rules:
# Disable some rules from eslint:recommended.
no-console: "off"
no-empty: ["error", { "allowEmptyCatch": true }]
# Allow unused parameters. In callbacks, removing them seems to obscure
# what the functions are doing.
no-unused-vars: ["error", {"args": "none"}]
# These should be disabled by eslint-config-prettier, but are not.
spaced-comment: "off"
standard/object-curly-even-spacing: "off"
one-var: "off"
# Shields additions.
no-var: "error"
prefer-const: "error"
strict: "error"
arrow-body-style: ["error", "as-needed"]
no-extension-in-require/main: "error"
object-shorthand: ["error", "properties"]
prefer-template: "error"
promise/prefer-await-to-then: "error"
# Mocha-related.
mocha/no-exclusive-tests: "error"
mocha/no-mocha-arrows: "error"
mocha/prefer-arrow-callback: "error"
# Chai friendly.
no-unused-expressions: "off"
chai-friendly/no-unused-expressions: "error"

26
.github/ISSUE_TEMPLATE/1_Bug_report.md vendored Normal file
View File

@@ -0,0 +1,26 @@
---
name: 🐛 Bug Report
about: Report errors and problems
---
Are you experiencing an issue with...
- [ ] [shields.io](https://shields.io/#/)
- [ ] My own instance
- [ ] [gh-badges NPM package](https://www.npmjs.com/package/gh-badges)
:beetle: **Description**
<!-- A clear and concise description of the problem. -->
:link: **Link to the badge**
<!--
If you are reporting a problem with a specific badge on shields.io,
provide a link to a badge demonstrating the error
-->
:bulb: **Possible Solution**
<!--- Optional: only if you have suggestions on a fix/reason for the bug -->
<!-- Love Shields? Please consider donating $10 to sustain our activities:
👉 https://opencollective.com/shields -->

View File

@@ -0,0 +1,28 @@
---
name: 💡 Badge Request
about: Ideas for new badges
---
:clipboard: **Description**
<!--
A clear and concise description of the new badge.
- Which service is this badge for e.g: GitHub, Travis CI
- What sort of information should this badge show?
Provide an example in plain text e.g: "version | v1.01" or as a static badge
(static badge generator can be found at https://shields.io)
-->
:link: **Data**
<!--
Where can we get the data from?
- Is there a public API?
- Does the API requires an API key?
- Link to the API documentation.
-->
<!-- Love Shields? Please consider donating $10 to sustain our activities:
👉 https://opencollective.com/shields -->

View File

@@ -0,0 +1,12 @@
---
name: 💡 Feature Request
about: Ideas for other new features or improvements
---
:clipboard: **Description**
<!-- A clear and concise description of the new feature. -->
<!-- Love Shields? Please consider donating $10 to sustain our activities:
👉 https://opencollective.com/shields -->

View File

@@ -0,0 +1,17 @@
---
name: ❓ Support Question
about: Ask a question about shields.io
---
:question: **Question**
<!--
Ask your question clearly and concisely.
#support on our [Discord](https://discordapp.com/invite/HjJCwm5)
is also a great place to ask questions and get help
-->
<!-- Love Shields? Please consider donating $10 to sustain our activities:
👉 https://opencollective.com/shields -->

10
.github/probot.js vendored Normal file
View File

@@ -0,0 +1,10 @@
on('pull_request.closed')
.filter(context => context.payload.pull_request.merged)
.filter(
context =>
context.payload.pull_request.head.ref.slice(0, 11) !== 'dependabot/'
)
.filter(context => context.payload.pull_request.base.ref === 'master')
.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: ![](https://img.shields.io/github/commit-status/{{ repository.full_name }}/gh-pages/{{ pull_request.merge_commit_sha }}.svg?label=deploy%20status)`)

81
.gitignore vendored
View File

@@ -4,11 +4,10 @@
/coverage.html
/redis
/ServerScript
/secret.json
/.github-user-tokens.json
# Installed npm modules
node_modules
/private
/index.html
/shields.env
gh-badges/package-lock.json
# Folder view configuration files
.DS_Store
@@ -18,6 +17,78 @@ Desktop.ini
._*
Thumbs.db
# eclipse
.project
.settings
# Files that might appear on external disks
.Spotlight-V100
.Trashes
# Jetbrains
/.idea
# Created by https://www.gitignore.io/api/node
### Node ###
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# Temporary build artifacts.
/build
.next
badge-examples.json
supported-features.json

16
.nycrc.json Normal file
View File

@@ -0,0 +1,16 @@
{
"reporter": ["lcov"],
"all": true,
"exclude": [
"**/*.spec.js",
"**/*.integration.js",
"dangerfile.js",
"services/**/*.tester.js",
"test-fixtures",
"scripts",
"coverage",
"build"
],
"silent": true,
"clean": false
}

8
.prettierignore Normal file
View File

@@ -0,0 +1,8 @@
package.json
package-lock.json
/__snapshots__
/.next
/build
/coverage
**/*.md
private/*.json

4
.prettierrc.yml Normal file
View File

@@ -0,0 +1,4 @@
semi: false
singleQuote: true
trailingComma: es5
bracketSpacing: true

View File

@@ -1,18 +0,0 @@
before_install:
- sudo apt-get update -myqq
- sudo apt-get install libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++
language: node_js
node_js:
- 6
branches:
only:
- master
notifications:
email:
- thaddee.tyl@gmail.com
irc: "irc.freenode.org#shields"
git:
depth: 10

1
CNAME
View File

@@ -1 +0,0 @@
shields.io

View File

@@ -1,65 +1,165 @@
# Contribution Guidelines
Contributing to Shields
=======================
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:
[![GitHub issues by-label](https://img.shields.io/github/issues/badges/shields/good%20first%20issue.svg)](https://github.com/badges/shields/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
### Contributing documentation
You can help by improving the project's usage and developer instructions.
- When you read the documentation, you can fix mistakes and add your own thoughts.
- When your pull request follows the documentation but the practice changed,
consider pointing this out and change the documentation for the next person.
### Helping others
You can help with code review, which reduces bugs, and over time has a
wonderful side effect of making the code more readable and therefore more
approachable. It's also a great way to teach and learn. Feel free to jump in!
Be welcoming, appreciative, and helpful. You can perform first reviews of
simple changes, like badge additions. These are usually tagged with
[service badge][service badge PR tag].
Please review [these impeccable guidelines][code review guidelines].
You can monitor [issues][] and the [chat room][], and help other people who
have questions about contributing to Shields, or using it for their projects.
Feel free to reach out to one of the [maintainers][]
if you need help getting started.
[service badge PR tag]: https://github.com/badges/shields/pulls?q=is%3Apr+is%3Aopen+label%3Aservice-badge
[code review guidelines]: http://amyciavolino.com/assets/MindfulCommunicationInCodeReviews.pdf
[issues]: https://github.com/badges/shields/issues
[chat room]: https://discordapp.com/invite/HjJCwm5
[maintainers]: https://github.com/badges/shields#project-leaders
### Suggesting improvements
There are _a lot_ of suggestions on file. You can help by weighing in on these
suggestions, which helps convey community need to other contributors who might
pick them up.
There is no need to post a new comment. Just add a :thumbsup: or :heart: to
the top post.
If you have a suggestion of your own, [search the open issues][issues]. If you
don't see it, feel free to [open a new issue][open an issue].
[open an issue]: https://github.com/badges/shields/issues/new/choose
### Spreading the word
Feel free to star the repository. This will help increase the visibility of the project, therefore attracting more users and contributors to Shields!
We're also asking for [one-time $10 donations](https://opencollective.com/shields) from developers who use and love Shields, please spread the word!
Getting help
------------
There are three places to get help:
1. If you're new to the project, a good place to start is the [tutorial][].
2. If you need help getting started or implementing a change, [open an issue][]
with your question. We promise it's okay to do that. If there is already an
issue open for the feature you're working on, you can post there.
3. You can also join the [chat room][] and ask your question there.
[tutorial]: doc/TUTORIAL.md
Badge guidelines
----------------
- Shields.io hosts integrations for services which are primarily
used by developers or which are widely used by developers
- The left-hand side of a badge should not advertise. It should be a lowercase *noun*
succinctly describing the meaning of the right-hand side.
- Query parameters must be *declared by the service*. See `request-handler.js`.
- Except for badges using the `social` style, logos should be *turned off by
default*.
Badge URLs
----------
- The left-hand side of a badge should not advertize. It should be a noun
describing succinctly the meaning of the right-hand-side data.
- New query parameters (such as `?label=` or `?style=`) should apply to any
requested badge. They must be registered in the cache (see `LruCache` in
`server.js`).
- The format of new badges should be of the form
`/VENDOR/SUBVENDOR-BADGE-SPECIFIC/PARAMETERS.format`. For instance,
`https://img.shields.io/gitter/room/nwjs/nw.js.svg`. The vendor is gitter, the
`/SERVICE/NOUN/PARAMETERS/QUALIFIERS.format`. For instance,
`/gitter/room/nwjs/nw.js.svg`. The vendor is gitter, the
badge is for rooms, the parameter is nwjs/nw.js, and the format is svg.
## Implementations
The main implementation, available at <http://shields.io>, has its code located in this repository.
Other systems that produce badges following the same design, hosted elsewhere, are listed below.
| website / AP | language | issues |
| --------------------------------- | ---------- | ---------------------------- |
| shielded | JavaScript | [shielded][shielded issues] |
| [buckler.repl.ca][] | Go | [buckler][buckler issues] |
| old img.shields.io (discontinued) | Python | [img.shields.io-old][] |
| DotBadge | C# | [DotBadge](https://github.com/rebornix/DotBadge/issues) |
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,
`/discourse/https/discourse.example.com/topics.svg`.
[shields.io]: http://shields.io/
[website]: https://github.com/badges/shields/tree/gh-pages
[GitHub Issues]: https://github.com/badges/shields/issues
[new issue]: https://github.com/badges/shields/issues/new
Coding guidelines
-----------------
[img.shields.io]: http://img.shields.io/
[gh-badges issues]: https://github.com/badges/shields/issues
[primary]: https://github.com/badges/shields/issues/94
### Prettier
[shielded issues]: https://github.com/badges/shielded/issues
This project formats its source code using Prettier. The most enjoyable way to
use Prettier is to let is format code for you when you save. You can [integrate
it into your editor][integrate prettier].
[buckler.repl.ca]: http://buckler.repl.ca/
[buckler issues]: https://github.com/badges/buckler/issues
Whether you integrate it into your editor or not, a pre-commit hook will run
Prettier before a commit by default.
[img.shields.io-old]: https://github.com/badges/img.shields.io-old/issues
[integrate prettier]: https://prettier.io/docs/en/editors.html
### Tests
When adding or changing a service [please write tests][service-tests].
When opening a pull request, include your service name in brackets in the pull
request title. That way, those service tests will run in CI.
e.g. **[Travis] Fix timeout issues**
When changing other code, please add unit tests.
To run the integration tests, you must have redis installed and in your PATH.
Use `brew install redis`, `yum install redis`, etc. The test runner will
start the server automatically.
[service-tests]: https://github.com/badges/shields/blob/master/doc/service-tests.md
### Code organization
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 ![](https://img.shields.io/badge/play-station-blue.svg?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEiIHdpZHRoPSI2MDAiIGhlaWdodD0iNjAwIj48cGF0aCBkPSJNMTI5IDExMWMtNTUgNC05MyA2Ni05MyA3OEwwIDM5OGMtMiA3MCAzNiA5MiA2OSA5MWgxYzc5IDAgODctNTcgMTMwLTEyOGgyMDFjNDMgNzEgNTAgMTI4IDEyOSAxMjhoMWMzMyAxIDcxLTIxIDY5LTkxbC0zNi0yMDljMC0xMi00MC03OC05OC03OGgtMTBjLTYzIDAtOTIgMzUtOTIgNDJIMjM2YzAtNy0yOS00Mi05Mi00MmgtMTV6IiBmaWxsPSIjZmZmIi8+PC9zdmc+) could be generated by calling: https://img.shields.io/badge/play-station-blue.svg?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEiIHdpZHRoPSI2MDAiIGhlaWdodD0iNjAwIj48cGF0aCBkPSJNMTI5IDExMWMtNTUgNC05MyA2Ni05MyA3OEwwIDM5OGMtMiA3MCAzNiA5MiA2OSA5MWgxYzc5IDAgODctNTcgMTMwLTEyOGgyMDFjNDMgNzEgNTAgMTI4IDEyOSAxMjhoMWMzMyAxIDcxLTIxIDY5LTkxbC0zNi0yMDljMC0xMi00MC03OC05OC03OGgtMTBjLTYzIDAtOTIgMzUtOTIgNDJIMjM2YzAtNy0yOS00Mi05Mi00MmgtMTV6IiBmaWxsPSIjZmZmIi8+PC9zdmc+
[simpleicons]: https://simpleicons.org/
[simple-icons github]: https://github.com/simple-icons/simple-icons
[SVGO]: https://github.com/svg/svgo
[svgomg]: https://jakearchibald.github.io/svgomg/

View File

@@ -1,3 +1,21 @@
FROM node:0.12-onbuild
ENV INFOSITE http://shields.io
FROM node:8.9.4-alpine
RUN apk add --no-cache gettext imagemagick librsvg git
RUN mkdir -p /usr/src/app
RUN mkdir /usr/src/app/private
WORKDIR /usr/src/app
ARG NODE_ENV
ENV NODE_ENV $NODE_ENV
COPY package.json /usr/src/app/
RUN npm install
COPY . /usr/src/app
RUN npm run build
RUN npm prune --production
RUN npm cache clean --force
CMD envsubst < secret.tpl.json > ./private/secret.json \
&& node server
EXPOSE 80

View File

@@ -1,170 +0,0 @@
# GitHub badges in SVG format
[![npm version](http://img.shields.io/npm/v/gh-badges.svg)](https://npmjs.org/package/gh-badges)
![coverage](https://rawgithub.com/badges/shields/master/coverage.svg)
[![build status](http://img.shields.io/travis/badges/gh-badges.svg)](https://travis-ci.org/badges/gh-badges)
Make your own badges [here][badges]! (Quick guide: `https://img.shields.io/badge/left-right-f39f37.svg`.)
[badges]: <http://shields.io/#your-badge>
# Install the API
```bash
npm install gh-badges
```
```js
var badge = require('gh-badges');
// Optional step, to have accurate text width computation.
badge.loadFont('/path/to/Verdana.ttf', function(err) {
badge({ text: ["build", "passed"], colorscheme: "green", template: "flat" },
function(svg, err) {
// svg is a String of your badge.
});
});
```
# Use the CLI
```bash
npm install -g gh-badges
badge build passed :green .png > mybadge.png
# Stored a PNG version of your badge on disk.
```
# Start the Server
To run the server you will need the following executables on your Path:
- [PhantomJS](http://www.phantomjs.org/)
On an OS X machine, [Homebrew](brew.sh) is a good package manager that will
allow you to install that.
On Ubuntu / Debian: `sudo apt-get install phantomjs`.
```bash
git clone https://github.com/badges/shields.git
cd shields
npm install # You may need sudo for this.
sudo node server
```
The server uses port 80 by default, which requires `sudo` permissions.
There are two ways to provide an alternate port:
```bash
PORT=8080 node server
node server 8080
```
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.
# Format
The format is the following:
```js
{
/* Textual information shown, in order. */
"text": [ "build", "passed" ],
"format": "svg", // Also supports "json".
"colorscheme": "green",
/* … Or… */
"colorA": "#555",
"colorB": "#4c1",
/* See template/ for a list of available templates.
Each offers a different visual design. */
"template": "flat"
}
```
# Defaults
If you want to add a colorscheme, head to `colorscheme.json`. Each scheme has a
name and a [CSS/SVG color][] for the color used in the first box (for the first
piece of text, field `colorA`) and for the one used in the second box (field
`colorB`).
[CSS/SVG color]: http://www.w3.org/TR/SVG/types.html#DataTypeColor
```js
"green": {
"colorB": "#4c1"
}
```
Both `colorA` and `colorB` have default values. Usually, the first box uses the
same dark grey, so you can rely on that default value by not providing a
`"colorA"` field (such as above).
You can also use the `"colorA"` and `"colorB"` fields directly in the badges if
you don't want to make a color scheme for it. In that case, remove the
`"colorscheme"` field altogether.
# Making your Heroku badge server
Once you have installed the [Heroku Toolbelt][]:
[Heroku Toolbelt]: https://toolbelt.heroku.com/
```bash
heroku login
heroku create your-app-name
heroku config:set BUILDPACK_URL=https://github.com/mojodna/heroku-buildpack-multi.git#build-env
cp /path/to/Verdana.ttf .
make deploy
heroku open
```
# Docker
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].
[gem]: https://github.com/badges/badgerbadgerbadger
# License
All work here is licensed CC0.

116
LICENSE Normal file
View File

@@ -0,0 +1,116 @@
CC0 1.0 Universal
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:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. 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
vii. 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.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@@ -1,33 +0,0 @@
# DEDICATED TO THE PUBLIC DOMAIN
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.

114
Makefile
View File

@@ -1,53 +1,76 @@
all: website favicon test
SHELL:=/bin/bash
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
SED=sed -r
NEWLINE=$\n
endif
ifeq ($(UNAME_S),Darwin)
SED=sed -E
NEWLINE=$$'\n'
endif
SERVER_TMP=${TMPDIR}shields-server-deploy
FRONTEND_TMP=${TMPDIR}shields-frontend-deploy
favicon:
node gh-badge.js '' '' '#bada55' .png > favicon.png
# This branch is reserved for the deploy process and should not be used for
# development. The deploy script will clobber it. To avoid accidentally
# pushing secrets to GitHub, this branch is configured to reject pushes.
WORKING_BRANCH=server-deploy-working-branch
all: website test
website:
cat try.html | $(SED) "s,(<img src=')(/[^'\?]+)',\1https://img.shields.io\2?maxAge=2592000'," \
| $(SED) "s,(<img src=')(/[^'\?]+\?[^']+)',\1https://img.shields.io\2\&maxAge=2592000'," \
| $(SED) "s,<span id='imgUrlPrefix'>,&https://img.shields.io," \
| $(SED) "s,var origin = '';,var origin = 'https://img.shields.io';," \
| $(SED) "s,<style>,<!-- WARNING: THIS FILE WAS GENERATED FROM try.html -->\\"$(NEWLINE)"<style>," > index.html
LONG_CACHE=false npm run build
deploy: deploy-s0 deploy-s1 deploy-gh-pages
deploy: deploy-s0 deploy-s1 deploy-s2 clean-server-deploy deploy-gh-pages deploy-gh-pages-clean
deploy-s0:
git add -f Verdana.ttf
git add -f secret.json
git commit -m'MUST NOT BE ON GITHUB'
git push -f s0 HEAD:master
git reset HEAD~1
git checkout master
deploy-s0: prepare-server-deploy push-s0
deploy-s1: prepare-server-deploy push-s1
deploy-s2: prepare-server-deploy push-s2
deploy-s1:
git add -f Verdana.ttf
git add -f secret.json
git commit -m'MUST NOT BE ON GITHUB'
git push -f s1 HEAD:master
git reset HEAD~1
git checkout master
prepare-server-deploy: website
# Ship a copy of the front end to each server for debugging.
# https://github.com/badges/shields/issues/1220
rm -rf ${SERVER_TMP}
git worktree prune
git worktree add -B ${WORKING_BRANCH} ${SERVER_TMP}
cp -r build ${SERVER_TMP}
git -C ${SERVER_TMP} add -f build/
git -C ${SERVER_TMP} commit --no-verify -m '[DEPLOY] Add frontend for debugging'
mkdir -p ${SERVER_TMP}/private
cp private/secret-production.json ${SERVER_TMP}/private/secret.json
git -C ${SERVER_TMP} add -f private/secret.json
git -C ${SERVER_TMP} commit --no-verify -m '[DEPLOY] MUST NOT BE ON GITHUB'
clean-server-deploy:
rm -rf ${SERVER_TMP}
git worktree prune
push-s0:
git push -f s0 ${WORKING_BRANCH}:master
push-s1:
git push -f s1 ${WORKING_BRANCH}:master
push-s2:
git push -f s2 ${WORKING_BRANCH}:master
deploy-gh-pages:
(git checkout -B gh-pages && \
git merge master && \
git push -f origin gh-pages:gh-pages) || git checkout master
git checkout master
rm -rf ${FRONTEND_TMP}
git worktree prune
LONG_CACHE=true \
BASE_URL=https://img.shields.io \
NEXT_ASSET_PREFIX=https://shields.io \
npm run build
git worktree add -B gh-pages ${FRONTEND_TMP}
git -C ${FRONTEND_TMP} ls-files | xargs git -C ${FRONTEND_TMP} rm
git -C ${FRONTEND_TMP} commit --no-verify -m '[DEPLOY] Completely clean the index'
cp -r build/* ${FRONTEND_TMP}
cp favicon.png ${FRONTEND_TMP}
echo shields.io > ${FRONTEND_TMP}/CNAME
touch ${FRONTEND_TMP}/.nojekyll
git -C ${FRONTEND_TMP} add .
git -C ${FRONTEND_TMP} commit --no-verify -m '[DEPLOY] Add built site'
git push -f origin gh-pages
deploy-gh-pages-clean:
rm -rf ${FRONTEND_TMP}
git worktree prune
deploy-heroku:
git add -f Verdana.ttf
git add -f secret.json
git commit -m'MUST NOT BE ON GITHUB'
git add -f private/secret.json build/
git commit --no-verify -m'MUST NOT BE ON GITHUB'
git push -f heroku HEAD:master
git reset HEAD~1
(git checkout -B gh-pages && \
@@ -55,18 +78,7 @@ deploy-heroku:
git push -f origin gh-pages:gh-pages) || git checkout master
git checkout master
setup:
curl http://download.redis.io/releases/redis-2.8.8.tar.gz >redis.tar.gz \
&& tar xf redis.tar.gz \
&& rm redis.tar.gz \
&& mv redis-2.8.8 redis \
&& cd redis \
&& make
redis:
./redis/src/redis-server
test:
npm test
.PHONY: all favicon website deploy deploy-s0 deploy-s1 deploy-gh-pages deploy-heroku setup redis test
.PHONY: all website deploy prepare-server-deploy clean-server-deploy deploy-s0 deploy-s1 deploy-s2 push-s0 push-s1 push-s2 deploy-gh-pages deploy-gh-pages-clean deploy-heroku setup redis test

1
Procfile Normal file
View File

@@ -0,0 +1 @@
web: node server

292
README.md
View File

@@ -1,96 +1,232 @@
<p align="center">
<img src="https://rawgit.com/badges/shields/master/logo.svg"
height="130">
<img src="https://rawgit.com/badges/shields/master/static/logo.svg"
height="130">
</p>
<p align="center">
<a href="https://www.gratipay.com/Shields/">
<img src="https://img.shields.io/gratipay/team/shields.svg"
alt="Gratipay">
</a>
<a href="https://npmjs.org/package/gh-badges">
<img src="https://img.shields.io/npm/v/gh-badges.svg"
alt="npm version">
</a>
<a href="https://travis-ci.org/badges/shields">
<img src="https://img.shields.io/travis/badges/shields.svg"
alt="build status">
</a>
<a href="#backers" alt="Backers on Open Collective">
<img src="https://opencollective.com/shields/backers/badge.svg" /></a>
<a href="#sponsors" alt="Sponsors on Open Collective">
<img src="https://opencollective.com/shields/sponsors/badge.svg" /></a>
<a href="https://circleci.com/gh/badges/shields/tree/master">
<img src="https://img.shields.io/circleci/project/github/badges/shields/master.svg"
alt="build status"></a>
<a href="https://circleci.com/gh/badges/daily-tests">
<img src="https://img.shields.io/circleci/project/github/badges/daily-tests.svg?label=daily%20tests"
alt="daily build status"></a>
<a href="https://coveralls.io/github/badges/shields">
<img src="https://img.shields.io/coveralls/github/badges/shields.svg"
alt="coverage"></a>
<a href="https://github.com/badges/shields/compare/gh-pages...master">
<img src="https://img.shields.io/github/commits-since/badges/shields/gh-pages.svg?label=commits%20to%20be%20deployed"
alt="commits to be deployed"></a>
<a href="https://lgtm.com/projects/g/badges/shields/alerts/">
<img src="https://img.shields.io/lgtm/alerts/g/badges/shields.svg?logo=lgtm&logoWidth=18"
alt="Total alerts"/></a>
<a href="https://discord.gg/HjJCwm5">
<img src="https://img.shields.io/discord/308323056592486420.svg?logo=discord"
alt="chat on Discord"></a>
<a href="https://twitter.com/intent/follow?screen_name=shields_io">
<img src="https://img.shields.io/twitter/follow/shields_io.svg?style=social&logo=twitter"
alt="follow on Twitter"></a>
</p>
<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>
* **[INSTALL](INSTALL.md)** installation instructions.
* **[CONTRIBUTING](CONTRIBUTING.md)** project contribution guidelines.
* **[SPECIFICATION](spec/SPECIFICATION.md)** spec for the visual design of Shields badges.
* **[LICENSE](LICENSE.md)** public domain dedication.
This is home to [Shields.io][shields.io], a service for concise, consistent,
and legible badges in SVG and raster format, which can easily be included in
GitHub readmes or any other web page. The service supports dozens of
continuous integration services, package registries, distributions, app
stores, social networks, code coverage services, and code analysis services.
Every month it serves over 470 million images.
Make your own badges [here][badges]! (Quick guide: `https://img.shields.io/badge/left-right-f39f37.svg`.)
This repo hosts:
[badges]: <http://shields.io/#your-badge>
* The [Shields.io][shields.io] frontend and server code
* An [NPM library for generating badges][gh-badges]
* [documentation][gh-badges-docs]
* [changelog][gh-badges-changelog]
* The [badge design specification][badge-spec]
## Solving the problem
Many GitHub repositories sport badges for things like:
<table>
<tr>
<td><a href="https://travis-ci.org/"><strong>Travis CI</strong></a><p><sup>(build status)</sup></p></td>
<td><img src="http://f.cl.ly/items/2H233M0I0T43313c3h0C/Screen%20Shot%202013-01-30%20at%202.45.30%20AM.png" alt="Travis CI badge"></td>
</tr>
<tr>
<td><a href="https://gemnasium.com/"><strong>Gemnasium</strong></a><p><sup>(dependency checks)</sup></p></td>
<td><img src="http://f.cl.ly/items/2j1D2R0q2C3s1x2y3k09/Screen%20Shot%202013-01-30%20at%202.46.10%20AM.png" alt="Gemnasium badge"></td>
</tr>
<tr>
<td><a href="http://codeclimate.com"><strong>Code Climate</strong></a><p><sup>(static analysis)</sup></p></td>
<td><img src="http://f.cl.ly/items/0H2O1A3q2b3j1D2i0M3j/Screen%20Shot%202013-01-30%20at%202.46.47%20AM.png" alt="Code Climate badge"></td>
</tr>
<tr>
<td><a href="http://rubygems.org"><strong>RubyGems</strong></a><p><sup>(released gem version)</sup></p></td>
<td><img src="http://f.cl.ly/items/443X21151h1V301s2s3a/Screen%20Shot%202013-01-30%20at%202.47.10%20AM.png" alt="RubyGems badge"></td>
</tr>
</table>
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.
[shields.io]: https://shields.io/
[gh-badges]: https://www.npmjs.com/package/gh-badges
[badge-spec]: https://github.com/badges/shields/tree/master/spec
[gh-badges-docs]: https://github.com/badges/shields/tree/master/gh-badges/README.md
[gh-badges-changelog]: https://github.com/badges/shields/tree/master/gh-badges/CHANGELOG.md
## The Shields solution
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.
![Badge design](spec/proportions.png)
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).
* code coverage percentage: ![coverage](https://img.shields.io/badge/coverage-80%25-yellowgreen.svg?maxAge=2592000)
* stable release version: ![version](https://img.shields.io/badge/version-1.2.3-blue.svg?maxAge=2592000)
* package manager release: ![gem](https://img.shields.io/badge/gem-2.2.0-blue.svg?maxAge=2592000)
* status of third-party dependencies: ![dependencies](https://img.shields.io/badge/dependencies-out%20of%20date-orange.svg?maxAge=2592000)
* static code analysis grade: ![codacy](https://img.shields.io/badge/codacy-B-green.svg?maxAge=2592000)
* [SemVer](https://semver.org/) version observance: ![semver](https://img.shields.io/badge/semver-2.0.0-blue.svg?maxAge=2592000)
* amount of [Liberapay](https://liberapay.com/) donations per week: ![receives](https://img.shields.io/badge/receives-2.00%20USD%2Fweek-yellow.svg?maxAge=2592000)
* Python package downloads: ![downloads](https://img.shields.io/badge/downloads-13k%2Fmonth-brightgreen.svg?maxAge=2592000)
* Chrome Web Store extension rating: ![rating](https://img.shields.io/badge/rating-★★★★☆-brightgreen.svg?maxAge=2592000)
* [Uptime Robot](https://uptimerobot.com) percentage: ![uptime](https://img.shields.io/badge/uptime-100%25-brightgreen.svg?maxAge=2592000)
## Examples
What kind of metadata can you convey using badges?
* test build status: `build | failing`
* code coverage percentage: `coverage | 80%`
* stable release version: `version | 1.2.3`
* package manager release: `gem | 1.2.3`
* status of third-party dependencies: `dependencies | out-of-date`
* static code analysis GPA: `code climate | 3.8`
* [SemVer](http://semver.org/) version observance: `semver | 2.0.0`
* amount of [Gratipay](http://gratipay.com) donations per week: `tips | $2/week`
[Make your own badges!][custom badges]
(Quick example: `https://img.shields.io/badge/left-right-f39f37.svg`)
## Services using the Shields standard
* [Badger](https://github.com/badges/badgerbadgerbadger)
* [badges2svg](https://github.com/bfontaine/badges2svg)
* [Codacy](https://www.codacy.com)
* [Code Climate](https://codeclimate.com/changelog/510d4fde56b102523a0004bf)
* [Coveralls](https://coveralls.io/)
* [Forkability](http://basicallydan.github.io/forkability/)
* [Gemnasium](http://support.gemnasium.com/forums/236528-general/suggestions/5518400-use-svg-for-badges-so-they-still-look-sharp-on-r)
* [GoDoc](https://godoc.org/)
* [PHPPackages](https://phppackages.org)
* [Read the Docs](https://readthedocs.org/)
* [reposs](https://github.com/rexfinn/reposs)
* [ruby-gem-downloads-badge](https://github.com/bogdanRada/ruby-gem-downloads-badge/)
* [Scrutinizer](https://scrutinizer-ci.com/)
* [Semaphore](https://semaphoreapp.com)
* [Travis CI](https://github.com/travis-ci/travis-ci/issues/630#issuecomment-38054967)
* [Version Badge](http://badge.fury.io/)
* [VersionEye](https://www.versioneye.com/)
Browse a [complete list of badges][shields.io].
# Legal
[custom badges]: http://shields.io/#your-badge
All assets and code are under the [CC0 LICENSE](LICENSE.md) and in the public
Contributing
------------
Shields is a community project. We invite your participation through issues
and pull requests! You can peruse the [contributing guidelines][contributing].
When adding or changing a service [please add tests][service-tests].
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:
[![GitHub issues by-label](https://img.shields.io/github/issues/badges/shields/good%20first%20issue.svg)](https://github.com/badges/shields/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
You can read a [tutorial on how to add a badge][tutorial].
[service-tests]: https://github.com/badges/shields/blob/master/doc/service-tests.md
[tutorial]: doc/TUTORIAL.md
[contributing]: CONTRIBUTING.md
Development
-----------
1. Install Node 8 or later. You can use the [package manager][] of your choice.
Tests need to pass in Node 8 and 9.
2. Clone this repository.
3. Run `npm install` to install the dependencies.
4. Run `npm run build` to build the frontend.
5. Run `npm start` to start the server.
6. Open `http://[::]:8080/` to view the home page.
To generate the frontend using production cache settings &ndash; that is,
badge preview URIs with `maxAge` &ndash; run `LONG_CACHE=true npm run build`.
To analyze the frontend bundle, run `npm install webpack-bundle-analyzer` and
then `ANALYZE=true npm start`.
[Snapshot tests][] ensure we don't inadvertently make changes that affect the
SVG or JSON output. When deliberately changing the output, run
`SNAPSHOT_DRY=1 npm run test:js:server` to preview changes to the saved
snapshots, and `SNAPSHOT_UPDATE=1 npm run test:js:server` to update them.
The server can be configured to use [Sentry][] ([configuration][sentry configuration]) and [Prometheus][] ([configuration][prometheus configuration]).
Daily tests, including a full run of the service tests and overall code coverage, are run via [badges/daily-tests][daily-tests].
[package manager]: https://nodejs.org/en/download/package-manager/
[snapshot tests]: https://glebbahmutov.com/blog/snapshot-testing/
[Prometheus]: https://prometheus.io/
[prometheus configuration]: doc/self-hosting.md#prometheus
[Sentry]: https://sentry.io/
[sentry configuration]: doc/self-hosting.md#sentry
[daily-tests]: https://github.com/badges/daily-tests
Hosting your own server
-----------------------
There is documentation about [hosting your own server][self-hosting].
[self-hosting]: doc/self-hosting.md
History
-------
b.adge.me was the original website for this service. Heroku back then had a
thing which made it hard to use a toplevel domain with it, hence the odd
domain. It used code developed in 2013 from a library called
[gh-badges][old-gh-badges], both developed by [Thaddée Tyl][espadrine].
The project merged with shields.io by making it use the b.adge.me code
and closed b.adge.me.
The original badge specification was developed in 2013 by
[Olivier Lacan][olivierlacan]. It was inspired by the Travis CI and similar
badges (there were a lot fewer, back then). In 2014 Thaddée Tyl redesigned
it with help from a Travis CI employee and convinced everyone to switch to
it. The old design is what today is called the plastic style; the new one
is the flat style.
You can read more about [the project's inception][thread],
[the motivation of the SVG badge specification][motivation], and
[the specification itself][spec].
[olivierlacan]: https://github.com/olivierlacan
[espadrine]: https://github.com/espadrine
[old-gh-badges]: https://github.com/badges/gh-badges
[motivation]: spec/motivation.md
[spec]: spec/SPECIFICATION.md
[thread]: https://github.com/h5bp/lazyweb-requests/issues/150
Project leaders
---------------
[espadrine](https://github.com/espadrine) is the sysadmin.
These contributors donate time on a consistent basis to help guide and
maintain the project:
* [chris48s](https://github.com/chris48s)
* [Daniel15](https://github.com/Daniel15)
* [espadrine](https://github.com/espadrine)
* [paulmelnikow](https://github.com/paulmelnikow)
* [platan](https://github.com/platan)
* [PyvesB](https://github.com/PyvesB)
* [RedSparr0w](https://github.com/RedSparr0w)
Related projects
----------------
- [badgerbadgerbadger gem][gem]
- [pybadges python library][pybadges]
[gem]: https://github.com/badges/badgerbadgerbadger
[pybadges]: https://github.com/google/pybadges
License
-------
All assets and code are under the [CC0 LICENSE](LICENSE) and in the public
domain unless specified otherwise.
The assets in `logo/` are trademarks of their respective companies and are under
their terms and license.
The assets in `logo/` are trademarks of their respective companies and are
under their terms and license.
## Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/badges/shields/graphs/contributors"><img src="https://opencollective.com/shields/contributors.svg?width=890" /></a>
## Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/shields#backer)]
<a href="https://opencollective.com/shields#backers" target="_blank"><img src="https://opencollective.com/shields/backers.svg?width=890"></a>
## Sponsors
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)]
<a href="https://opencollective.com/shields/sponsor/0/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/shields/sponsor/1/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/shields/sponsor/2/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/shields/sponsor/3/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/shields/sponsor/4/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/shields/sponsor/5/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/shields/sponsor/6/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/shields/sponsor/7/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/shields/sponsor/8/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/shields/sponsor/9/website" target="_blank"><img src="https://opencollective.com/shields/sponsor/9/avatar.svg"></a>

View File

@@ -0,0 +1,26 @@
exports['The badge generator SVG should always produce the same SVG (unless we have changed something!) 1'] = `
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="90" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h45v20H0z"/><path fill="#4c1" d="M45 0h45v20H45z"/><path fill="url(#b)" d="M0 0h90v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="235" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="350">cactus</text><text x="235" y="140" transform="scale(.1)" textLength="350">cactus</text><text x="665" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="350">grown</text><text x="665" y="140" transform="scale(.1)" textLength="350">grown</text></g> </svg>
`
exports['The badge generator JSON should always produce the same JSON (unless we have changed something!) 1'] = `
{
"name": "cactus",
"value": "grown"
}
`
exports['The badge generator badges with logos should always produce the same badge shields GitHub logo default color (#333333) 1'] = `
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="github"/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg>
`
exports['The badge generator badges with logos should always produce the same badge shields GitHub logo custom color (whitesmoke) 1'] = `
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="github"/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg>
`
exports['The badge generator badges with logos should always produce the same badge simple-icons javascript logo default color (#F7DF1E) 1'] = `
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="javascript"/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg>
`
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'] = `
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="javascript"/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg>
`

25
app.json Normal file
View File

@@ -0,0 +1,25 @@
{
"name": "Shields",
"description": "Concise, consistent, and legible badges in SVG and raster format.",
"keywords": [
"badge",
"github",
"svg",
"status"
],
"website": "https://shields.io/",
"repository": "https://github.com/badges/shields",
"logo": "http://shields.io/favicon.png",
"env": {
"NPM_CONFIG_PRODUCTION": {
"description": "Configure whether devDependencies are installed (they are needed for the build).",
"value": "false"
}
},
"formation": {
"web": {
"quantity": 1,
"size": "free"
}
}
}

102
badge.js
View File

@@ -1,102 +0,0 @@
var fs = require('fs');
var path = require('path');
var SVGO = require('svgo');
var dot = require('dot');
var measureTextWidth = require('./measure-text');
// cache templates.
var templates = {};
var templateFiles = fs.readdirSync(path.join(__dirname, 'templates'));
dot.templateSettings.strip = false; // Do not strip whitespace.
templateFiles.forEach(function(filename) {
if (filename[0] === '.') { return; }
var templateData = fs.readFileSync(
path.join(__dirname, 'templates', filename)).toString();
var extension = filename.split('.').pop();
var style = filename.slice(0, -(('-template.' + extension).length));
templates[style + '-' + extension] = dot.template(templateData);
});
function escapeXml(s) {
return s.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
function capitalize(s) {
return s[0].toUpperCase() + s.slice(1);
}
function addEscapers(data) {
data.escapeXml = escapeXml;
data.capitalize = capitalize;
}
var colorscheme = require(path.join(__dirname, 'colorscheme.json'));
function optimize(string, callback) {
var svgo = new SVGO();
svgo.optimize(string, callback);
}
function makeImage(data, cb) {
if (data.format !== 'json') {
data.format = 'svg';
}
if (!(data.template + '-' + data.format in templates)) {
data.template = 'default';
}
if (data.colorscheme) {
var pickedColorscheme = colorscheme[data.colorscheme];
if (!pickedColorscheme) {
pickedColorscheme = colorscheme.red;
}
data.colorA = pickedColorscheme.colorA;
data.colorB = pickedColorscheme.colorB;
}
// Logo.
data.logoWidth = +data.logoWidth || (data.logo? 14: 0);
data.logoPadding = (data.logo? 3: 0);
// String coercion.
data.text[0] = '' + data.text[0];
data.text[1] = '' + data.text[1];
if (data.text[0].length === 0) {
data.logoPadding = 0;
}
var textWidth1 = (measureTextWidth(data.text[0])|0);
var textWidth2 = (measureTextWidth(data.text[1])|0);
// Increase chances of pixel grid alignment.
if (textWidth1 % 2 === 0) { textWidth1++; }
if (textWidth2 % 2 === 0) { textWidth2++; }
data.widths = [
textWidth1 + 10 + data.logoWidth + data.logoPadding,
textWidth2 + 10,
];
if (data.links === undefined) {
data.links = ['', ''];
} else {
for (var i = 0; i < data.links.length; i++) {
data.links[i] = escapeXml(data.links[i]);
}
}
var template = templates[data.template + '-' + data.format];
addEscapers(data);
try {
var result = template(data);
} catch(e) {
cb('', e);
return;
}
if (data.format === 'json') {
cb(result);
} else {
// Run the SVG through SVGO.
optimize(result, function(object) { cb(object.data); });
}
}
module.exports = makeImage;
module.exports.loadFont = measureTextWidth.loadFont;

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="110" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><mask id="a"><rect width="110" height="20" rx="3" fill="#fff"/></mask><g mask="url(#a)"><path fill="#555" d="M0 0h63v20H0z"/><path fill="#dfb317" d="M63 0h47v20H63z"/><path fill="url(#b)" d="M0 0h110v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text><text x="31.5" y="14">coverage</text><text x="85.5" y="15" fill="#010101" fill-opacity=".3">76.8%</text><text x="85.5" y="14">76.8%</text></g></svg>

Before

Width:  |  Height:  |  Size: 744 B

170
dangerfile.js Normal file
View File

@@ -0,0 +1,170 @@
'use strict'
// Have you identified a contributing guideline that should be included here?
// Please open a pull request!
//
// To test changes to this file, pick a PR to test against, then run
// `./node_modules/.bin/danger pr pr-url`
// Note that the line numbers in the runtime errors are incorrecr.
const { danger, fail, message, warn } = require('danger')
const chainsmoker = require('chainsmoker')
const { default: noTestShortcuts } = require('danger-plugin-no-test-shortcuts')
const fileMatch = chainsmoker({
created: danger.git.created_files,
modified: danger.git.modified_files,
createdOrModified: danger.git.modified_files.concat(danger.git.created_files),
deleted: danger.git.deleted_files,
})
const documentation = fileMatch(
'**/*.md',
'lib/all-badge-examples.js',
'frontend/components/usage.js'
)
const server = fileMatch('server.js')
const serviceTests = fileMatch('services/**/*.tester.js')
const helpers = fileMatch(
'lib/**/*.js',
'!**/*.spec.js',
'!lib/all-badge-examples.js'
)
const logos = fileMatch('logo/*.svg')
const helperTests = fileMatch('lib/**/*.spec.js')
const packageJson = fileMatch('package.json')
const packageLock = fileMatch('package-lock.json')
const capitals = fileMatch('**/*[A-Z]*.js')
const underscores = fileMatch('**/*_*.js')
const targetBranch = danger.github.pr.base.ref
message(
[
':sparkles: Thanks for your contribution to Shields, ',
`@${danger.github.pr.user.login}!`,
].join('')
)
if (targetBranch !== 'master') {
const message = `This PR targets \`${targetBranch}\``
const idea = 'It is likely that the target branch should be `master`'
warn(`${message} - <i>${idea}</i>`)
}
if (documentation.createdOrModified) {
message(
[
'Thanks for contributing to our documentation. ',
'We :heart: our [documentarians](http://www.writethedocs.org/)!',
].join('')
)
}
if (packageJson.modified && !packageLock.modified) {
const message = 'This PR modified `package.json`, but not `package-lock.json`'
const idea = 'Perhaps you need to run `npm install`?'
warn(`${message} - <i>${idea}</i>`)
}
if (server.modified && !serviceTests.createdOrModified) {
warn(
[
'This PR modified the server but none of the service tests. <br>',
"That's okay so long as it's refactoring existing code. ",
'Otherwise, please consider adding tests to the service: ',
'[How-to](https://github.com/badges/shields/blob/master/doc/service-tests.md#readme)',
].join('')
)
}
if (helpers.created && !helperTests.created) {
warn(
[
'This PR added helper modules in `lib/` but not accompanying tests. <br>',
'Generally helper modules should have their own tests.',
].join('')
)
} else if (helpers.createdOrModified && !helperTests.createdOrModified) {
warn(
[
'This PR modified helper functions in `lib/` but not accompanying tests. <br>',
"That's okay so long as it's refactoring existing code.",
].join('')
)
}
if (logos.created) {
message(
[
':art: Thanks for submitting a logo. <br>',
'Please ensure your contribution follows our ',
'[guidance](https://github.com/badges/shields/blob/master/CONTRIBUTING.md#logos) ',
'for logo submissions.',
].join('')
)
}
if (capitals.created || underscores.created) {
fail(
[
'JavaScript source files should be named with `kebab-case` ',
'(dash-separated lowercase).',
].join('')
)
}
const allFiles = danger.git.created_files.concat(danger.git.modified_files)
allFiles.forEach(file => {
// eslint-disable-next-line promise/prefer-await-to-then
danger.git.diffForFile(file).then(diff => {
if (/\+.*assert[(.]/.test(diff.diff)) {
warn(
[
`Found 'assert' statement added in \`${file}\`. <br>`,
'Please ensure tests are written using Chai ',
'[expect syntax](http://chaijs.com/guide/styles/#expect)',
].join('')
)
}
})
})
function onlyUnique(value, index, self) {
return self.indexOf(value) === index
}
const affectedServices = allFiles
.map(file => {
const match = file.match(/^services\/(.+)\/.+\.service.js$/)
return match ? match[1] : undefined
})
.filter(Boolean)
.filter(onlyUnique)
const testedServices = allFiles
.map(file => {
const match = file.match(/^services\/(.+)\/.+\.tester.js$/)
return match ? match[1] : undefined
})
.filter(Boolean)
.filter(onlyUnique)
affectedServices.forEach(service => {
if (testedServices.indexOf(service) === -1) {
warn(
[
`This PR modified service code for <kbd>${service}</kbd> but not its test code. <br>`,
"That's okay so long as it's refactoring existing code.",
].join('')
)
}
})
// Prevent merging exclusive services tests.
noTestShortcuts({
testFilePredicate: filePath => filePath.endsWith('.tester.js'),
patterns: {
only: ['only()'],
},
})

309
doc/TUTORIAL.md Normal file
View File

@@ -0,0 +1,309 @@
Tutorial on how to add a badge for a service
============================================
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.
2. Clone the fork
`git clone git@github.com:YOURGITHUBUSERNAME/shields.git`
3. `cd shields`
4. Install npm and other required packages (Ubuntu 16.10)
`sudo apt-get install npm nodejs-legacy curl imagemagick`
5. Install all packages
`npm install`
6. Run the server
`npm start`
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.
Example: [wercker](https://github.com/badges/shields/tree/master/services/wercker)
* For service families with multiple badges we usually store the code for each
badge in its own file like this:
* `/services/SERVICENAME/SERVICENAME-downloads.service.js`
* `/services/SERVICENAME/SERVICENAME-version.service.js` etc.
Example: [ruby gems](https://github.com/badges/shields/tree/master/services/gem)
* In files ending with `.tester.js`, you can find the code which uses
the shields server to test if the badges are generated correctly.
There is a [chapter on Tests][write tests].
### (4.2) Our First Badge
All service badge classes inherit from [BaseService] or another class which extends it.
Other classes implement useful behavior on top of [BaseService].
* [BaseJsonService](https://github.com/badges/shields/blob/master/services/base-json.js)
implements methods for performing requests to a JSON API and schema validation.
* [BaseXmlService](https://github.com/badges/shields/blob/master/services/base-xml.js)
implements methods for performing requests to an XML API and schema validation.
* If you are contributing to a *service family*, you may define a common super
class for the badges or one may already exist.
[BaseService]: https://github.com/badges/shields/blob/master/services/base.js
As a first step we will look at the code for an example which generates a badge without contacting an API.
```js
'use strict' // (1)
const BaseService = require('../base') // (2)
module.exports = class Example extends BaseService { // (3)
static get route() { // (4)
return {
base: 'example',
pattern: ':text',
}
}
async handle({ text }) { // (5)
return {
label: 'example',
message: text,
color: 'blue',
}
}
}
```
Description of the code:
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: ![](https://img.shields.io/badge/example-foo-blue.svg)
[path-to-regexp]: https://github.com/pillarjs/path-to-regexp#parameters
### (4.3) Querying an API
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:
```js
'use strict' // (1)
const BaseJsonService = require('../base-json') // (2)
const { renderVersionBadge } = require('../../lib/version') // (3)
const Joi = require('joi') // (4)
const schema = Joi.object({ // (4)
version: Joi.string().required(), // (4)
}).required() // (4)
module.exports = class GemVersion extends BaseJsonService { // (5)
static get route() { // (6)
return {
base: 'gem/v',
pattern: ':gem',
}
}
static get defaultBadgeData() { // (7)
return { label: 'gem' }
}
async handle({ gem }) { // (8)
const { version } = await this.fetch({ gem })
return this.constructor.render({ version })
}
async fetch({ gem }) { // (9)
return this._requestJson({
schema,
url: `https://rubygems.org/api/v1/gems/${gem}.json`,
})
}
static render({ version }) { // (10)
return renderVersionBadge({ version })
}
}
```
Description of the code:
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:
* [color-formatters.js](https://github.com/badges/shields/blob/master/lib/color-formatters.js)
* [licenses.js](https://github.com/badges/shields/blob/master/lib/licenses.js)
* [text-formatters.js](https://github.com/badges/shields/blob/master/lib/text-formatters.js)
* [version.js](https://github.com/badges/shields/blob/master/lib/version.js)
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: ![](https://img.shields.io/gem/v/formatador.svg)
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 ![](https://img.shields.io/gem/v/does-not-exist.svg) 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.
* One of the
[maintainers](https://github.com/badges/shields/blob/master/README.md#project-leaders)
will review your contribution.
* 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.

38
doc/production-hosting.md Normal file
View File

@@ -0,0 +1,38 @@
Production hosting
==================
Server secrets
--------------
Some services require the use of secret tokens or passwords. Those are stored
in `private/secret.json` which is not checked into the repository.
These settings are currently set on the production server:
- bintray_apikey
- bintray_user
- gh_client_id
- gh_client_secret
- gh_token
- gitter_dev_secret
- shieldsIps
- shieldsSecret
- sl_insight_apiToken
- sl_insight_userUuid
(Gathered from `cat private/secret.json | jq keys | grep -o '".*"' | sed 's/"//g'`.)
The `secret.tpl.json` is a template file used by the Docker container to set the secrets based on
environment variables.
Main Server Sysadmin
--------------------
- Servers in DNS round-robin:
- s0: 192.99.59.72 (vps71670.vps.ovh.ca)
- s1: 51.254.114.150 (vps244529.ovh.net)
- s2: 149.56.96.133 (vps117870.vps.ovh.ca)
- Self-signed TLS certificates, but `img.shields.io` is behind CloudFlare, which provides signed certificates.
- Using systemd to automatically restart the server when it crashes.
See https://github.com/badges/ServerScript for helper admin scripts.

214
doc/self-hosting.md Normal file
View File

@@ -0,0 +1,214 @@
Hosting your own Shields server
===============================
Installation
------------
You will need Node 8 or later, which you can install using a
[package manager][].
On Ubuntu / Debian:
```sh
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -; sudo apt-get install -y nodejs
```
```sh
git clone https://github.com/badges/shields.git
cd shields
npm install # You may need sudo for this.
```
[package manager]: https://nodejs.org/en/download/package-manager/
Build the frontend
------------------
```sh
LONG_CACHE=true npm run build
```
Start the server
----------------
```sh
sudo node server
```
The server uses port 80 by default, which requires `sudo` permissions.
There are two ways to provide an alternate port:
```sh
PORT=8080 node server
node server 8080
```
The root gets redirected to https://shields.io.
For testing purposes, you can go to `http://localhost/`.
Heroku
------
Once you have installed the [Heroku Toolbelt][]:
```bash
heroku login
heroku create your-app-name
heroku config:set BUILDPACK_URL=https://github.com/mojodna/heroku-buildpack-multi.git#build-env
make deploy
heroku open
```
[Heroku Toolbelt]: https://toolbelt.heroku.com/
Docker
------
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
Successfully built 4471b442c220
```
Optionally, create a file called `shields.env` that contains the needed
configuration. See [shields.example.env][shields.example.env] for an example.
Then run the container:
```console
$ docker run --rm -p 8080:80 --name shields shields
# or if you have shields.env file, run the following instead
$ docker run --rm -p 8080:80 --env-file shields.env --name shields shields
> gh-badges@1.1.2 start /usr/src/app
> node server.js
http://[::1]/
```
Assuming Docker is running locally, you should be able to get to the
application at http://localhost:8080/.
If you run Docker in a virtual machine (such as boot2docker or Docker Machine)
then you will need to replace `localhost` with the IP address of that virtual
machine.
[shields.example.env]: ../shields.example.env
Zeit Now
--------
To deploy using Zeit Now:
```console
npm run build # Not sure why, but this needs to be run before deploying.
now
```
## Persistence
To enable Redis-backed GitHub token persistence, point `REDIS_URL` to your
Redis installation.
Server secrets
--------------
You can add your own server secrets in `private/secret.json`.
Because of Github rate limits, you will need to provide a token, or else badges
will stop working once you hit 60 requests per hour, the
[unauthenticated rate limit][github rate limit].
You can [create a personal access token][personal access tokens] through the
Github website. When you create the token, you can choose to give read access
to your repositories. If you do that, your self-hosted Shields installation
will have access to your private repositories.
```
{
"gh_token": "..."
}
```
When a `gh_token` is specified, it is used in place of the Shields token
rotation logic.
You can also give your self-hosted Shields installation access to private npm
packages by [generating an npm token] and using that for the `npm_token` value.
[github rate limit]: https://developer.github.com/v3/#rate-limiting
[personal access tokens]: https://github.com/settings/tokens
[generating an npm token]: https://docs.npmjs.com/getting-started/working_with_tokens
Separate frontend hosting
-------------------------
If you want to host the frontend on a separate server, such as cloud storage
or a CDN, you can do that.
First, build the frontend, pointing `BASE_URL` to your server.
```sh
LONG_CACHE=true BASE_URL=https://your-server.example.com npm run build
```
Then copy the contents of the `build/` folder to your static hosting / CDN.
There are also a couple settings you should configure on the server.
If you want to use server suggestions, you should also set `ALLOWED_ORIGIN`:
```sh
ALLOWED_ORIGIN=http://my-custom-shields.s3.amazonaws.com,https://my-custom-shields.s3.amazonaws.com
```
This should be a comma-separated list of allowed origin headers. They should
not have paths or trailing slashes.
To help out users, you can make the Shields server redirect the server root.
Set the `REDIRECT_URI` environment variable:
```sh
REDIRECT_URI=http://my-custom-shields.s3.amazonaws.com/
```
Sentry
------
In order to enable integration with [Sentry](https://sentry.io), you need your own [Sentry DSN](https://docs.sentry.io/quickstart/#configure-the-dsn). Its 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.
```bash
METRICS_PROMETHEUS_ENABLED=true METRICS_PROMETHEUS_ALLOWED_IPS="^127\.0\.0\.1$" npm start
```
Metrics are available at `/metrics` resource.

312
doc/service-tests.md Normal file
View File

@@ -0,0 +1,312 @@
Service tests
=============
When creating a badge for a new service or changing a badge's behavior,
automated tests should be included. They serve three purposes:
1. The contributor and reviewer can easily verify the code works as
intended.
2. When a badge stops working due to an upstream API, maintainers can find out
right away.
3. They speed up future contributors when they are debugging or improving a
badge.
Test should cover:
1. Valid behavior
2. Optional parameters like tags or branches
3. Any customized error handling
4. If a non-trivial validator is defined, include tests for malformed responses
Tutorial
--------
Before getting started, set up a development environment by following the
[setup instructions](https://github.com/badges/shields/blob/master/doc/TUTORIAL.md#2-setup)
We will write some tests for the [Wercker Build service](https://github.com/badges/shields/blob/master/services/wercker/wercker.service.js)
### (1) Boilerplate
The code for our badge is in `services/wercker/wercker.service.js`. Tests for this badge should be stored in `services/wercker/wercker.tester.js`.
We'll start by adding some boilerplate to our file:
```js
'use strict'
const Joi = require('joi') // 1
const createServiceTester = require('../create-service-tester') // 2
const t = createServiceTester() // 2
module.exports = t // 3
```
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`.
3. `t` is exported from the module.
### (2) Our First Test Case
First we'll add a test for the typical case:
```js
const { isBuildStatus } = require('../test-validators')
t.create('Build status') // 1
.get('/build/wercker/go-wercker-api.json') // 2
.expectJSONTypes( // 3
Joi.object().keys({ // 4
name: 'build', // 5
value: isBuildStatus, // 6
})
)
```
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 ![](https://img.shields.io/wercker/build/wercker/go-wercker-api.svg) 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
harness will call it for you.
[IcedFrisby]: https://github.com/MarkHerhold/IcedFrisby
[longer example]: https://github.com/MarkHerhold/IcedFrisby/#show-me-some-code
[IcedFrisby API]: https://github.com/MarkHerhold/IcedFrisby/blob/master/API.md
[Joi]: https://github.com/hapijs/joi
[Joi API]: https://github.com/hapijs/joi/blob/master/API.md
### (3) Running the Tests
Lets run the test we have written:
```
npm run test:services -- --only=wercker
```
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:
```js
t.create('Build status (application not found)')
.get('/build/some-project/that-doesnt-exist.json')
.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:
```js
t.create('Build status (private application)')
.get('/build/wercker/go-wercker-api.json')
.intercept(nock => nock('https://app.wercker.com/api/v3/applications/')
.get('/wercker/go-wercker-api/builds?limit=1')
.reply(401)
)
.expectJSON({ name: 'build', value: 'private application not supported' })
```
This will intercept the request and provide our own mock response.
We use the `intercept()` method provided by the
[icedfrisby-nock plugin][icedfrisby-nock]. It takes a setup function,
which returns an interceptor, and exposes the full API of the HTTP mocking
library [Nock][].
Nock is fussy. All parts of a request must match perfectly for the mock to
take effect, including the HTTP method (in this case GET), scheme (https), host,
and path.
[icedfrisby-nock]: https://github.com/paulmelnikow/icedfrisby-nock#usage
[Nock]: https://github.com/node-nock/nock
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
static render({ 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.
```js
const { colorScheme } = require('../test-helpers')
t.create('Build passed (mocked)')
.get('/build/wercker/go-wercker-api.json?style=_shields_test')
.intercept(nock =>
nock('https://app.wercker.com/api/v3/applications/')
.get('/wercker/go-wercker-api/builds?limit=1')
.reply(200, [{ status: 'finished', result: 'passed' }])
)
.expectJSON({ name: 'build', value: 'passing', colorB: colorScheme.brightgreen })
t.create('Build failed (mocked)')
.get('/build/wercker/go-wercker-api.json?style=_shields_test')
.intercept(nock =>
nock('https://app.wercker.com/api/v3/applications/')
.get('/wercker/go-wercker-api/builds?limit=1')
.reply(200, [{ status: 'finished', result: 'failed' }])
)
.expectJSON({ name: 'build', value: 'failed', colorB: colorScheme.red })
```
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
```js
.expectJSON({ name: 'build', value: 'failed', colorB: colorScheme.red })
```
instead of
```js
.expectJSON({ name: 'build', value: 'passing', colorB: '#e05d44' })
```
Code coverage
-------------
By checking code coverage, we can make sure we've covered all our bases.
We can generate a coverage report and open it:
```
npm run coverage:test:services -- --only=wercker
npm run coverage:report:open
```
Pull requests
-------------
The affected service ids should be included in brackets in the pull request
title. That way, Travis will run those service tests. When a pull request
affects multiple services, they should be separated with spaces. The test
runner is case-insensitive, so they should be capitalized for readability.
For example:
- [Travis] Fix timeout issues
- [Travis Sonar] Support user token authentication
- Add tests for [CRAN] and [CPAN]
Getting help
------------
If you have questions about how to write your tests, please open an issue. If
there's already an issue open for the badge you're working on, you can post a
comment there instead.
Further reading
---------------
- [IcedFrisby API][]
- [Joi API][]
- [icedfrisby-nock][]
- [Nock API](https://github.com/node-nock/nock#use)

50
doc/users.md Normal file
View File

@@ -0,0 +1,50 @@
# Notable Projects Using Shields
- https://github.com/AFNetworking/AFNetworking
- https://github.com/angular/angular.js
- https://github.com/ansible/ansible
- https://github.com/apple/swift
- https://github.com/atom/atom
- https://github.com/babel/babel
- https://github.com/bevacqua/dragula
- https://github.com/bower/bower
- https://github.com/chartjs/Chart.js
- https://github.com/creationix/nvm
- https://github.com/discourse/discourse
- https://github.com/docker/docker
- https://github.com/electron/electron
- https://github.com/elm-lang/core
- https://github.com/emberjs/ember.js
- https://github.com/expressjs/express
- https://github.com/facebook/react
- https://github.com/FortAwesome/Font-Awesome
- https://github.com/gitlabhq/gitlabhq
- https://github.com/gulpjs/gulp
- https://github.com/h5bp/html5-boilerplate
- https://github.com/jakubroztocil/httpie
- https://github.com/jekyll/jekyll
- https://github.com/kennethreitz/requests
- https://github.com/kubernetes/kubernetes
- https://github.com/laravel/laravel
- https://github.com/less/less.js
- https://github.com/Microsoft/TypeScript
- https://github.com/Microsoft/vscode
- https://github.com/mitchellh/vagrant
- https://github.com/Modernizr/Modernizr
- https://github.com/moment/moment
- https://github.com/mrdoob/three.js
- https://github.com/necolas/normalize.css
- https://github.com/nodejs/node
- https://github.com/plataformatec/devise
- https://github.com/postcss/postcss
- https://github.com/rails/rails
- https://github.com/reactjs/redux
- https://github.com/socketio/socket.io
- https://github.com/tensorflow/tensorflow
- https://github.com/TryGhost/Ghost
- https://github.com/twbs/bootstrap
- https://github.com/videojs/video.js
- https://github.com/vuejs/vue
- https://github.com/webpack/webpack
- https://github.com/yarnpkg/yarn
- https://github.com/zurb/foundation-sites

1
frontend/.eslintrc.yml Normal file
View File

@@ -0,0 +1 @@
extends: '../.eslintrc-frontend.yml'

View File

@@ -0,0 +1,149 @@
import React from 'react'
import { Link } from 'react-router-dom'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import resolveBadgeUrl from '../lib/badge-url'
const Badge = ({
title,
exampleUrl,
previewUrl,
urlPattern,
documentation,
baseUrl,
longCache,
shouldDisplay = () => true,
onClick,
}) => {
const handleClick = onClick
? () =>
onClick({
title,
exampleUrl,
previewUrl,
urlPattern,
documentation,
})
: undefined
const previewImage = previewUrl ? (
<img
className={classNames('badge-img', { clickable: onClick })}
onClick={handleClick}
src={resolveBadgeUrl(previewUrl, baseUrl, { longCache })}
alt=""
/>
) : (
'\u00a0'
) // non-breaking space
const resolvedExampleUrl = resolveBadgeUrl(
urlPattern || previewUrl,
baseUrl,
{ longCache: false }
)
if (shouldDisplay()) {
return (
<tr>
<th
className={classNames({ clickable: onClick })}
onClick={handleClick}
>
{title}:
</th>
<td>{previewImage}</td>
<td>
<code
className={classNames({ clickable: onClick })}
onClick={handleClick}
>
{resolvedExampleUrl}
</code>
</td>
</tr>
)
}
return null
}
Badge.propTypes = {
title: PropTypes.string.isRequired,
exampleUrl: PropTypes.string,
previewUrl: PropTypes.string,
urlPattern: PropTypes.string,
documentation: PropTypes.string,
baseUrl: PropTypes.string,
longCache: PropTypes.bool.isRequired,
shouldDisplay: PropTypes.func,
onClick: PropTypes.func.isRequired,
}
const Category = ({ category, examples, baseUrl, longCache, onClick }) => {
if (examples.filter(example => example.shouldDisplay()).length === 0) {
return null
}
return (
<div>
<Link to={`/examples/${category.id}`}>
<h3 id={category.id}>{category.name}</h3>
</Link>
<table className="badge">
<tbody>
{examples.map(badgeData => (
<Badge
key={badgeData.key}
{...badgeData}
baseUrl={baseUrl}
longCache={longCache}
onClick={onClick}
/>
))}
</tbody>
</table>
</div>
)
}
Category.propTypes = {
category: PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
}).isRequired,
examples: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string.isRequired,
exampleUrl: PropTypes.string,
previewUrl: PropTypes.string,
urlPattern: PropTypes.string,
documentation: PropTypes.string,
})
).isRequired,
baseUrl: PropTypes.string,
longCache: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
}
const BadgeExamples = ({ categories, baseUrl, longCache, onClick }) => (
<div>
{categories.map((categoryData, i) => (
<Category
key={i}
{...categoryData}
baseUrl={baseUrl}
longCache={longCache}
onClick={onClick}
/>
))}
</div>
)
BadgeExamples.propTypes = {
categories: PropTypes.arrayOf(
PropTypes.shape({
category: Category.propTypes.category,
examples: Category.propTypes.examples,
})
),
baseUrl: PropTypes.string,
longCache: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
}
export { Badge, BadgeExamples }

View File

@@ -0,0 +1,102 @@
import React from 'react'
import PropTypes from 'prop-types'
import { dynamicBadgeUrl } from '../lib/badge-url'
export default class DynamicBadgeMaker extends React.Component {
static propTypes = {
baseUrl: PropTypes.string,
}
state = {
datatype: '',
label: '',
url: '',
query: '',
color: '',
prefix: '',
suffix: '',
}
makeBadgeUrl() {
const { datatype, label, url, query, color, prefix, suffix } = this.state
const { baseUrl: baseUrl = document.location.href } = this.props
return dynamicBadgeUrl(baseUrl, datatype, label, url, query, {
color,
prefix,
suffix,
})
}
handleSubmit(e) {
e.preventDefault()
document.location = this.makeBadgeUrl()
}
get isValid() {
const { datatype, label, url, query } = this.state
return datatype && label && url && query
}
render() {
return (
<form onSubmit={e => this.handleSubmit(e)}>
<select
className="short"
value={this.state.datatype}
onChange={event => this.setState({ datatype: event.target.value })}
>
<option value="" disabled>
data type
</option>
<option value="json">json</option>
<option value="xml">xml</option>
<option value="yaml">yaml</option>
</select>{' '}
{}
<input
className="short"
value={this.state.label}
onChange={event => this.setState({ label: event.target.value })}
placeholder="label"
/>{' '}
{}
<input
className="short"
value={this.state.url}
onChange={event => this.setState({ url: event.target.value })}
placeholder="url"
/>{' '}
{}
<input
className="short"
value={this.state.query}
onChange={event => this.setState({ query: event.target.value })}
placeholder="query"
/>{' '}
{}
<input
className="short"
value={this.state.color}
onChange={event => this.setState({ color: event.target.value })}
placeholder="color"
/>{' '}
{}
<input
className="short"
value={this.state.prefix}
onChange={event => this.setState({ prefix: event.target.value })}
placeholder="prefix"
/>{' '}
{}
<input
className="short"
value={this.state.suffix}
onChange={event => this.setState({ suffix: event.target.value })}
placeholder="suffix"
/>{' '}
{}
<button disabled={!this.isValid}>Make Badge</button>
</form>
)
}
}

View File

@@ -0,0 +1,109 @@
import React from 'react'
import PropTypes from 'prop-types'
import Meta from './meta'
import Header from './header'
import SuggestionAndSearch from './suggestion-and-search'
import SearchResults from './search-results'
import MarkupModal from './markup-modal'
import Usage from './usage'
import Footer from './footer'
import { baseUrl, longCache } from '../constants'
export default class ExamplesPage extends React.Component {
constructor(props) {
super(props)
this.state = {
category: props.match.params.id,
query: null,
example: null,
searchReady: true,
}
this.searchTimeout = 0
this.renderSearchResults = this.renderSearchResults.bind(this)
this.searchQueryChanged = this.searchQueryChanged.bind(this)
}
static propTypes = {
match: PropTypes.object.isRequired,
}
searchQueryChanged(query) {
this.setState({ searchReady: false })
/*
Add a small delay before showing search results
so that we wait until the user has stipped typing
before we start loading stuff.
This
a) reduces the amount of badges we will load and
b) stops the page from 'flashing' as the user types, like this:
https://user-images.githubusercontent.com/7288322/42600206-9b278470-85b5-11e8-9f63-eb4a0c31cb4a.gif
*/
window.clearTimeout(this.searchTimeout)
this.searchTimeout = window.setTimeout(() => {
this.setState({
searchReady: true,
query,
})
}, 500)
}
renderSearchResults() {
if (this.state.searchReady) {
if (this.state.query != null && this.state.query.length === 1) {
return <div>Search term must have 2 or more characters</div>
} else {
return (
<SearchResults
category={this.state.category}
query={this.state.query}
clickHandler={example => {
this.setState({ example })
}}
/>
)
}
} else {
return <div>searching...</div>
}
}
render() {
return (
<div>
<Meta />
<Header />
<MarkupModal
example={this.state.example}
onRequestClose={() => {
this.setState({ example: null })
}}
baseUrl={baseUrl}
key={this.state.example}
/>
<section>
<SuggestionAndSearch
queryChanged={this.searchQueryChanged}
onBadgeClick={example => {
this.setState({ example })
}}
baseUrl={baseUrl}
longCache={longCache}
/>
<a className="donate" href="https://opencollective.com/shields">
donate
</a>
</section>
{this.renderSearchResults()}
<Usage baseUrl={baseUrl} longCache={longCache} />
<Footer baseUrl={baseUrl} />
<style jsx>{`
.donate {
text-decoration: none;
color: rgba(0, 0, 0, 0.1);
}
`}</style>
</div>
)
}
}

View File

@@ -0,0 +1,61 @@
import React from 'react'
import PropTypes from 'prop-types'
import resolveUrl from '../lib/resolve-url'
const Footer = ({ baseUrl }) => (
<section>
<h2 id="like-this">Like This?</h2>
<p>
<object
data={resolveUrl(
'/twitter/follow/shields_io.svg?style=social&label=Follow',
baseUrl
)}
alt="Follow @shields_io"
/>{' '}
{}
<a href="https://opencollective.com/shields" alt="Donate to us!">
<img src="https://opencollective.com/shields/backers/badge.svg?style=social" />
</a>{' '}
{}
<a href="https://opencollective.com/shields" alt="Donate to us!">
<img src="https://opencollective.com/shields/sponsors/badge.svg?style=social" />
</a>{' '}
{}
<object
data={resolveUrl(
'/github/forks/badges/shields.svg?style=social&label=Fork',
baseUrl
)}
alt="Fork on GitHub"
/>{' '}
{}
<object
data={resolveUrl(
'/discord/308323056592486420.svg?style=social&label=Chat&link=https://discord.gg/HjJCwm5',
baseUrl
)}
alt="chat on Discord"
/>
</p>
<p>
What is your favorite badge service to use?
<br />
<a href="https://github.com/badges/shields/blob/master/CONTRIBUTING.md">
Tell us
</a>{' '}
and we might bring it to you!
</p>
<p className="spaced-row">
<a href="https://status.shields.io/">Status</a>
<a href="https://github.com/badges/shields/">GitHub</a>
</p>
</section>
)
export default Footer
Footer.propTypes = {
baseUrl: PropTypes.string.isRequired,
}

View File

@@ -0,0 +1,23 @@
import { Link } from 'react-router-dom'
import React from 'react'
export default () => (
<section>
<Link to="/">
<img alt="Shields.io" src="/static/logo.svg" />
</Link>
<hr className="spacing" />
<p className="highlights">
Pixel-perfect &nbsp; Retina-ready &nbsp; Fast &nbsp; Consistent &nbsp;
Hackable &nbsp; No tracking
</p>
<style jsx>{`
.highlights {
font-style: italic;
}
`}</style>
</section>
)

View File

@@ -0,0 +1,190 @@
import React from 'react'
import PropTypes from 'prop-types'
import Modal from 'react-modal'
import ClickToSelect from '@mapbox/react-click-to-select'
import resolveBadgeUrl from '../lib/badge-url'
import generateAllMarkup from '../lib/generate-image-markup'
import { advertisedStyles } from '../../supported-features.json'
export default class MarkupModal extends React.Component {
static propTypes = {
example: PropTypes.shape({
title: PropTypes.string.isRequired,
exampleUrl: PropTypes.string,
previewUrl: PropTypes.string,
urlPattern: PropTypes.string,
documentation: PropTypes.string,
link: PropTypes.string,
}),
baseUrl: PropTypes.string.isRequired,
onRequestClose: PropTypes.func.isRequired,
}
state = {
exampleUrl: null,
badgeUrl: null,
link: '',
style: 'flat',
}
constructor(props) {
super(props)
// Transfer `badgeUrl` and `link` into state so they can be edited by the
// user.
const { example, baseUrl } = props
if (example) {
const { exampleUrl, urlPattern, previewUrl, link } = example
this.state = {
...this.state,
exampleUrl: exampleUrl
? resolveBadgeUrl(exampleUrl, baseUrl || window.location.href)
: null,
badgeUrl: resolveBadgeUrl(
urlPattern || previewUrl,
baseUrl || window.location.href
),
link: !link ? '' : link,
}
}
}
get isOpen() {
return this.props.example !== null
}
generateCompleteBadgeUrl() {
const { baseUrl } = this.props
const { badgeUrl, style } = this.state
return resolveBadgeUrl(
badgeUrl,
baseUrl || window.location.href,
// Default style doesn't need to be specified.
style === 'flat' ? undefined : { style }
)
}
generateMarkup() {
if (!this.isOpen) {
return {}
}
const { title } = this.props.example
const { link } = this.state
const completeBadgeUrl = this.generateCompleteBadgeUrl()
return generateAllMarkup(completeBadgeUrl, link, title)
}
renderDocumentation() {
if (!this.isOpen) {
return null
}
const { documentation } = this.props.example
return documentation ? (
<div>
<h4>Documentation</h4>
<div dangerouslySetInnerHTML={{ __html: documentation }} />
</div>
) : null
}
render() {
const { markdown, reStructuredText, asciiDoc } = this.generateMarkup()
const completeBadgeUrl = this.isOpen
? this.generateCompleteBadgeUrl()
: undefined
return (
<Modal
isOpen={this.isOpen}
onRequestClose={this.props.onRequestClose}
contentLabel="Example Modal"
>
<form action="">
<p>
<img className="badge-img" src={completeBadgeUrl} />
</p>
<p>
<label>
Link&nbsp;
<input
type="url"
value={this.state.link}
onChange={event => {
this.setState({ link: event.target.value })
}}
/>
</label>
</p>
<p>
<label>
Image&nbsp;
<input
type="url"
value={this.state.badgeUrl}
onChange={event => {
this.setState({ badgeUrl: event.target.value })
}}
/>
</label>
</p>
{this.state.exampleUrl && (
<p>
Example&nbsp;
<ClickToSelect>
<input
className="code clickable"
readOnly
value={this.state.exampleUrl}
/>
</ClickToSelect>
</p>
)}
<p>
<label>
Style&nbsp;
<select
value={this.state.style}
onChange={event => {
this.setState({ style: event.target.value })
}}
>
{advertisedStyles.map(style => (
<option key={style} value={style}>
{style}
</option>
))}
</select>
</label>
</p>
<p>
Markdown&nbsp;
<ClickToSelect>
<input className="code clickable" readOnly value={markdown} />
</ClickToSelect>
</p>
<p>
reStructuredText&nbsp;
<ClickToSelect>
<input
className="code clickable"
readOnly
value={reStructuredText}
/>
</ClickToSelect>
</p>
<p>
AsciiDoc&nbsp;
<ClickToSelect>
<input className="code clickable" readOnly value={asciiDoc} />
</ClickToSelect>
</p>
{this.renderDocumentation()}
</form>
</Modal>
)
}
}

View File

@@ -0,0 +1,21 @@
import React from 'react'
import Head from 'next/head'
const description = `We serve fast and scalable informational images as badges
for GitHub, Travis CI, Jenkins, WordPress and many more services. Use them to
track the state of your projects, or for promotional purposes.`
export default () => (
<Head>
<title>Shields.io: Quality metadata badges for open source projects</title>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="description" content={description} />
<link rel="icon" type="image/png" href="favicon.png" />
<link href="/static/main.css" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css?family=Lekton"
rel="stylesheet"
/>
</Head>
)

View File

@@ -0,0 +1,53 @@
import React from 'react'
import { Link } from 'react-router-dom'
import PropTypes from 'prop-types'
import { BadgeExamples } from './badge-examples'
import badgeExampleData from '../../badge-examples.json'
import { prepareExamples, predicateFromQuery } from '../lib/prepare-examples'
import { baseUrl, longCache } from '../constants'
export default class SearchResults extends React.Component {
static propTypes = {
category: PropTypes.string,
query: PropTypes.string,
clickHandler: PropTypes.func.isRequired,
}
prepareExamples(category) {
const examples = category
? badgeExampleData.filter(example => example.category.id === category)
: badgeExampleData
return prepareExamples(examples, () => predicateFromQuery(this.props.query))
}
renderExamples() {
return (
<BadgeExamples
categories={this.preparedExamples}
onClick={this.props.clickHandler}
baseUrl={baseUrl}
longCache={longCache}
/>
)
}
renderCategoryHeadings() {
return this.preparedExamples.map((category, i) => (
<Link to={`/examples/${category.category.id}`} key={category.category.id}>
<h3 id={category.category.id}>{category.category.name}</h3>
</Link>
))
}
render() {
this.preparedExamples = this.prepareExamples(this.props.category)
if (this.props.category) {
return this.renderExamples()
} else if (this.props.query == null || this.props.query.length === 0) {
return this.renderCategoryHeadings()
} else {
return this.renderExamples()
}
}
}

View File

@@ -0,0 +1,71 @@
import React from 'react'
import PropTypes from 'prop-types'
import { staticBadgeUrl } from '../lib/badge-url'
export default class StaticBadgeMaker extends React.Component {
static propTypes = {
baseUrl: PropTypes.string,
}
state = {
subject: '',
status: '',
color: '',
}
handleSubmit(e) {
e.preventDefault()
const { baseUrl } = this.props
const { subject, status, color } = this.state
const badgeUrl = staticBadgeUrl(
baseUrl || window.location.href,
subject,
status,
color
)
document.location = badgeUrl
}
render() {
return (
<form onSubmit={e => this.handleSubmit(e)}>
<input
className="short"
value={this.state.subject}
onChange={event => this.setState({ subject: event.target.value })}
placeholder="subject"
/>{' '}
{}
<input
className="short"
value={this.state.status}
onChange={event => this.setState({ status: event.target.value })}
placeholder="status"
/>{' '}
{}
<input
className="short"
value={this.state.color}
onChange={event => this.setState({ color: event.target.value })}
list="default-colors"
placeholder="color"
/>{' '}
{}
<datalist id="default-colors">
<option value="brightgreen" />
<option value="green" />
<option value="yellowgreen" />
<option value="yellow" />
<option value="orange" />
<option value="red" />
<option value="lightgrey" />
<option value="blue" />
</datalist>{' '}
{}
<button>Make Badge</button>
</form>
)
}
}

View File

@@ -0,0 +1,119 @@
import React from 'react'
import PropTypes from 'prop-types'
import fetchPonyfill from 'fetch-ponyfill'
import debounce from 'lodash.debounce'
import { Badge } from './badge-examples'
import resolveUrl from '../lib/resolve-url'
export default class SuggestionAndSearch extends React.Component {
static propTypes = {
queryChanged: PropTypes.func.isRequired,
onBadgeClick: PropTypes.func.isRequired,
baseUrl: PropTypes.string.isRequired,
longCache: PropTypes.bool.isRequired,
}
constructor(props) {
super(props)
this.queryChangedDebounced = debounce(props.queryChanged, 50, {
leading: true,
})
}
state = {
isUrl: false,
inProgress: false,
projectUrl: null,
suggestions: [],
}
queryChanged(query) {
const isUrl = query.startsWith('https://') || query.startsWith('http://')
this.setState({
isUrl,
projectUrl: isUrl ? query : null,
})
this.queryChangedDebounced(query)
}
getSuggestions() {
this.setState({ inProgress: true }, async () => {
const { baseUrl } = this.props
const { projectUrl } = this.state
const url = resolveUrl('/$suggest/v1', baseUrl, { url: projectUrl })
const fetch = window.fetch || fetchPonyfill
const res = await fetch(url)
let suggestions
try {
const json = await res.json()
// This doesn't validate the response. The default value here prevents
// a crash if the server returns {"err":"Disallowed"}.
suggestions = json.badges || []
} catch (e) {
suggestions = []
}
this.setState({ inProgress: false, suggestions })
})
}
renderSuggestions() {
const { baseUrl, longCache } = this.props
const { suggestions } = this.state
if (suggestions.length === 0) {
return null
}
return (
<table className="badge">
<tbody>
{suggestions.map(({ name, link, badge }, i) => (
// TODO We need to deal with `link`.
<Badge
key={i}
title={name}
previewUrl={badge}
onClick={() =>
this.props.onBadgeClick({
title: name,
previewUrl: badge,
link,
})
}
baseUrl={baseUrl}
longCache={longCache}
/>
))}
</tbody>
</table>
)
}
render() {
return (
<section>
<form action="javascript:void 0" autoComplete="off">
<input
onChange={event => this.queryChanged(event.target.value)}
autofill="off"
autoFocus
placeholder="search / project URL"
/>
<br />
<button
onClick={event => this.getSuggestions(event.target.value)}
disabled={this.state.inProgress}
hidden={!this.state.isUrl}
>
Suggest badges
</button>
</form>
{this.renderSuggestions()}
</section>
)
}
}

View File

@@ -0,0 +1,287 @@
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import StaticBadgeMaker from './static-badge-maker'
import DynamicBadgeMaker from './dynamic-badge-maker'
import { staticBadgeUrl } from '../lib/badge-url'
import { advertisedStyles, logos } from '../../supported-features.json'
export default class Usage extends React.PureComponent {
static propTypes = {
baseUrl: PropTypes.string.isRequired,
longCache: PropTypes.bool.isRequired,
}
renderColorExamples() {
const { baseUrl, longCache } = this.props
const colors = [
'brightgreen',
'green',
'yellowgreen',
'yellow',
'orange',
'red',
'lightgrey',
'blue',
'ff69b4',
]
return (
<p>
{colors.map((color, i) => (
<Fragment key={i}>
<img
className="badge-img"
src={staticBadgeUrl(baseUrl, 'color', color, color, {
longCache,
})}
alt={color}
/>{' '}
{}
</Fragment>
))}
</p>
)
}
renderStyleExamples() {
const { baseUrl, longCache } = this.props
return (
<table className="badge-img">
<tbody>
{advertisedStyles.map((style, i) => {
const badgeUrl = staticBadgeUrl(baseUrl, 'style', style, 'green', {
logo: 'appveyor',
longCache,
style,
})
return (
<tr key={i}>
<td>
<img className="badge-img" src={badgeUrl} alt={style} />
</td>
<td>
<code>{badgeUrl}</code>
</td>
</tr>
)
})}
</tbody>
</table>
)
}
static renderNamedLogos() {
const renderLogo = logo => (
<span className="nowrap" key={logo}>
{logo}
</span>
)
const [first, ...rest] = logos
return [renderLogo(first)].concat(
rest.reduce((result, logo) => result.concat([', ', renderLogo(logo)]), [])
)
}
render() {
const { baseUrl } = this.props
return (
<section>
<h2 id="your-badge">Your Badge</h2>
<h3 id="static-badge">Static</h3>
<StaticBadgeMaker baseUrl={baseUrl} />
<hr className="spacing" />
<p>
<code>
{baseUrl}
/badge/&lt;SUBJECT&gt;-&lt;STATUS&gt;-&lt;COLOR&gt;.svg
</code>
</p>
<table className="centered">
<tbody>
<tr>
<td>
Dashes <code>--</code>
</td>
<td></td>
<td>
<code>-</code> Dash
</td>
</tr>
<tr>
<td>
Underscores <code>__</code>
</td>
<td></td>
<td>
<code>_</code> Underscore
</td>
</tr>
<tr>
<td>
<code>_</code> or Space <code>&nbsp;</code>
</td>
<td></td>
<td>
<code>&nbsp;</code> Space
</td>
</tr>
</tbody>
</table>
{this.renderColorExamples()}
<h3 id="dynamic-badge">Dynamic</h3>
<DynamicBadgeMaker baseUrl={baseUrl} />
<p>
<code>
/badge/dynamic/json.svg?url=&lt;URL&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;
<a
href="https://www.npmjs.com/package/jsonpath"
target="_BLANK"
title="JSONdata syntax"
>
$.DATA.SUBDATA
</a>
&gt;&amp;colorB=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;
</code>
</p>
<p>
<code>
/badge/dynamic/xml.svg?url=&lt;URL&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;
<a
href="https://www.npmjs.com/package/xpath"
target="_BLANK"
title="XPath syntax"
>
//data/subdata
</a>
&gt;&amp;colorB=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;
</code>
</p>
<p>
<code>
/badge/dynamic/yaml.svg?url=&lt;URL&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;
<a
href="https://www.npmjs.com/package/jsonpath"
target="_BLANK"
title="JSONdata syntax"
>
$.DATA.SUBDATA
</a>
&gt;&amp;colorB=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;
</code>
</p>
<hr className="spacing" />
<h2 id="styles">Styles</h2>
<p>
The following styles are available. Flat is the default. Examples are
shown with an optional logo:
</p>
{this.renderStyleExamples()}
<p>
Here are a few other parameters you can use: (connecting several with
"&" is possible)
</p>
<table className="usage">
<tbody>
<tr>
<td>
<code>?label=healthinesses</code>
</td>
<td>
Override the default left-hand-side text (
<a href="https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding">
URL-Encoding
</a>
{} needed for spaces or special characters!)
</td>
</tr>
<tr>
<td>
<code>?logo=appveyor</code>
</td>
<td>
Insert one of the named logos from (
{this.constructor.renderNamedLogos()}) or{' '}
<a href="https://simpleicons.org/" target="_BLANK">
simple-icons
</a>
</td>
</tr>
<tr>
<td>
<code>?logo=data:image/png;base64,</code>
</td>
<td>Insert custom logo image ( 14px high)</td>
</tr>
<tr>
<td>
<code>?logoColor=violet</code>
</td>
<td>
Set the color of the logo (hex, rgb, rgba, hsl, hsla and css
named colors supported)
</td>
</tr>
<tr>
<td>
<code>?logoWidth=40</code>
</td>
<td>Set the horizontal space to give to the logo</td>
</tr>
<tr>
<td>
<code>?link=http://left&amp;link=http://right</code>
</td>
<td>
Specify what clicking on the left/right of a badge should do
(esp. for social badge style)
</td>
</tr>
<tr>
<td>
<code>?colorA=abcdef</code>
</td>
<td>
Set background of the left part (hex, rgb, rgba, hsl, hsla and
css named colors supported)
</td>
</tr>
<tr>
<td>
<code>?colorB=fedcba</code>
</td>
<td>
Set background of the right part (hex, rgb, rgba, hsl, hsla and
css named colors supported)
</td>
</tr>
<tr>
<td>
<code>?maxAge=3600</code>
</td>
<td>
Set the HTTP cache lifetime in secs (rules are applied to infer
a default value on a per-badge basis, any values specified below
the default will be ignored)
</td>
</tr>
</tbody>
</table>
<p>
We support <code>.svg</code>, <code>.json</code>, <code>.png</code>{' '}
and a few others, but use them responsibly.
</p>
</section>
)
}
}

6
frontend/constants.js Normal file
View File

@@ -0,0 +1,6 @@
import envFlag from 'node-env-flag'
const baseUrl = process.env.BASE_URL
const longCache = envFlag(process.env.LONG_CACHE, false)
export { baseUrl, longCache }

52
frontend/lib/badge-url.js Normal file
View File

@@ -0,0 +1,52 @@
import resolveUrl from './resolve-url'
import { staticBadgeUrl as makeStaticBadgeUrl } from '../../lib/make-badge-url'
export default function resolveBadgeUrl(
url,
baseUrl,
{ longCache, style, queryParams: inQueryParams } = {}
) {
const outQueryParams = Object.assign({}, inQueryParams)
if (longCache) {
outQueryParams.maxAge = '2592000'
}
if (style) {
outQueryParams.style = style
}
return resolveUrl(url, baseUrl, outQueryParams)
}
export function staticBadgeUrl(baseUrl, label, message, color, options) {
const path = makeStaticBadgeUrl({ label, message, color })
return resolveUrl(path, baseUrl, options)
}
// Options can include: { prefix, suffix, color, longCache, style, queryParams }
export function dynamicBadgeUrl(
baseUrl,
datatype,
label,
dataUrl,
query,
{ prefix, suffix, color, queryParams = {}, ...rest } = {}
) {
Object.assign(queryParams, {
label,
url: dataUrl,
query,
})
if (color) {
queryParams.colorB = color
}
if (prefix) {
queryParams.prefix = prefix
}
if (suffix) {
queryParams.suffix = suffix
}
const outOptions = Object.assign({ queryParams }, rest)
return resolveBadgeUrl(`/badge/dynamic/${datatype}.svg`, baseUrl, outOptions)
}

View File

@@ -0,0 +1,51 @@
import { test, given } from 'sazerac'
import resolveBadgeUrl, { staticBadgeUrl, dynamicBadgeUrl } from './badge-url'
const resolveBadgeUrlWithLongCache = (url, baseUrl) =>
resolveBadgeUrl(url, baseUrl, { longCache: true })
describe('Badge URL functions', function() {
test(resolveBadgeUrl, () => {
given('/badge/foo-bar-blue.svg', undefined).expect(
'/badge/foo-bar-blue.svg'
)
given('/badge/foo-bar-blue.svg', 'http://example.com').expect(
'http://example.com/badge/foo-bar-blue.svg'
)
})
test(resolveBadgeUrlWithLongCache, () => {
given('/badge/foo-bar-blue.svg', undefined).expect(
'/badge/foo-bar-blue.svg?maxAge=2592000'
)
given('/badge/foo-bar-blue.svg', 'http://example.com').expect(
'http://example.com/badge/foo-bar-blue.svg?maxAge=2592000'
)
})
test(staticBadgeUrl, () => {
given('http://img.example.com', 'foo', 'bar', 'blue', {
style: 'plastic',
}).expect('http://img.example.com/badge/foo-bar-blue.svg?style=plastic')
})
test(dynamicBadgeUrl, () => {
const dataUrl = 'http://example.com/foo.json'
const query = '$.bar'
const prefix = 'value: '
given('http://img.example.com', 'json', 'foo', dataUrl, query, {
prefix,
style: 'plastic',
}).expect(
[
'http://img.example.com/badge/dynamic/json.svg',
'?label=foo',
`&url=${encodeURIComponent(dataUrl)}`,
`&query=${encodeURIComponent(query)}`,
`&prefix=${encodeURIComponent(prefix)}`,
'&style=plastic',
].join('')
)
})
})

View File

@@ -0,0 +1,75 @@
export function markdown(badgeUrl, link, title) {
const withoutLink = `![${title || ''}](${badgeUrl})`
if (link) {
return `[${withoutLink}](${link})`
} else {
return withoutLink
}
}
export function reStructuredText(badgeUrl, link, title) {
let result = `.. image:: ${badgeUrl}`
if (title) {
result += ` :alt: ${title}`
}
if (link) {
result += ` :target: ${link}`
}
return result
}
function quoteAsciiDocAttribute(attr) {
if (typeof attr === 'string') {
const withQuotesEscaped = attr.replace(/"/g, '\\"')
return `"${withQuotesEscaped}"`
} else if (attr == null) {
return 'None'
} else {
return attr
}
}
// lodash.mapvalues is huge!
function mapValues(obj, iteratee) {
const result = {}
for (const k in obj) {
result[k] = iteratee(obj[k])
}
return result
}
export function renderAsciiDocAttributes(positional, named) {
// http://asciidoc.org/userguide.html#X21
const needsQuoting =
positional.some(attr => attr.includes(',')) || Object.keys(named).length > 0
if (needsQuoting) {
positional = positional.map(attr => quoteAsciiDocAttribute(attr))
named = mapValues(named, attr => quoteAsciiDocAttribute(attr))
}
const items = positional.concat(
Object.entries(named).map(([k, v]) => `${k}=${v}`)
)
if (items.length) {
return `[${items.join(',')}]`
} else {
return ''
}
}
export function asciiDoc(badgeUrl, link, title) {
const positional = title ? [title] : []
const named = link ? { link } : {}
const attrs = renderAsciiDocAttributes(positional, named)
return `image:${badgeUrl}${attrs}`
}
export default function generateAllMarkup(badgeUrl, link, title) {
// This is a wee bit "clever". It runs each of the three functions on the
// parameters provided, and returns the result in an object.
return mapValues({ markdown, reStructuredText, asciiDoc }, fn =>
fn(badgeUrl, link, title)
)
}

View File

@@ -0,0 +1,45 @@
import escapeStringRegexp from 'escape-string-regexp'
export function exampleMatchesRegex(example, regex) {
const { title, keywords } = example
const haystack = [title].concat(keywords).join(' ')
return regex.test(haystack)
}
export function predicateFromQuery(query) {
if (query) {
const escaped = escapeStringRegexp(query)
const regex = new RegExp(escaped, 'i') // Case-insensitive.
return example => exampleMatchesRegex(example, regex)
} else {
return () => true
}
}
export function mapExamples(categories, iteratee) {
return (
categories
.map(({ category, examples }) => ({
category,
examples: iteratee(examples),
}))
// Remove empty categories.
.filter(({ category, examples }) => examples.length > 0)
)
}
export function prepareExamples(categories, predicateProvider) {
let nextKey = 0
return mapExamples(categories, examples =>
examples.map(example =>
Object.assign(
{
shouldDisplay: () => predicateProvider()(example),
// Assign each example a unique ID.
key: nextKey++,
},
example
)
)
)
}

View File

@@ -0,0 +1,18 @@
import { test, given, forCases } from 'sazerac'
import { predicateFromQuery } from './prepare-examples'
describe('Badge example functions', function() {
const exampleMatchesQuery = (example, query) =>
predicateFromQuery(query)(example)
test(exampleMatchesQuery, () => {
forCases([given({ title: 'node version' }, 'npm')]).expect(false)
forCases([
given({ title: 'node version', keywords: ['npm'] }, 'node'),
given({ title: 'node version', keywords: ['npm'] }, 'npm'),
// https://github.com/badges/shields/issues/1578
given({ title: 'c++ is the best language' }, 'c++'),
]).expect(true)
})
})

View File

@@ -0,0 +1,14 @@
// I played with build-url and url-resolve-browser and neither of them did the
// right thing. Previously this was based on url-path, which patched around
// the URL API. This caused problems in Firefox 57, but only in the production
// build.
import { resolve, parse, format } from 'url'
// baseUrl and queryParams are optional.
export default function resolveUrl(url, baseUrl, queryParams) {
const resolved = baseUrl ? resolve(baseUrl, url) : url
const parsed = parse(resolved, /* parseQueryString */ true)
parsed.query = Object.assign({}, parsed.query, queryParams)
delete parsed.search
return format(parsed)
}

View File

@@ -0,0 +1,29 @@
import { test, given, forCases } from 'sazerac'
import resolveUrl from './resolve-url'
describe('URL resolver', function() {
test(resolveUrl, () => {
forCases([
given('/foo/bar'),
given('/foo/bar', '/'),
given('/foo/bar', '/baz'),
given('/foo/bar', '/baz/'),
given('/foo/bar', ''),
given('/foo/bar', undefined),
]).expect('/foo/bar')
given('foo/bar', '/baz/').expect('/baz/foo/bar')
forCases([
given('http://foo/bar'),
given('bar', 'http://foo/'),
given('/bar', 'http://foo/'),
]).expect('http://foo/bar')
given('/foo/bar', '/baz', { baz: 'bazinga' }).expect('/foo/bar?baz=bazinga')
given('/foo/bar?thing=1', undefined, { other: '2' }).expect(
'/foo/bar?thing=1&other=2'
)
})
})

View File

@@ -1,69 +0,0 @@
#!/usr/bin/env node
var path = require('path');
var badge = require(path.join(__dirname, 'badge.js'));
var svg2img = require(path.join(__dirname, 'svg-to-img.js'));
var colorscheme = require(path.join(__dirname, 'colorscheme.json'));
if (process.argv.length < 4) {
console.log('Usage: badge subject status [:colorscheme] [.output] [@style]');
console.log('Or: badge subject status right-color [left-color] [.output] [@style]');
console.log();
console.log(' colorscheme: one of '
+ Object.keys(colorscheme).join(', ') + '.');
console.log(' left-color, right-color:');
console.log(' #xxx (three hex digits)');
console.log(' #xxxxxx (six hex digits)');
console.log(' color (CSS color)');
console.log(' output:');
console.log(' svg, png, jpg, or gif');
console.log();
console.log('Eg: badge cactus grown :green @flat');
console.log();
process.exit();
}
// Find a format specifier.
var format = 'svg';
var style = '';
for (var i = 4; i < process.argv.length; i++) {
if (process.argv[i][0] === '.') {
format = process.argv[i].slice(1);
process.argv.splice(i, 1);
continue;
}
if (process.argv[i][0] === '@') {
style = process.argv[i].slice(1);
process.argv.splice(i, 1);
continue;
}
}
var subject = process.argv[2];
var status = process.argv[3];
var color = process.argv[4] || ':green';
var colorA = process.argv[5];
var badgeData = {text: [subject, status], format: format};
if (style) {
badgeData.template = style;
}
if (color[0] === ':') {
color = color.slice(1);
if (colorscheme[color] == null) {
// Colorscheme not found.
console.error('Invalid color scheme.');
process.exit(1);
}
badgeData.colorscheme = color;
} else {
badgeData.colorB = color;
if (colorA) { badgeData.colorA = colorA; }
}
badge(badgeData, function produceOutput(svg) {
if (/png|jpg|gif/.test(format)) {
svg2img(svg, format, process.stdout);
} else {
console.log(svg);
}
});

2
gh-badges/.npmignore Normal file
View File

@@ -0,0 +1,2 @@
lib/make-badge-test-helpers.js
lib/**/*.spec.js

140
gh-badges/CHANGELOG.md Normal file
View File

@@ -0,0 +1,140 @@
# Changelog
## 2.1.0
gh-badges v2.1.0 implements a new text width measurer which uses a lookup table, removing the dependency
on PDFKit. It is no longer necessary to provide a local copy of Verdana for accurate text width computation.
As such, the `fontPath` and `precomputeWidths` parameters are now deprecated. The recommended call to create an instance of `BadgeFactory` is now
```js
const bf = new BadgeFactory()
```
For backwards compatibility you can still construct an instance of `BadgeFactory` with a call like
```js
const bf = new BadgeFactory({ fontPath: '/path/to/Verdana.ttf', precomputeWidths: true })
```
However, the function will issue a warning.
To clear the warning, change the code to:
```js
const bf = new BadgeFactory()
```
These arguments will be removed in a future release.
To upgrade from v1.3.0, change your code from:
```js
const badge = require('gh-badges')
const format = {
text: ['build', 'passed'],
colorscheme: 'green',
template: 'flat',
}
badge.loadFont('/path/to/Verdana.ttf', err => {
badge(format, (svg, err) => {
// svg is a string containing your badge
})
})
```
to:
```js
const { BadgeFactory } = require('gh-badges')
const bf = new BadgeFactory()
const format = {
text: ['build', 'passed'],
colorscheme: 'green',
template: 'flat',
}
const svg = bf.create(format)
```
### Other changes in this release:
* Remove unnecessary dependencies
* Documentation improvements
## 2.0.0 - 2018-11-09
gh-badges v2.0.0 declares a new public interface which is synchronous.
If your version 1.3.0 code looked like this:
```js
const badge = require('gh-badges')
const format = {
text: ['build', 'passed'],
colorscheme: 'green',
template: 'flat',
}
badge.loadFont('/path/to/Verdana.ttf', err => {
badge(format, (svg, err) => {
// svg is a string containing your badge
})
})
```
To upgrade to version 2.0.0, refactor you code to:
```js
const { BadgeFactory } = require('gh-badges')
const bf = new BadgeFactory({ fontPath: '/path/to/Verdana.ttf' })
const format = {
text: ['build', 'passed'],
colorscheme: 'green',
template: 'flat',
}
const svg = bf.create(format)
```
You can generate badges without a copy of Verdana, however font width computation is approximate and badges may be distorted.
```js
const bf = new BadgeFactory({ fallbackFontPath: 'Helvetica' })
```
## 1.3.0 - 2016-09-07
Add support for optionally specifying the path to `Verdana.ttf`. In earlier versions, the file needed to be in the directory containing Shields.
Without font path:
```js
const badge = require('gh-badges')
badge({ text: [ 'build', 'passed' ], colorscheme: 'green' },
(svg, err) => {
// svg is a string containing your badge
})
```
With font path:
```js
const badge = require('gh-badges')
// Optional step, to have accurate text width computation.
badge.loadFont('/path/to/Verdana.ttf', err => {
badge({ text: ['build', 'passed'], colorscheme: 'green', template: 'flat' },
(svg, err) => {
// svg is a string containing your badge
})
})
```

116
gh-badges/LICENSE Normal file
View File

@@ -0,0 +1,116 @@
CC0 1.0 Universal
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:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. 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
vii. 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.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

86
gh-badges/README.md Normal file
View File

@@ -0,0 +1,86 @@
# gh-badges
[![npm version](https://img.shields.io/npm/v/gh-badges.svg)](https://npmjs.org/package/gh-badges)
[![npm license](https://img.shields.io/npm/l/gh-badges.svg)](https://npmjs.org/package/gh-badges)
## Installation
```sh
npm install gh-badges
```
## Usage
### On the console
```sh
npm install -g gh-badges
badge build passed :green .png > mybadge.png
```
### As a library
```js
const { BadgeFactory } = require('gh-badges')
const bf = new BadgeFactory()
const format = {
text: ['build', 'passed'],
colorscheme: 'green',
template: 'flat',
}
const svg = bf.create(format)
```
## Format
The format is the following:
```js
{
text: [ 'build', 'passed' ], // Textual information shown, in order
format: 'svg', // Also supports json
colorscheme: 'green',
// or ...
colorA: '#555',
colorB: '#4c1',
// See templates/ for a list of available templates.
// Each offers a different visual design.
template: 'flat',
}
```
### See also
- [colorscheme.json](./lib/colorscheme.json) for the `colorscheme` option
- [templates/](./templates) for the `template` option
## Defaults
If you want to use a colorscheme, head to `lib/colorscheme.json`. Each scheme
has a name and a [CSS/SVG color][] for the color used in the first box (for the
first piece of text, field `colorA`) and for the one used in the second box
(field `colorB`).
[CSS/SVG color]: http://www.w3.org/TR/SVG/types.html#DataTypeColor
```js
"green": {
"colorB": "#4c1"
}
```
Both `colorA` and `colorB` have default values. Usually, the first box uses the
same dark grey, so you can rely on that default value by not providing a
`"colorA"` field (such as above).
You can also use the `"colorA"` and `"colorB"` fields directly in the badges if
you don't want to make a color scheme for it. In that case, remove the
`"colorscheme"` field altogether.

87
gh-badges/lib/badge-cli.js Executable file
View File

@@ -0,0 +1,87 @@
#!/usr/bin/env node
'use strict'
const makeBadge = require('./make-badge')
const svg2img = require('./svg-to-img')
const colorscheme = require('./colorscheme.json')
if (process.argv.length < 4) {
console.log('Usage: badge subject status [:colorscheme] [.output] [@style]')
console.log(
'Or: badge subject status right-color [left-color] [.output] [@style]'
)
console.log()
console.log(` colorscheme: one of ${Object.keys(colorscheme).join(', ')}.`)
console.log(' left-color, right-color:')
console.log(' #xxx (three hex digits)')
console.log(' #xxxxxx (six hex digits)')
console.log(' color (CSS color)')
console.log(' output:')
console.log(' svg, png, jpg, or gif')
console.log()
console.log('Eg: badge cactus grown :green @flat')
console.log()
process.exit()
}
// Find a format specifier.
let format = 'svg'
let style = ''
for (let i = 4; i < process.argv.length; i++) {
if (process.argv[i][0] === '.') {
format = process.argv[i].slice(1)
process.argv.splice(i, 1)
continue
}
if (process.argv[i][0] === '@') {
style = process.argv[i].slice(1)
process.argv.splice(i, 1)
continue
}
}
const subject = process.argv[2]
const status = process.argv[3]
let color = process.argv[4] || ':green'
const colorA = process.argv[5]
const badgeData = { text: [subject, status], format }
if (style) {
badgeData.template = style
}
if (color[0] === ':') {
color = color.slice(1)
if (colorscheme[color] == null) {
// Colorscheme not found.
console.error('Invalid color scheme.')
process.exit(1)
}
badgeData.colorscheme = color
} else {
badgeData.colorB = color
if (colorA) {
badgeData.colorA = colorA
}
}
async function main() {
const svg = makeBadge(badgeData)
if (/png|jpg|gif/.test(format)) {
const data = await svg2img(svg, format)
process.stdout.write(data)
} else {
console.log(svg)
}
}
;(async () => {
try {
await main()
} catch (e) {
console.error(e)
process.exit(1)
}
})()

View File

@@ -0,0 +1,58 @@
'use strict'
const path = require('path')
const isPng = require('is-png')
const isSvg = require('is-svg')
const { spawn } = require('child-process-promise')
const { expect, use } = require('chai')
use(require('chai-string'))
use(require('sinon-chai'))
function runCli(args) {
return spawn('node', [path.join(__dirname, 'badge-cli.js'), ...args], {
capture: ['stdout'],
})
}
describe('The CLI', function() {
it('should provide a help message', async function() {
const { stdout } = await runCli([])
expect(stdout).to.startWith('Usage')
})
it('should produce default badges', async function() {
const { stdout } = await runCli(['cactus', 'grown'])
expect(stdout)
.to.satisfy(isSvg)
.and.to.include('cactus')
.and.to.include('grown')
})
it('should produce colorschemed badges', async function() {
const { stdout } = await runCli(['cactus', 'grown', ':green'])
expect(stdout).to.satisfy(isSvg)
})
it('should produce right-color badges', async function() {
const { stdout } = await runCli(['cactus', 'grown', '#abcdef'])
expect(stdout)
.to.satisfy(isSvg)
.and.to.include('#abcdef')
})
it('should produce PNG badges', async function() {
const child = runCli(['cactus', 'grown', '.png'])
// The buffering done by `child-process-promise` doesn't seem correctly to
// handle binary data.
let chunk
child.childProcess.stdout.once('data', data => {
chunk = data
})
await child
expect(chunk).to.satisfy(isPng)
})
})

34
gh-badges/lib/index.js Normal file
View File

@@ -0,0 +1,34 @@
'use strict'
const makeBadge = require('./make-badge')
class BadgeFactory {
constructor(options) {
if (options !== undefined) {
console.error(
'BadgeFactory: Constructor options are deprecated and will be ignored'
)
}
}
/**
* Create a badge
*
* @param {object} format - Object specifying badge data
* @param {string[]} format.text
* @param {string} format.colorscheme
* @param {string} format.colorA
* @param {string} format.colorB
* @param {string} format.format
* @param {string} format.template
* @return {string} Badge in SVG or JSON format
* @see https://github.com/badges/shields/tree/master/gh-badges/README.md
*/
create(format) {
return makeBadge(format)
}
}
module.exports = {
BadgeFactory,
}

View File

@@ -0,0 +1,20 @@
'use strict'
const { expect } = require('chai')
const { BadgeFactory } = require('./index')
const isSvg = require('is-svg')
const bf = new BadgeFactory()
describe('BadgeFactory class', function() {
it('should produce badge with valid input', function() {
expect(
bf.create({
text: ['build', 'passed'],
format: 'svg',
colorscheme: 'green',
template: 'flat',
})
).to.satisfy(isSvg)
})
})

138
gh-badges/lib/lru-cache.js Normal file
View File

@@ -0,0 +1,138 @@
'use strict'
// In-memory KV, remove the oldest data when the capacity is reached.
const typeEnum = {
unit: 0,
heap: 1,
}
function CacheSlot(key, value) {
this.key = key
this.value = value
this.older = null // Newest slot that is older than this slot.
this.newer = null // Oldest slot that is newer than this slot.
}
function Cache(capacity, type) {
if (!(this instanceof Cache)) {
return new Cache(capacity, type)
}
type = type || 'unit'
this.capacity = capacity
this.type = typeEnum[type]
this.cache = new Map() // Maps cache keys to CacheSlots.
this.newest = null // Newest slot in the cache.
this.oldest = null
}
Cache.prototype = {
set: function addToCache(cacheKey, cached) {
let slot = this.cache.get(cacheKey)
if (slot === undefined) {
slot = new CacheSlot(cacheKey, cached)
this.cache.set(cacheKey, slot)
}
this.makeNewest(slot)
const numItemsToRemove = this.limitReached()
if (numItemsToRemove > 0) {
for (let i = 0; i < numItemsToRemove; i++) {
this.removeOldest()
}
}
},
get: function getFromCache(cacheKey) {
const slot = this.cache.get(cacheKey)
if (slot !== undefined) {
this.makeNewest(slot)
return slot.value
}
},
has: function hasInCache(cacheKey) {
return this.cache.has(cacheKey)
},
makeNewest: function makeNewestSlot(slot) {
const previousNewest = this.newest
if (previousNewest === slot) {
return
}
const older = slot.older
const newer = slot.newer
if (older !== null) {
older.newer = newer
} else if (newer !== null) {
this.oldest = newer
}
if (newer !== null) {
newer.older = older
}
this.newest = slot
if (previousNewest !== null) {
slot.older = previousNewest
slot.newer = null
previousNewest.newer = slot
} else {
// If previousNewest is null, the cache used to be empty.
this.oldest = slot
}
},
removeOldest: function removeOldest() {
const cacheKey = this.oldest.key
if (this.oldest !== null) {
this.oldest = this.oldest.newer
if (this.oldest !== null) {
this.oldest.older = null
}
}
this.cache.delete(cacheKey)
},
// Returns the number of elements to remove if we're past the limit.
limitReached: function heuristic() {
if (this.type === typeEnum.unit) {
// Remove the excess.
return Math.max(0, this.cache.size - this.capacity)
} else if (this.type === typeEnum.heap) {
if (getHeapSize() >= this.capacity) {
console.log('LRU HEURISTIC heap:', getHeapSize())
// Remove half of them.
return this.cache.size >> 1
} else {
return 0
}
} else {
console.error(`Unknown heuristic '${this.type}' for LRU cache.`)
return 1
}
},
clear: function() {
this.cache.clear()
this.newest = null
this.oldest = null
},
}
// In bytes.
let heapSize
let heapSizeTimeout
function getHeapSize() {
if (heapSizeTimeout == null) {
// Compute the heap size every 60 seconds.
heapSizeTimeout = setInterval(computeHeapSize, 60 * 1000)
return computeHeapSize()
} else {
return heapSize
}
}
function computeHeapSize() {
return (heapSize = process.memoryUsage().heapTotal)
}
module.exports = Cache

View File

@@ -0,0 +1,139 @@
'use strict'
const { expect } = require('chai')
const LRU = require('./lru-cache')
function expectCacheSlots(cache, keys) {
expect(cache.cache.size).to.equal(keys.length)
const slots = keys.map(k => cache.cache.get(k))
const first = slots[0]
const last = slots.slice(-1)[0]
expect(cache.oldest).to.equal(first)
expect(cache.newest).to.equal(last)
expect(first.older).to.be.null
expect(last.newer).to.be.null
for (let i = 0; i + 1 < slots.length; ++i) {
const current = slots[i]
const next = slots[i + 1]
expect(current.newer).to.equal(next)
expect(next.older).to.equal(current)
}
}
describe('The LRU cache', function() {
it('should support being called without new', function() {
const cache = LRU(1)
expect(cache).to.be.an.instanceof(LRU)
})
it('should support a zero capacity', function() {
const cache = new LRU(0)
cache.set('key', 'value')
expect(cache.cache.size).to.equal(0)
})
it('should support a one capacity', function() {
const cache = new LRU(1)
cache.set('key1', 'value1')
expectCacheSlots(cache, ['key1'])
cache.set('key2', 'value2')
expectCacheSlots(cache, ['key2'])
expect(cache.get('key1')).to.be.undefined
expect(cache.get('key2')).to.equal('value2')
})
it('should remove the oldest element when reaching capacity', function() {
const cache = new LRU(2)
cache.set('key1', 'value1')
cache.set('key2', 'value2')
cache.set('key3', 'value3')
cache.cache.get('key1')
expectCacheSlots(cache, ['key2', 'key3'])
expect(cache.cache.get('key1')).to.be.undefined
expect(cache.get('key1')).to.be.undefined
expect(cache.get('key2')).to.equal('value2')
expect(cache.get('key3')).to.equal('value3')
})
it('should make sure that resetting a key in cache makes it newest', function() {
const cache = new LRU(2)
cache.set('key', 'value')
cache.set('key2', 'value2')
expectCacheSlots(cache, ['key', 'key2'])
cache.set('key', 'value')
expectCacheSlots(cache, ['key2', 'key'])
})
describe('getting a key in the cache', function() {
context('when the requested key is oldest', function() {
it('should leave the keys in the expected order', function() {
const cache = new LRU(2)
cache.set('key1', 'value1')
cache.set('key2', 'value2')
expectCacheSlots(cache, ['key1', 'key2'])
expect(cache.get('key1')).to.equal('value1')
expectCacheSlots(cache, ['key2', 'key1'])
})
})
context('when the requested key is newest', function() {
it('should leave the keys in the expected order', function() {
const cache = new LRU(2)
cache.set('key1', 'value1')
cache.set('key2', 'value2')
expect(cache.get('key2')).to.equal('value2')
expectCacheSlots(cache, ['key1', 'key2'])
})
})
context('when the requested key is in the middle', function() {
it('should leave the keys in the expected order', function() {
const cache = new LRU(3)
cache.set('key1', 'value1')
cache.set('key2', 'value2')
cache.set('key3', 'value3')
expectCacheSlots(cache, ['key1', 'key2', 'key3'])
expect(cache.get('key2')).to.equal('value2')
expectCacheSlots(cache, ['key1', 'key3', 'key2'])
})
})
})
it('should clear', function() {
// Set up.
const cache = new LRU(2)
cache.set('key1', 'value1')
cache.set('key2', 'value2')
// Confidence check.
expect(cache.get('key1')).to.equal('value1')
expect(cache.get('key2')).to.equal('value2')
// Run.
cache.clear()
// Test.
expect(cache.get('key1')).to.be.undefined
expect(cache.get('key2')).to.be.undefined
expect(cache.cache.size).to.equal(0)
})
})

192
gh-badges/lib/make-badge.js Normal file
View File

@@ -0,0 +1,192 @@
'use strict'
const fs = require('fs')
const path = require('path')
const SVGO = require('svgo')
const dot = require('dot')
const anafanafo = require('anafanafo')
const isCSSColor = require('is-css-color')
// cache templates.
const templates = {}
const templateFiles = fs.readdirSync(path.join(__dirname, '..', 'templates'))
dot.templateSettings.strip = false // Do not strip whitespace.
templateFiles.forEach(async filename => {
if (filename[0] === '.') {
return
}
const templateData = fs
.readFileSync(path.join(__dirname, '..', 'templates', filename))
.toString()
const extension = path.extname(filename).slice(1)
const style = filename.slice(0, -`-template.${extension}`.length)
// Compile the template. Necessary to always have a working template.
templates[`${style}-${extension}`] = dot.template(templateData)
if (extension === 'svg') {
// Substitute dot code.
const mapping = new Map()
let mappingIndex = 1
const untemplatedSvg = templateData.replace(/{{.*?}}/g, match => {
// Weird substitution that currently works for all templates.
const mapKey = `99999990${mappingIndex}.1`
mappingIndex++
mapping.set(mapKey, match)
return mapKey
})
const svgo = new SVGO()
const { data, error } = await svgo.optimize(untemplatedSvg)
if (error !== undefined) {
console.error(
`Template ${filename}: ${error}\n` +
' Generated untemplated SVG:\n' +
`---\n${untemplatedSvg}---\n`
)
return
}
// Substitute dot code back.
let svg = data
const unmappedKeys = []
mapping.forEach((value, key) => {
let keySubstituted = false
svg = svg.replace(RegExp(key, 'g'), () => {
keySubstituted = true
return value
})
if (!keySubstituted) {
unmappedKeys.push(key)
}
})
if (unmappedKeys.length > 0) {
console.error(
`Template ${filename} has unmapped keys ` +
`${unmappedKeys.join(', ')}.\n` +
' Generated untemplated SVG:\n' +
`---\n${untemplatedSvg}\n---\n` +
' Generated template:\n' +
`---\n${svg}\n---\n`
)
return
}
templates[`${style}-${extension}`] = dot.template(svg)
}
})
function escapeXml(s) {
if (s === undefined || typeof s !== 'string') {
return undefined
} else {
return s
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
}
}
function capitalize(s) {
return s.charAt(0).toUpperCase() + s.slice(1)
}
// check if colorA/B is a colorscheme else check if it's a valid css3 color else return undefined and let the badge assign the default color
function assignColor(color = '', colorschemeType = 'colorB') {
if (definedColorschemes[color] !== undefined) {
return definedColorschemes[color][colorschemeType] || undefined
} else if (isCSSColor(color)) {
return color
} else {
return undefined
}
}
const definedColorschemes = require(path.join(__dirname, 'colorscheme.json'))
function makeBadge({
format,
template,
text,
colorscheme,
colorA,
colorB,
logo,
logoPosition,
logoWidth,
links = ['', ''],
}) {
// String coercion.
text = text.map(value => `${value}`)
if (format !== 'json') {
format = 'svg'
}
if (!(`${template}-${format}` in templates)) {
template = format === 'svg' ? 'flat' : 'default'
}
if (template.startsWith('popout')) {
if (logo) {
logoPosition =
logoPosition <= 10 && logoPosition >= -10 ? logoPosition : 0
logoWidth = +logoWidth || 32
} else {
template = template.replace('popout', 'flat')
}
}
if (template === 'social') {
text[0] = capitalize(text[0])
} else if (template === 'for-the-badge') {
text = text.map(value => value.toUpperCase())
}
// colorA/B have a higher priority than colorscheme
colorA = colorA || colorscheme || undefined
colorB = colorB || colorscheme || undefined
colorA = assignColor(colorA, 'colorA')
colorB = assignColor(colorB, 'colorB')
const [left, right] = text
let leftWidth = (anafanafo(left) / 10) | 0
// Increase chances of pixel grid alignment.
if (leftWidth % 2 === 0) {
leftWidth++
}
let rightWidth = (anafanafo(right) / 10) | 0
// Increase chances of pixel grid alignment.
if (rightWidth % 2 === 0) {
rightWidth++
}
logoWidth = +logoWidth || (logo ? 14 : 0)
let logoPadding
if (left.length === 0) {
logoPadding = 0
} else {
logoPadding = logo ? 3 : 0
}
const context = {
text: [left, right],
escapedText: text.map(escapeXml),
widths: [leftWidth + 10 + logoWidth + logoPadding, rightWidth + 10],
links: links.map(escapeXml),
logo,
logoPosition,
logoWidth,
logoPadding,
colorA,
colorB,
escapeXml,
}
const templateFn = templates[`${template}-${format}`]
// The call to template() can raise an exception.
return templateFn(context)
}
module.exports = makeBadge

View File

@@ -0,0 +1,210 @@
'use strict'
const { test, given, forCases } = require('sazerac')
const { expect } = require('chai')
const snapshot = require('snap-shot-it')
const eol = require('eol')
const isSvg = require('is-svg')
const makeBadge = require('./make-badge')
const colorschemes = require('./colorscheme.json')
function testColor(color = '') {
return JSON.parse(
makeBadge({
text: ['name', 'Bob'],
colorB: color,
format: 'json',
template: '_shields_test',
})
).colorB
}
describe('The badge generator', function() {
describe('color test', function() {
test(testColor, () => {
// valid hex
given('#4c1').expect('#4c1')
given('#4C1').expect('#4C1')
given('#abc123').expect('#abc123')
given('#ABC123').expect('#ABC123')
// valid rgb(a)
given('rgb(0,128,255)').expect('rgb(0,128,255)')
given('rgba(0,128,255,0)').expect('rgba(0,128,255,0)')
// valid hsl(a)
given('hsl(100, 56%, 10%)').expect('hsl(100, 56%, 10%)')
given('hsla(25,20%,0%,0.1)').expect('hsla(25,20%,0%,0.1)')
// either a css named color or colorscheme
given('papayawhip').expect('papayawhip')
given('red').expect(colorschemes['red'].colorB)
given('green').expect(colorschemes['green'].colorB)
given('blue').expect(colorschemes['blue'].colorB)
given('yellow').expect(colorschemes['yellow'].colorB)
forCases(
// invalid hex
given('#123red'), // contains letter above F
given('#red'), // contains letter above F
given('123456'), // contains no # symbol
given('123'), // contains no # symbol
// invalid rgb(a)
given('rgb(220,128,255,0.5)'), // has alpha
given('rgba(0,0,255)'), // no alpha
// invalid hsl(a)
given('hsl(360,50%,50%,0.5)'), // has alpha
given('hsla(0,50%,101%)'), // no alpha
// neither a css named color nor colorscheme
given('notacolor'),
given('bluish'),
given('almostred'),
given('brightmaroon'),
given('cactus')
).expect(undefined)
})
})
describe('SVG', function() {
it('should produce SVG', function() {
const svg = makeBadge({ text: ['cactus', 'grown'], format: 'svg' })
expect(svg)
.to.satisfy(isSvg)
.and.to.include('cactus')
.and.to.include('grown')
})
it('should always produce the same SVG (unless we have changed something!)', function() {
const svg = makeBadge({ text: ['cactus', 'grown'], format: 'svg' })
snapshot(svg)
})
})
describe('JSON', function() {
it('should always produce the same JSON (unless we have changed something!)', function() {
const json = makeBadge({ text: ['cactus', 'grown'], format: 'json' })
const jsonWithLFEndings = eol.lf(json)
snapshot(jsonWithLFEndings)
})
it('should replace unknown json template with "default"', function() {
const jsonBadgeWithUnknownStyle = makeBadge({
text: ['name', 'Bob'],
format: 'json',
template: 'unknown_style',
})
const jsonBadgeWithDefaultStyle = makeBadge({
text: ['name', 'Bob'],
format: 'json',
template: 'default',
})
expect(jsonBadgeWithUnknownStyle).to.equal(jsonBadgeWithDefaultStyle)
expect(JSON.parse(jsonBadgeWithUnknownStyle)).to.deep.equal({
name: 'name',
value: 'Bob',
})
})
it('should replace unknown svg template with "flat"', function() {
const jsonBadgeWithUnknownStyle = makeBadge({
text: ['name', 'Bob'],
format: 'svg',
template: 'unknown_style',
})
const jsonBadgeWithDefaultStyle = makeBadge({
text: ['name', 'Bob'],
format: 'svg',
template: 'flat',
})
expect(jsonBadgeWithUnknownStyle)
.to.equal(jsonBadgeWithDefaultStyle)
.and.to.satisfy(isSvg)
})
})
describe('"for-the-badge" template badge generation', function() {
// https://github.com/badges/shields/issues/1280
it('numbers should produce a string', function() {
const svg = makeBadge({
text: [1998, 1999],
format: 'svg',
template: 'for-the-badge',
})
expect(svg)
.to.include('1998')
.and.to.include('1999')
})
it('lowercase/mixedcase string should produce uppercase string', function() {
const svg = makeBadge({
text: ['Label', '1 string'],
format: 'svg',
template: 'for-the-badge',
})
expect(svg)
.to.include('LABEL')
.and.to.include('1 STRING')
})
})
describe('"social" template badge generation', function() {
it('should produce capitalized string for badge key', function() {
const svg = makeBadge({
text: ['some-key', 'some-value'],
format: 'svg',
template: 'social',
})
expect(svg)
.to.include('Some-key')
.and.to.include('some-value')
})
// https://github.com/badges/shields/issues/1606
it('should handle empty strings used as badge keys', function() {
const svg = makeBadge({
text: ['', 'some-value'],
format: 'json',
template: 'social',
})
expect(svg)
.to.include('""')
.and.to.include('some-value')
})
})
describe('badges with logos should always produce the same badge', function() {
it('shields GitHub logo default color (#333333)', function() {
const svg = makeBadge({
text: ['label', 'message'],
format: 'svg',
logo: 'github',
})
snapshot(svg)
})
it('shields GitHub logo custom color (whitesmoke)', function() {
const svg = makeBadge({
text: ['label', 'message'],
format: 'svg',
logo: 'github',
logoColor: 'whitesmoke',
})
snapshot(svg)
})
it('simple-icons javascript logo default color (#F7DF1E)', function() {
const svg = makeBadge({
text: ['label', 'message'],
format: 'svg',
logo: 'javascript',
})
snapshot(svg)
})
it('simple-icons javascript logo custom color (rgba(46,204,113,0.8))', function() {
const svg = makeBadge({
text: ['label', 'message'],
format: 'svg',
logo: 'javascript',
logoColor: 'rgba(46,204,113,0.8)',
})
snapshot(svg)
})
})
})

View File

@@ -0,0 +1,39 @@
'use strict'
const { promisify } = require('util')
const gm = require('gm')
const LruCache = require('./lru-cache')
const imageMagick = gm.subClass({ imageMagick: true })
// The following is an arbitrary limit (~1.5MB, 1.5kB/image).
const imgCache = new LruCache(1000)
async function svgToImg(svg, format) {
const cacheIndex = `${format}${svg}`
if (imgCache.has(cacheIndex)) {
return imgCache.get(cacheIndex)
}
const svgBuffer = Buffer.from(
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>${svg}`
)
const chain = imageMagick(svgBuffer, `image.${format}`)
.density(90)
.background(format === 'jpg' ? '#FFFFFF' : 'none')
.flatten()
const toBuffer = chain.toBuffer.bind(chain)
const data = await promisify(toBuffer)(format)
imgCache.set(cacheIndex, data)
return data
}
module.exports = svgToImg
// To simplify testing.
module.exports._imgCache = imgCache
module.exports._imageMagick = imageMagick

View File

@@ -0,0 +1,33 @@
'use strict'
const { expect } = require('chai')
const isPng = require('is-png')
const sinon = require('sinon')
const svg2img = require('./svg-to-img')
const makeBadge = require('./make-badge')
describe('The rasterizer', function() {
let cacheGet
beforeEach(function() {
cacheGet = sinon.spy(svg2img._imgCache, 'get')
})
afterEach(function() {
cacheGet.restore()
})
it('should produce PNG', async function() {
const svg = makeBadge({ text: ['cactus', 'grown'], format: 'svg' })
const data = await svg2img(svg, 'png')
expect(data).to.satisfy(isPng)
})
it('should cache its results', async function() {
const svg = makeBadge({ text: ['will-this', 'be-cached?'], format: 'svg' })
const data1 = await svg2img(svg, 'png')
expect(data1).to.satisfy(isPng)
expect(cacheGet).not.to.have.been.called
const data2 = await svg2img(svg, 'png')
expect(data2).to.satisfy(isPng)
expect(cacheGet).to.have.been.calledOnce
})
})

45
gh-badges/package.json Normal file
View File

@@ -0,0 +1,45 @@
{
"name": "gh-badges",
"version": "2.1.0",
"description": "Shields.io badge library",
"keywords": [
"GitHub",
"badge",
"SVG",
"image",
"shields.io"
],
"main": "lib/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/badges/shields.git"
},
"author": "Thaddée Tyl <thaddee.tyl@gmail.com>",
"license": "CC0-1.0",
"bugs": {
"url": "https://github.com/badges/shields/issues"
},
"homepage": "http://shields.io",
"bin": {
"badge": "lib/badge-cli.js"
},
"engines": {
"node": ">= 8",
"npm": ">= 5"
},
"collective": {
"type": "opencollective",
"url": "https://opencollective.com/shields",
"logo": "https://opencollective.com/opencollective/logo.txt"
},
"dependencies": {
"anafanafo": "^0.1.0",
"dot": "~1.1.2",
"gm": "^1.23.0",
"is-css-color": "^1.0.0",
"svgo": "~1.1.1"
},
"scripts": {
"test": "echo 'Run tests from parent dir'; false"
}
}

View File

@@ -0,0 +1,10 @@
{
{{?it.colorA}}
"colorA": {{=JSON.stringify(it.colorA)}},
{{?}}
{{?it.colorB}}
"colorB": {{=JSON.stringify(it.colorB)}},
{{?}}
"name": {{=JSON.stringify(it.text[0])}},
"value": {{=JSON.stringify(it.text[1])}}
}

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{=(it.widths[0] -= it.text[0].length ? 0 : (it.logo ? (it.colorA ? 0 : 7) : 11))+it.widths[1]}}" height="20">
<g shape-rendering="crispEdges">
<rect width="{{=it.widths[0]}}" height="20" fill="{{=it.escapeXml(it.text[0].length || it.logo && it.colorA ? (it.colorA||"#555") : (it.colorB||"#4c1"))}}"/>
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="20" fill="{{=it.escapeXml(it.colorB||"#4c1")}}"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110">
{{?it.logo}}
<image x="5" y="3" width="{{=it.logoWidth}}" height="14" xlink:href="{{=it.logo}}"/>
{{?}}
{{?it.text[0].length}}
<text x="{{=(((it.widths[0]+it.logoWidth+it.logoPadding)/2)+1)*10}}" y="140" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
{{?}}
<text x="{{=(it.widths[0]+it.widths[1]/2-(it.text[0].length ? 1 : 0 ))*10}}" y="140" transform="scale(0.1)" textLength="{{=(it.widths[1]-10)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
</g>
{{?(it.links[0] && it.links[0].length)}}
<a target="_blank" xlink:href="{{=it.links[0]}}">
<rect width="{{=it.widths[0]}}" height="20" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
{{?(it.links[0] && it.links[0].length || it.links[1] && it.links[1].length)}}
<a target="_blank" xlink:href="{{=it.links[1] || it.links[0]}}">
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="20" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,39 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{=(it.widths[0] -= it.text[0].length ? 0 : (it.logo ? (it.colorA ? 0 : 7) : 11))+it.widths[1]}}" height="20">
<linearGradient id="smooth" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<clipPath id="round">
<rect width="{{=it.widths[0]+it.widths[1]}}" height="20" rx="3" fill="#fff"/>
</clipPath>
<g clip-path="url(#round)">
<rect width="{{=it.widths[0]}}" height="20" fill="{{=it.escapeXml(it.text[0].length || it.logo && it.colorA ? (it.colorA||"#555") : (it.colorB||"#4c1"))}}"/>
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="20" fill="{{=it.escapeXml(it.colorB||"#4c1")}}"/>
<rect width="{{=it.widths[0]+it.widths[1]}}" height="20" fill="url(#smooth)"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110">
{{?it.logo}}
<image x="5" y="3" width="{{=it.logoWidth}}" height="14" xlink:href="{{=it.logo}}"/>
{{?}}
{{?it.text[0].length}}
<text x="{{=(((it.widths[0]+it.logoWidth+it.logoPadding)/2)+1)*10}}" y="150" fill="#010101" fill-opacity=".3" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
<text x="{{=(((it.widths[0]+it.logoWidth+it.logoPadding)/2)+1)*10}}" y="140" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
{{?}}
<text x="{{=(it.widths[0]+it.widths[1]/2-(it.text[0].length ? 1 : 0 ))*10}}" y="150" fill="#010101" fill-opacity=".3" transform="scale(0.1)" textLength="{{=(it.widths[1]-10)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
<text x="{{=(it.widths[0]+it.widths[1]/2-(it.text[0].length ? 1 : 0 ))*10}}" y="140" transform="scale(0.1)" textLength="{{=(it.widths[1]-10)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
</g>
{{?(it.links[0] && it.links[0].length)}}
<a target="_blank" xlink:href="{{=it.links[0]}}">
<rect width="{{=it.widths[0]}}" height="20" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
{{?(it.links[0] && it.links[0].length || it.links[1] && it.links[1].length)}}
<a target="_blank" xlink:href="{{=it.links[1] || it.links[0]}}">
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="20" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{=(it.widths[0] -= it.text[0].length ? -(10+(it.text[0].length*1.5)) : (it.logo ? (it.colorA ? -7 : 7) : 11))+(it.widths[1]+=(10+(it.text[1].length*2)))}}" height="28">
<g shape-rendering="crispEdges">
<rect width="{{=it.widths[0]}}" height="28" fill="{{=it.escapeXml(it.text[0].length || it.logo && it.colorA ? (it.colorA||"#555") : (it.colorB||"#4c1"))}}"/>
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="28" fill="{{=it.escapeXml(it.colorB||"#4c1")}}"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="100">
{{?it.logo}}
<image x="9" y="7" width="{{=it.logoWidth}}" height="14" xlink:href="{{=it.logo}}"/>
{{?}}
{{?it.text[0].length}}
<text x="{{=((it.widths[0]+it.logoWidth+it.logoPadding)/2)*10}}" y="175" transform="scale(0.1)" textLength="{{=(it.widths[0]-(24+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
{{?}}
<text x="{{=(it.widths[0]+it.widths[1]/2)*10}}" y="175" font-weight="bold" transform="scale(0.1)" textLength="{{=(it.widths[1]-24)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
</g>
{{?(it.text[0].length && it.links[0] && it.links[0].length)}}
<a target="_blank" xlink:href="{{=it.links[0]}}">
<rect width="{{=it.widths[0]}}" height="28" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
{{?(it.links[0] && it.links[0].length || it.links[1] && it.links[1].length)}}
<a target="_blank" xlink:href="{{=it.links[1] || it.links[0]}}">
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="28" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,41 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{=(it.widths[0] -= it.text[0].length ? 0 : (it.logo ? (it.colorA ? 0 : 7) : 11))+it.widths[1]}}" height="18">
<linearGradient id="smooth" x2="0" y2="100%">
<stop offset="0" stop-color="#fff" stop-opacity=".7"/>
<stop offset=".1" stop-color="#aaa" stop-opacity=".1"/>
<stop offset=".9" stop-color="#000" stop-opacity=".3"/>
<stop offset="1" stop-color="#000" stop-opacity=".5"/>
</linearGradient>
<clipPath id="round">
<rect width="{{=it.widths[0]+it.widths[1]}}" height="18" rx="4" fill="#fff"/>
</clipPath>
<g clip-path="url(#round)">
<rect width="{{=it.widths[0]}}" height="18" fill="{{=it.escapeXml(it.text[0].length || it.logo && it.colorA ? (it.colorA||"#555") : (it.colorB||"#4c1"))}}"/>
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="18" fill="{{=it.escapeXml(it.colorB||"#4c1")}}"/>
<rect width="{{=it.widths[0]+it.widths[1]}}" height="18" fill="url(#smooth)"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110">
{{?it.logo}}
<image x="5" y="3" width="{{=it.logoWidth}}" height="14" xlink:href="{{=it.logo}}"/>
{{?}}
{{?it.text[0].length}}
<text x="{{=(((it.widths[0]+it.logoWidth+it.logoPadding)/2)+1)*10}}" y="140" fill="#010101" fill-opacity=".3" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
<text x="{{=(((it.widths[0]+it.logoWidth+it.logoPadding)/2)+1)*10}}" y="130" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
{{?}}
<text x="{{=(it.widths[0]+it.widths[1]/2-(it.text[0].length ? 1 : 0))*10}}" y="140" fill="#010101" fill-opacity=".3" transform="scale(0.1)" textLength="{{=(it.widths[1]-10)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
<text x="{{=(it.widths[0]+it.widths[1]/2-(it.text[0].length ? 1 : 0))*10}}" y="130" transform="scale(0.1)" textLength="{{=(it.widths[1]-10)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
</g>
{{?(it.links[0] && it.links[0].length)}}
<a target="_blank" xlink:href="{{=it.links[0]}}">
<rect width="{{=it.widths[0]}}" height="18" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
{{?(it.links[0] && it.links[0].length || it.links[1] && it.links[1].length)}}
<a target="_blank" xlink:href="{{=it.links[1] || it.links[0]}}">
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="18" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{=(it.widths[0] -= it.text[0].length ? 0 : (it.logo ? (it.colorA ? 0 : 6) : 11))+it.widths[1]}}" height="40">
<g shape-rendering="crispEdges">
<rect width="{{=it.widths[0]}}" y="{{=10-it.logoPosition}}" height="20" fill="{{=it.escapeXml(it.text[0].length || it.logo && it.colorA ? (it.colorA||"#555") : (it.colorB||"#4c1"))}}"/>
<rect x="{{=it.widths[0]}}" y="{{=10-it.logoPosition}}" width="{{=it.widths[1]}}" height="20" fill="{{=it.escapeXml(it.colorB||"#4c1")}}"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110">
{{?it.logo}}
<image x="5" y="3" width="{{=it.logoWidth}}" height="32" xlink:href="{{=it.logo}}"/>
{{?}}
<text x="{{=(((it.widths[0]+it.logoWidth+it.logoPadding)/2)+1)*10}}" y="{{=(24-it.logoPosition)*10}}" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
<text x="{{=(it.widths[0]+it.widths[1]/2-1)*10}}" y="{{=(24-it.logoPosition)*10}}" transform="scale(0.1)" textLength="{{=(it.widths[1]-10)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
</g>
{{?(it.links[0] && it.links[0].length)}}
<a xlink:href="{{=it.links[0]}}">
<rect width="{{=it.widths[0]}}" height="40" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
{{?(it.links[0] && it.links[0].length || it.links[1] && it.links[1].length)}}
<a xlink:href="{{=it.links[1] || it.links[0]}}">
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="40" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,37 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{=(it.widths[0] -= it.text[0].length ? 0 : (it.logo ? (it.colorA ? 0 : 6) : 11))+it.widths[1]}}" height="40">
<linearGradient id="smooth" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<clipPath id="round">
<rect width="{{=it.widths[0]+it.widths[1]}}" y="{{=10-it.logoPosition}}" height="20" rx="3" fill="#fff"/>
</clipPath>
<g clip-path="url(#round)">
<rect width="{{=it.widths[0]}}" y="{{=10-it.logoPosition}}" height="20" fill="{{=it.escapeXml(it.text[0].length || it.logo && it.colorA ? (it.colorA||"#555") : (it.colorB||"#4c1"))}}"/>
<rect x="{{=it.widths[0]}}" y="{{=10-it.logoPosition}}" width="{{=it.widths[1]}}" height="20" fill="{{=it.escapeXml(it.colorB||"#4c1")}}"/>
<rect width="{{=it.widths[0]+it.widths[1]}}" y="{{=10-it.logoPosition}}" height="20" fill="url(#smooth)"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110">
{{?it.logo}}
<image x="5" y="3" width="{{=it.logoWidth}}" height="32" xlink:href="{{=it.logo}}"/>
{{?}}
<text x="{{=(((it.widths[0]+it.logoWidth+it.logoPadding)/2)+1)*10}}" y="{{=(25-it.logoPosition)*10}}" fill="#010101" fill-opacity=".3" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
<text x="{{=(((it.widths[0]+it.logoWidth+it.logoPadding)/2)+1)*10}}" y="{{=(24-it.logoPosition)*10}}" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
<text x="{{=(it.widths[0]+it.widths[1]/2-1)*10}}" y="{{=(25-it.logoPosition)*10}}" fill="#010101" fill-opacity=".3" transform="scale(0.1)" textLength="{{=(it.widths[1]-10)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
<text x="{{=(it.widths[0]+it.widths[1]/2-1)*10}}" y="{{=(24-it.logoPosition)*10}}" transform="scale(0.1)" textLength="{{=(it.widths[1]-10)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
</g>
{{?(it.links[0] && it.links[0].length)}}
<a xlink:href="{{=it.links[0]}}">
<rect width="{{=it.widths[0]}}" height="40" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
{{?(it.links[0] && it.links[0].length || it.links[1] && it.links[1].length)}}
<a xlink:href="{{=it.links[1] || it.links[0]}}">
<rect x="{{=it.widths[0]}}" width="{{=it.widths[1]}}" height="40" fill="rgba(0,0,0,0)"/>
</a>
{{?}}
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,39 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{=it.widths[0]+1 + (it.text[1] && it.text[1].length > 0 ? it.widths[1]+2 : 0)}}" height="20">
{{it.widths[1]-=4;}}
<style type="text/css"><![CDATA[
a #llink:hover { fill:url(#b); stroke:#ccc; }
a #rlink:hover { fill:#4183C4; }
]]></style>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-color="#fcfcfc" stop-opacity="0"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#ccc" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<g stroke="#d5d5d5">
<rect stroke="none" fill="#fcfcfc" x="0.5" y="0.5" width="{{=it.widths[0]}}" height="19" rx="2"/>
{{?(it.text[1] && it.text[1].length)}}
<rect y="0.5" x="{{=it.widths[0]+6.5}}" width="{{=it.widths[1]}}" height="19" rx="2" fill="#fafafa"/>
<rect x="{{=it.widths[0]+6}}" y="7.5" width="0.5" height="5" stroke="#fafafa"/>
<path d="M{{=it.widths[0]+6.5}} 6.5 l-3 3v1 l3 3" stroke="d5d5d5" fill="#fafafa"/>
{{?}}
</g>
{{?it.logo}}
<image x="5" y="3" width="{{=it.logoWidth}}" height="14" xlink:href="{{=it.logo}}"/>
{{?}}
<g fill="#333" text-anchor="middle" font-family="Helvetica Neue,Helvetica,Arial,sans-serif" font-weight="700" font-size="110px" line-height="14px">
<text x="{{=((it.widths[0]+it.logoWidth+it.logoPadding)/2)*10}}" y="150" fill="#fff" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
<text x="{{=((it.widths[0]+it.logoWidth+it.logoPadding)/2)*10}}" y="140" transform="scale(0.1)" textLength="{{=(it.widths[0]-(10+it.logoWidth+it.logoPadding))*10}}" lengthAdjust="spacing">{{=it.escapedText[0]}}</text>
{{?(it.text[1] && it.text[1].length)}}
<text x="{{=(it.widths[0]+it.widths[1]/2+6)*10}}" y="150" fill="#fff" transform="scale(0.1)" textLength="{{=(it.widths[1]-8)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
{{?(it.links[0] && it.links[0].length || it.links[1] && it.links[1].length)}}<a target="_blank" xlink:href="{{=it.links[1] || it.links[0]}}">{{?}}
<text id="rlink" x="{{=(it.widths[0]+it.widths[1]/2+6)*10}}" y="140" transform="scale(0.1)" textLength="{{=(it.widths[1]-8)*10}}" lengthAdjust="spacing">{{=it.escapedText[1]}}</text>
{{?(it.links[0] && it.links[0].length || it.links[1] && it.links[1].length)}}</a>{{?}}
{{?}}
</g>
{{?(it.links[0] && it.links[0].length)}}<a target="_blank" xlink:href="{{=it.links[0]}}">{{?}}
<rect id="llink" stroke="#d5d5d5" fill="url(#a)" x="0.5" y="0.5" width="{{=it.widths[0]}}" height="19" rx="2"/>
{{?(it.links[0] && it.links[0].length)}}</a>{{?}}
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

1409
index.html

File diff suppressed because it is too large Load Diff

454
lib/all-badge-examples.js Normal file
View File

@@ -0,0 +1,454 @@
'use strict'
const { loadServiceClasses } = require('../services')
const allBadgeExamples = [
{
category: {
id: 'build',
name: 'Build',
},
examples: [],
},
{
category: {
id: 'chat',
name: 'Chat',
},
examples: [],
},
{
category: {
id: 'dependencies',
name: 'Dependencies',
},
examples: [],
},
{
category: {
id: 'size',
name: 'Size',
},
examples: [],
},
{
category: {
id: 'downloads',
name: 'Downloads',
},
examples: [
{
title: 'Chocolatey',
previewUrl: '/chocolatey/dt/scriptcs.svg',
},
{
title: 'NuGet',
previewUrl: '/nuget/dt/Microsoft.AspNetCore.Mvc.svg',
},
{
title: 'MyGet',
previewUrl: '/myget/mongodb/dt/MongoDB.Driver.Core.svg',
},
{
title: 'MyGet tenant',
previewUrl:
'/dotnet.myget/dotnet-coreclr/dt/Microsoft.DotNet.CoreCLR.svg',
},
{
title: 'PowerShell Gallery',
previewUrl: '/powershellgallery/dt/ACMESharp.svg',
},
{
title: 'Crates.io',
previewUrl: '/crates/d/rustc-serialize.svg',
keywords: ['Rust'],
},
{
title: 'Crates.io',
previewUrl: '/crates/dv/rustc-serialize.svg',
keywords: ['Rust'],
},
{
title: 'Puppet Forge',
previewUrl: '/puppetforge/dt/camptocamp/openldap.svg',
},
{
title: 'Mozilla Add-on',
previewUrl: '/amo/d/dustman.svg',
keywords: ['amo', 'firefox'],
},
{
title: 'Visual Studio Marketplace',
previewUrl: '/vscode-marketplace/d/ritwickdey.LiveServer.svg',
keywords: ['vscode-marketplace'],
},
{
title: 'JetBrains ReSharper plugins',
previewUrl: '/resharper/dt/ReSharper.Nuke.svg',
keywords: ['jetbrains', 'plugin'],
},
],
},
{
category: {
id: 'funding',
name: 'Funding',
},
examples: [
{
title: 'Chrome Web Store',
previewUrl:
'/chrome-web-store/price/ogffaloegjglncjfehdfplabnoondfjo.svg',
keywords: ['chrome'],
},
],
},
{
category: {
id: 'issue-tracking',
name: 'Issue Tracking',
},
examples: [],
},
{
category: {
id: 'license',
name: 'License',
},
examples: [
{
title: 'Crates.io',
previewUrl: '/crates/l/rustc-serialize.svg',
keywords: ['Rust'],
},
{
title: 'Packagist',
previewUrl: '/packagist/l/doctrine/orm.svg',
keywords: ['PHP'],
},
{
title: 'Bower',
previewUrl: '/bower/l/bootstrap.svg',
},
{
title: 'CPAN',
previewUrl: '/cpan/l/Config-Augeas.svg',
keywords: ['perl'],
},
{
title: 'CRAN',
previewUrl: '/cran/l/devtools.svg',
keywords: ['R'],
},
{
title: 'DUB',
previewUrl: '/dub/l/vibe-d.svg',
keywords: ['dub'],
},
],
},
{
category: {
id: 'rating',
name: 'Rating',
},
examples: [
{
title: 'Chrome Web Store',
previewUrl:
'/chrome-web-store/rating/ogffaloegjglncjfehdfplabnoondfjo.svg',
keywords: ['chrome'],
},
{
title: 'Chrome Web Store',
previewUrl:
'/chrome-web-store/stars/ogffaloegjglncjfehdfplabnoondfjo.svg',
keywords: ['chrome'],
},
{
title: 'Chrome Web Store',
previewUrl:
'/chrome-web-store/rating-count/ogffaloegjglncjfehdfplabnoondfjo.svg',
keywords: ['chrome'],
},
{
title: 'Mozilla Add-on',
previewUrl: '/amo/rating/dustman.svg',
keywords: ['amo', 'firefox'],
},
{
title: 'Mozilla Add-on',
previewUrl: '/amo/stars/dustman.svg',
keywords: ['amo', 'firefox'],
},
{
title: 'Plugin on redmine.org',
previewUrl:
'/redmine/plugin/rating/redmine_xlsx_format_issue_exporter.svg',
keywords: ['redmine', 'plugin'],
},
{
title: 'Plugin on redmine.org',
previewUrl:
'/redmine/plugin/stars/redmine_xlsx_format_issue_exporter.svg',
keywords: ['redmine', 'plugin'],
},
{
title: 'Vaadin Directory',
previewUrl: '/vaadin-directory/rating/vaadinvaadin-grid.svg',
keywords: ['vaadin-directory', 'vaadin directory', 'rating'],
},
{
title: 'Vaadin Directory',
previewUrl: '/vaadin-directory/stars/vaadinvaadin-grid.svg',
keywords: ['vaadin-directory', 'vaadin directory', 'star', 'stars'],
},
{
title: 'Vaadin Directory',
previewUrl: '/vaadin-directory/rating-count/vaadinvaadin-grid.svg',
keywords: [
'vaadin-directory',
'vaadin directory',
'rating-count',
'rating count',
],
},
{
title: 'Visual Studio Marketplace',
previewUrl: '/vscode-marketplace/r/ritwickdey.LiveServer.svg',
keywords: ['vscode-marketplace'],
},
{
title: 'StackExchange',
previewUrl: '/stackexchange/tex/r/951.svg',
},
],
},
{
category: {
id: 'social',
name: 'Social',
},
examples: [],
},
{
category: {
id: 'version',
name: 'Version',
},
examples: [
{
title: 'LuaRocks',
previewUrl: '/luarocks/v/mpeterv/luacheck.svg',
keywords: ['lua'],
},
{
title: 'Hackage',
previewUrl: '/hackage/v/lens.svg',
},
{
title: 'Crates.io',
previewUrl: '/crates/v/rustc-serialize.svg',
keywords: ['Rust'],
},
{
title: 'Packagist',
previewUrl: '/packagist/v/symfony/symfony.svg',
keywords: ['PHP'],
},
{
title: 'Packagist Pre Release',
previewUrl: '/packagist/vpre/symfony/symfony.svg',
keywords: ['PHP'],
},
{
title: 'NuGet',
previewUrl: '/nuget/v/Nuget.Core.svg',
},
{
title: 'NuGet Pre Release',
previewUrl: '/nuget/vpre/Microsoft.AspNet.Mvc.svg',
},
{
title: 'MyGet',
previewUrl: '/myget/mongodb/v/MongoDB.Driver.Core.svg',
},
{
title: 'MyGet Pre Release',
previewUrl: '/myget/yolodev/vpre/YoloDev.Dnx.FSharp.svg',
},
{
title: 'MyGet tenant',
previewUrl:
'/dotnet.myget/dotnet-coreclr/v/Microsoft.DotNet.CoreCLR.svg',
},
{
title: 'Chocolatey',
previewUrl: '/chocolatey/v/git.svg',
},
{
title: 'PowerShell Gallery',
previewUrl: '/powershellgallery/v/Zyborg.Vault.svg',
},
{
title: 'Puppet Forge',
previewUrl: '/puppetforge/v/vStone/percona.svg',
},
{
title: 'Sonatype Nexus (Releases)',
previewUrl:
'/nexus/r/https/oss.sonatype.org/com.google.guava/guava.svg',
},
{
title: 'Sonatype Nexus (Snapshots)',
previewUrl:
'/nexus/s/https/oss.sonatype.org/com.google.guava/guava.svg',
},
{
title: 'CPAN',
previewUrl: '/cpan/v/Config-Augeas.svg',
keywords: ['perl'],
},
{
title: 'CRAN',
previewUrl: '/cran/v/devtools.svg',
keywords: ['R'],
},
{
title: 'DUB',
previewUrl: '/dub/v/vibe-d.svg',
keywords: ['dub'],
},
{
title: 'Chrome Web Store',
previewUrl: '/chrome-web-store/v/ogffaloegjglncjfehdfplabnoondfjo.svg',
keywords: ['chrome'],
},
{
title: 'Mozilla Add-on',
previewUrl: '/amo/v/dustman.svg',
keywords: ['amo', 'firefox'],
},
{
title: 'Visual Studio Marketplace',
previewUrl: '/vscode-marketplace/v/ritwickdey.LiveServer.svg',
keywords: ['vscode-marketplace'],
},
{
title: 'JetBrains ReSharper Plugins',
previewUrl: '/resharper/v/ReSharper.Nuke.svg',
},
{
title: 'JetBrains ReSharper Plugins Pre-release',
previewUrl: '/resharper/vpre/ReSharper.Nuke.svg',
},
{
title: 'Vaadin Directory',
previewUrl: '/vaadin-directory/v/vaadinvaadin-grid.svg',
keywords: [
'vaadin-directory',
'vaadin directory',
'version',
'latest version',
],
},
],
},
{
category: {
id: 'platform-support',
name: 'Platform & Version Support',
},
examples: [],
},
{
category: {
id: 'monitoring',
name: 'Monitoring',
},
examples: [],
},
{
category: {
id: 'other',
name: 'Other',
},
examples: [
{
title: 'Puppet Forge',
previewUrl: '/puppetforge/e/camptocamp/openssl.svg',
},
{
title: 'Puppet Forge',
previewUrl: '/puppetforge/f/camptocamp/openssl.svg',
},
{
title: 'Puppet Forge',
previewUrl: '/puppetforge/rc/camptocamp.svg',
},
{
title: 'Puppet Forge',
previewUrl: '/puppetforge/mc/camptocamp.svg',
},
{
title: 'Chrome Web Store',
previewUrl:
'/chrome-web-store/users/ogffaloegjglncjfehdfplabnoondfjo.svg',
keywords: ['chrome'],
},
{
title: 'Mozilla Add-on',
previewUrl: '/amo/users/dustman.svg',
keywords: ['amo', 'firefox'],
},
{
title: 'Vaadin Directory',
previewUrl: '/vaadin-directory/status/vaadinvaadin-grid.svg',
keywords: ['vaadin-directory', 'vaadin directory', 'status'],
},
{
title: 'Vaadin Directory',
previewUrl: '/vaadin-directory/release-date/vaadinvaadin-grid.svg',
keywords: [
'vaadin-directory',
'vaadin directory',
'date',
'latest release date',
],
},
{
title: 'StackExchange',
previewUrl: '/stackexchange/stackoverflow/t/augeas.svg',
},
],
},
]
function findCategory(wantedCategory) {
return allBadgeExamples.find(
thisCat => thisCat.category.id === wantedCategory
)
}
function loadExamples() {
loadServiceClasses().forEach(ServiceClass => {
const prepared = ServiceClass.prepareExamples()
if (prepared.length === 0) {
return
}
const category = findCategory(ServiceClass.category)
if (category === undefined) {
throw Error(
`Unknown category ${ServiceClass.category} referenced in ${
ServiceClass.name
}`
)
}
category.examples = category.examples.concat(prepared)
})
}
loadExamples()
module.exports = allBadgeExamples
module.exports.findCategory = findCategory

View File

@@ -0,0 +1,34 @@
'use strict'
const { expect } = require('chai')
const allBadgeExamples = require('./all-badge-examples')
describe('The badge examples', function() {
it('should include AppVeyor, which is added automatically', function() {
const { examples } = allBadgeExamples.findCategory('build')
const appVeyorBuildExamples = examples
.filter(ex => ex.title.includes('AppVeyor'))
.filter(ex => !ex.title.includes('tests'))
expect(appVeyorBuildExamples).to.deep.equal([
{
title: 'AppVeyor',
exampleUrl: '/appveyor/ci/gruntjs/grunt.svg',
previewUrl: '/badge/build-passing-brightgreen.svg',
urlPattern: '/appveyor/ci/:user/:repo.svg',
documentation: undefined,
keywords: undefined,
},
{
title: 'AppVeyor branch',
exampleUrl: '/appveyor/ci/gruntjs/grunt/master.svg',
previewUrl: '/badge/build-passing-brightgreen.svg',
urlPattern: '/appveyor/ci/:user/:repo/:branch.svg',
documentation: undefined,
keywords: undefined,
},
])
})
})

148
lib/analytics.js Normal file
View File

@@ -0,0 +1,148 @@
'use strict'
const fs = require('fs')
const { URL } = require('url')
// We can either use a process-wide object regularly saved to a JSON file,
// or a Redis equivalent (for multi-process / when the filesystem is unreliable.
let redis
let useRedis = false
if (process.env.REDISTOGO_URL) {
const { port, hostname, password } = new URL(process.env.REDISTOGO_URL)
redis = require('redis').createClient(port, hostname)
redis.auth(password)
useRedis = true
}
let analytics = {}
let autosaveIntervalId
const analyticsPath = process.env.SHIELDS_ANALYTICS_FILE || './analytics.json'
function performAutosave() {
const contents = JSON.stringify(analytics)
if (useRedis) {
redis.set(analyticsPath, contents)
} else {
fs.writeFileSync(analyticsPath, contents)
}
}
function scheduleAutosaving() {
const analyticsAutoSavePeriod = 10000
autosaveIntervalId = setInterval(performAutosave, analyticsAutoSavePeriod)
}
// For a clean shutdown.
function cancelAutosaving() {
if (autosaveIntervalId) {
clearInterval(autosaveIntervalId)
autosaveIntervalId = null
}
performAutosave()
}
function defaultAnalytics() {
const analytics = Object.create(null)
// In case something happens on the 36th.
analytics.vendorMonthly = new Array(36)
resetMonthlyAnalytics(analytics.vendorMonthly)
analytics.rawMonthly = new Array(36)
resetMonthlyAnalytics(analytics.rawMonthly)
analytics.vendorFlatMonthly = new Array(36)
resetMonthlyAnalytics(analytics.vendorFlatMonthly)
analytics.rawFlatMonthly = new Array(36)
resetMonthlyAnalytics(analytics.rawFlatMonthly)
analytics.vendorFlatSquareMonthly = new Array(36)
resetMonthlyAnalytics(analytics.vendorFlatSquareMonthly)
analytics.rawFlatSquareMonthly = new Array(36)
resetMonthlyAnalytics(analytics.rawFlatSquareMonthly)
return analytics
}
function load() {
const defaultAnalyticsObject = defaultAnalytics()
if (useRedis) {
redis.get(analyticsPath, (err, value) => {
if (err == null && value != null) {
// if/try/return trick:
// if error, then the rest of the function is run.
try {
analytics = JSON.parse(value)
// Extend analytics with a new value.
for (const key in defaultAnalyticsObject) {
if (!(key in analytics)) {
analytics[key] = defaultAnalyticsObject[key]
}
}
return
} catch (e) {
console.error('Invalid Redis analytics, resetting.')
console.error(e)
}
}
analytics = defaultAnalyticsObject
})
} else {
// Not using Redis.
try {
analytics = JSON.parse(fs.readFileSync(analyticsPath))
// Extend analytics with a new value.
for (const key in defaultAnalyticsObject) {
if (!(key in analytics)) {
analytics[key] = defaultAnalyticsObject[key]
}
}
} catch (e) {
if (e.code !== 'ENOENT') {
console.error('Invalid JSON file for analytics, resetting.')
console.error(e)
}
analytics = defaultAnalyticsObject
}
}
}
let lastDay = new Date().getDate()
function resetMonthlyAnalytics(monthlyAnalytics) {
for (let i = 0; i < monthlyAnalytics.length; i++) {
monthlyAnalytics[i] = 0
}
}
function incrMonthlyAnalytics(monthlyAnalytics) {
try {
const currentDay = new Date().getDate()
// If we changed month, reset empty days.
while (lastDay !== currentDay) {
// Assumption: at least a hit a month.
lastDay = (lastDay + 1) % monthlyAnalytics.length
monthlyAnalytics[lastDay] = 0
}
monthlyAnalytics[currentDay]++
} catch (e) {
console.error(e.stack)
}
}
function noteRequest(queryParams, match) {
incrMonthlyAnalytics(analytics.vendorMonthly)
if (queryParams.style === 'flat') {
incrMonthlyAnalytics(analytics.vendorFlatMonthly)
} else if (queryParams.style === 'flat-square') {
incrMonthlyAnalytics(analytics.vendorFlatSquareMonthly)
}
}
function setRoutes(server) {
server.ajax.on('analytics/v1', (json, end) => {
end(analytics)
})
}
module.exports = {
load,
scheduleAutosaving,
cancelAutosaving,
noteRequest,
setRoutes,
}

162
lib/badge-data.js Normal file
View File

@@ -0,0 +1,162 @@
'use strict'
const isCSSColor = require('is-css-color')
const logos = require('./load-logos')()
const simpleIcons = require('./load-simple-icons')()
const { svg2base64, isDataUri } = require('./logo-helper')
const colorschemes = require('../gh-badges/lib/colorscheme.json')
function toArray(val) {
if (val === undefined) {
return []
} else if (Object(val) instanceof Array) {
return val
} else {
return [val]
}
}
function prependPrefix(s, prefix) {
if (s === undefined) {
return undefined
}
s = `${s}`
if (s.startsWith(prefix)) {
return s
} else {
return prefix + s
}
}
function isHexColor(s = '') {
return /^([\da-f]{3}){1,2}$/i.test(s)
}
function makeColor(color) {
if (isHexColor(color)) {
return `#${color}`
} else if (colorschemes[color] !== undefined) {
return colorschemes[color].colorB
} else if (isCSSColor(color)) {
return color
} else {
return undefined
}
}
function makeColorB(defaultColor, overrides) {
return makeColor(overrides.colorB || defaultColor)
}
function setBadgeColor(badgeData, color) {
if (isHexColor(color)) {
badgeData.colorB = `#${color}`
delete badgeData.colorscheme
} else if (colorschemes[color] !== undefined) {
badgeData.colorscheme = color
delete badgeData.colorB
} else if (isCSSColor(color)) {
badgeData.colorB = color
delete badgeData.colorscheme
} else {
badgeData.colorscheme = 'red'
delete badgeData.colorB
}
return badgeData
}
function makeLabel(defaultLabel, overrides) {
return `${
overrides.label === undefined
? (defaultLabel || '').toLowerCase()
: overrides.label
}`
}
function getShieldsIcon(icon = '', color = '') {
icon = typeof icon === 'string' ? icon.toLowerCase() : ''
if (!logos[icon]) {
return undefined
}
color = makeColor(color)
return color
? logos[icon].svg.replace(/fill="(.+?)"/g, `fill="${color}"`)
: logos[icon].base64
}
function getSimpleIcon(icon = '', color = null) {
icon = typeof icon === 'string' ? icon.toLowerCase().replace(/ /g, '-') : ''
if (!simpleIcons[icon]) {
return undefined
}
color = makeColor(color)
return color
? simpleIcons[icon].svg.replace('<svg', `<svg fill="${color}"`)
: simpleIcons[icon].base64
}
function makeLogo(defaultNamedLogo, overrides) {
if (overrides.logo === undefined) {
return svg2base64(
getShieldsIcon(defaultNamedLogo, overrides.logoColor) ||
getSimpleIcon(defaultNamedLogo, overrides.logoColor)
)
}
// +'s are replaced with spaces when used in query params, this returns them to +'s, then removes remaining whitespace - #1546
const maybeDataUri = prependPrefix(overrides.logo, 'data:')
.replace(/ /g, '+')
.replace(/\s/g, '')
if (isDataUri(maybeDataUri)) {
return maybeDataUri
} else {
return svg2base64(
getShieldsIcon(overrides.logo, overrides.logoColor) ||
getSimpleIcon(overrides.logo, overrides.logoColor)
)
}
}
// Generate the initial badge data. Pass the URL query parameters, which
// override the default label.
//
// The following parameters are supported:
//
// - label
// - style
// - logo
// - logoWidth
// - link
// - colorA
// - colorB
// - maxAge
//
// Note: maxAge is handled by cache(), not this function.
function makeBadgeData(defaultLabel, overrides) {
return {
text: [makeLabel(defaultLabel, overrides), 'n/a'],
colorscheme: 'lightgrey',
template: overrides.style,
logo: makeLogo(undefined, overrides),
logoPosition: +overrides.logoPosition,
logoWidth: +overrides.logoWidth,
links: toArray(overrides.link),
colorA: makeColor(overrides.colorA),
colorB: makeColor(overrides.colorB),
}
}
module.exports = {
toArray,
prependPrefix,
isHexColor,
makeLabel,
makeLogo,
makeBadgeData,
makeColor,
makeColorB,
setBadgeColor,
}

109
lib/badge-data.spec.js Normal file
View File

@@ -0,0 +1,109 @@
'use strict'
const { expect } = require('chai')
const { test, given, forCases } = require('sazerac')
const {
prependPrefix,
isHexColor,
makeLabel,
makeLogo,
makeBadgeData,
makeColor,
setBadgeColor,
} = require('./badge-data')
describe('Badge data helpers', function() {
test(prependPrefix, () => {
given('data:image/svg+xml;base64,PHN2ZyB4bWxu', 'data:').expect(
'data:image/svg+xml;base64,PHN2ZyB4bWxu'
)
given('foobar', 'data:').expect('data:foobar')
given(undefined, 'data:').expect(undefined)
})
test(isHexColor, () => {
forCases([given('f00bae'), given('4c1')]).expect(true)
forCases([given('f00bar'), given(''), given(undefined)]).expect(false)
})
test(makeLabel, () => {
given('my badge', {}).expect('my badge')
given('My bAdge', {}).expect('my badge')
given('my badge', { label: 'no, my badge' }).expect('no, my badge')
given('my badge', { label: 'no, MY badge' }).expect('no, MY badge')
given('my badge', { label: false }).expect('false')
given('my badge', { label: 0 }).expect('0')
given('my badge', { label: '' }).expect('')
})
test(makeLogo, () => {
forCases([
given('gratipay', { logo: 'image/svg+xml;base64,PHN2ZyB4bWxu' }),
given('gratipay', { logo: 'data:image/svg+xml;base64,PHN2ZyB4bWxu' }),
given('gratipay', { logo: 'data:image/svg xml;base64,PHN2ZyB4bWxu' }),
given('gratipay', { logo: 'data:image/svg+xml;base64,PHN2ZyB\n4bWxu' }),
]).expect('data:image/svg+xml;base64,PHN2ZyB4bWxu')
forCases([given('gratipay', { logo: '' }), given(undefined, {})]).expect(
undefined
)
given('gratipay', {}).assert(
'should not be empty',
v => expect(v).not.to.be.empty
)
})
test(makeBadgeData, () => {
given('my badge', {
label: 'no, my badge',
style: 'flat-square',
logo: 'image/svg+xml;base64,PHN2ZyB4bWxu',
logoPosition: 10,
logoWidth: '25',
link: 'https://example.com/',
colorA: 'blue',
colorB: 'f00bae',
}).expect({
text: ['no, my badge', 'n/a'],
colorscheme: 'lightgrey',
template: 'flat-square',
logo: 'data:image/svg+xml;base64,PHN2ZyB4bWxu',
logoPosition: 10,
logoWidth: 25,
links: ['https://example.com/'],
colorA: '#007ec6',
colorB: '#f00bae',
})
})
test(makeColor, () => {
given('red').expect('#e05d44')
given('blue').expect('#007ec6')
given('4c1').expect('#4c1')
given('f00f00').expect('#f00f00')
given('papayawhip').expect('papayawhip')
given('purple').expect('purple')
})
test(setBadgeColor, () => {
given({}, 'red').expect({ colorscheme: 'red' })
given({}, 'f00f00').expect({ colorB: '#f00f00' })
given({ colorB: '#f00f00', colorscheme: 'blue' }, 'red').expect({
colorscheme: 'red',
})
given({ colorB: '#f00f00', colorscheme: 'blue' }, 'blue').expect({
colorscheme: 'blue',
})
given({ colorB: '#f00f00', colorscheme: 'blue' }, 'papayawhip').expect({
colorB: 'papayawhip',
})
given({ colorB: '#f00f00', colorscheme: 'blue' }, 'purple').expect({
colorB: 'purple',
})
given({ colorB: '#b00b00', colorscheme: 'blue' }, '4c1').expect({
colorB: '#4c1',
})
given({ colorB: '#b00b00', colorscheme: 'blue' }, 'f00f00').expect({
colorB: '#f00f00',
})
})
})

117
lib/color-formatters.js Normal file
View File

@@ -0,0 +1,117 @@
/**
* Commonly-used functions for determining the colour to use for a badge,
* including colours based off download count, version number, etc.
*/
'use strict'
const moment = require('moment')
function version(version) {
if (typeof version !== 'string' && typeof version !== 'number') {
throw new Error(`Can't generate a version color for ${version}`)
}
version = `${version}`
let first = version[0]
if (first === 'v') {
first = version[1]
}
if (first === '0' || /alpha|beta|snapshot|dev|pre/i.test(version)) {
return 'orange'
} else {
return 'blue'
}
}
function downloadCount(downloads) {
return floorCount(downloads, 10, 100, 1000)
}
function coveragePercentage(percentage) {
return floorCount(percentage, 80, 90, 100)
}
function floorCount(value, yellow, yellowgreen, green) {
if (value <= 0) {
return 'red'
} else if (value < yellow) {
return 'yellow'
} else if (value < yellowgreen) {
return 'yellowgreen'
} else if (value < green) {
return 'green'
} else {
return 'brightgreen'
}
}
function letterScore(score) {
if (score === 'A') {
return 'brightgreen'
} else if (score === 'B') {
return 'green'
} else if (score === 'C') {
return 'yellowgreen'
} else if (score === 'D') {
return 'yellow'
} else if (score === 'E') {
return 'orange'
} else {
return 'red'
}
}
function colorScale(steps, colors, reversed) {
if (steps === undefined) {
throw Error('When invoking colorScale, steps should be provided.')
}
const defaultColors = {
1: ['red', 'brightgreen'],
2: ['red', 'yellow', 'brightgreen'],
3: ['red', 'yellow', 'green', 'brightgreen'],
4: ['red', 'yellow', 'yellowgreen', 'green', 'brightgreen'],
5: ['red', 'orange', 'yellow', 'yellowgreen', 'green', 'brightgreen'],
}
if (typeof colors === 'undefined') {
if (steps.length in defaultColors) {
colors = defaultColors[steps.length]
} else {
throw Error(`No default colors for ${steps.length} steps.`)
}
}
if (steps.length !== colors.length - 1) {
throw Error(
'When colors are provided, there should be n + 1 colors for n steps.'
)
}
if (reversed) {
colors = Array.from(colors).reverse()
}
return value => {
const stepIndex = steps.findIndex(step => value < step)
// For the final step, stepIndex is -1, so in all cases this expression
// works swimmingly.
return colors.slice(stepIndex)[0]
}
}
function age(date) {
const colorByAge = colorScale([7, 30, 180, 365, 730], undefined, true)
const daysElapsed = moment().diff(moment(date), 'days')
return colorByAge(daysElapsed)
}
module.exports = {
version,
downloadCount,
coveragePercentage,
floorCount,
letterScore,
colorScale,
age,
}

View File

@@ -0,0 +1,111 @@
'use strict'
const { test, given, forCases } = require('sazerac')
const { expect } = require('chai')
const {
coveragePercentage,
colorScale,
letterScore,
age,
version,
} = require('./color-formatters')
describe('Color formatters', function() {
const byPercentage = colorScale([Number.EPSILON, 80, 90, 100])
test(byPercentage, () => {
given(-1).expect('red')
given(0).expect('red')
given(0.5).expect('yellow')
given(1).expect('yellow')
given(50).expect('yellow')
given(80).expect('yellowgreen')
given(85).expect('yellowgreen')
given(90).expect('green')
given(100).expect('brightgreen')
given(101).expect('brightgreen')
forCases(
[-1, 0, 0.5, 1, 50, 80, 85, 90, 100, 101].map(v =>
given(v).expect(coveragePercentage(v))
)
).should("return '%s', for parity with coveragePercentage()")
})
context('when reversed', function() {
test(colorScale([7, 30, 180, 365, 730], undefined, true), () => {
given(3).expect('brightgreen')
given(7).expect('green')
given(10).expect('green')
given(60).expect('yellowgreen')
given(250).expect('yellow')
given(400).expect('orange')
given(800).expect('red')
})
})
test(letterScore, () => {
given('A').expect('brightgreen')
given('B').expect('green')
given('C').expect('yellowgreen')
given('D').expect('yellow')
given('E').expect('orange')
given('F').expect('red')
given('Z').expect('red')
})
const monthsAgo = months => {
const result = new Date()
// This looks wack but it works.
result.setMonth(result.getMonth() - months)
return result
}
test(age, () => {
given(Date.now())
.describe('when given the current timestamp')
.expect('brightgreen')
given(new Date())
.describe('when given the current Date')
.expect('brightgreen')
given(new Date(2001, 1, 1))
.describe('when given a Date many years ago')
.expect('red')
given(monthsAgo(2))
.describe('when given a Date two months ago')
.expect('yellowgreen')
given(monthsAgo(15))
.describe('when given a Date 15 months ago')
.expect('orange')
})
test(version, () => {
forCases([given('1.0'), given(9), given(1.0)]).expect('blue')
forCases([
given(0.1),
given('0.9'),
given('1.0-Beta'),
given('1.1-alpha'),
given('6.0-SNAPSHOT'),
given('1.0.1-dev'),
given('2.1.6-prerelease'),
]).expect('orange')
expect(() => version(null)).to.throw(
Error,
"Can't generate a version color for null"
)
expect(() => version(undefined)).to.throw(
Error,
"Can't generate a version color for undefined"
)
expect(() => version(true)).to.throw(
Error,
"Can't generate a version color for true"
)
expect(() => version({})).to.throw(
Error,
"Can't generate a version color for [object Object]"
)
})
})

View File

@@ -0,0 +1,20 @@
'use strict'
const deprecatedServices = {
gittip: new Date('2017-12-29'),
gratipay: new Date('2017-12-29'),
gemnasium: new Date('2018-05-15'),
snap: new Date('2018-01-23'),
'snap-ci': new Date('2018-01-23'),
cauditor: new Date('2018-02-15'),
dotnetstatus: new Date('2018-04-01'),
magnumci: new Date('2018-07-08'),
bithound: new Date('2018-07-08'),
versioneye: new Date('2018-08-20'),
issuestats: new Date('2018-09-01'),
libscore: new Date('2018-09-22'),
}
module.exports = {
deprecatedServices,
}

View File

@@ -0,0 +1,13 @@
'use strict'
const { Deprecated } = require('../services/errors')
function enforceDeprecation(effectiveDate) {
if (Date.now() >= effectiveDate.getTime()) {
throw new Deprecated()
}
}
module.exports = {
enforceDeprecation,
}

View File

@@ -0,0 +1,17 @@
'use strict'
const { expect } = require('chai')
const { Deprecated } = require('../services/errors')
const { enforceDeprecation } = require('./deprecation-helpers')
describe('enforceDeprecation', function() {
it('throws Deprecated for a date in the past', function() {
expect(() => enforceDeprecation(new Date())).to.throw(Deprecated)
})
it('does not throw for a date in the future', function() {
expect(() =>
enforceDeprecation(new Date(Date.now() + 10000))
).not.to.throw()
})
})

55
lib/error-helper.js Normal file
View File

@@ -0,0 +1,55 @@
'use strict'
const {
NotFound,
InvalidResponse,
Inaccessible,
} = require('../services/errors')
const defaultErrorMessages = {
404: 'not found',
}
const checkErrorResponse = function(badgeData, err, res, errorMessages = {}) {
errorMessages = { ...defaultErrorMessages, ...errorMessages }
if (err != null) {
badgeData.text[1] = 'inaccessible'
badgeData.colorscheme = 'red'
return true
} else if (errorMessages[res.statusCode] !== undefined) {
badgeData.text[1] = errorMessages[res.statusCode]
badgeData.colorscheme = 'lightgrey'
return true
} else if (res.statusCode !== 200) {
badgeData.text[1] = 'invalid'
badgeData.colorscheme = 'lightgrey'
return true
} else {
return false
}
}
checkErrorResponse.asPromise = function(errorMessages = {}) {
return async function({ buffer, res }) {
errorMessages = { ...defaultErrorMessages, ...errorMessages }
if (res.statusCode === 404) {
throw new NotFound({ prettyMessage: errorMessages[404] })
} else if (res.statusCode !== 200) {
const underlying = Error(
`Got status code ${res.statusCode} (expected 200)`
)
const props = { underlyingError: underlying }
if (errorMessages[res.statusCode] !== undefined) {
props.prettyMessage = errorMessages[res.statusCode]
}
if (res.statusCode >= 500) {
throw new Inaccessible(props)
}
throw new InvalidResponse(props)
}
return { buffer, res }
}
}
module.exports = {
checkErrorResponse,
}

152
lib/error-helper.spec.js Normal file
View File

@@ -0,0 +1,152 @@
'use strict'
const { expect } = require('chai')
const { checkErrorResponse } = require('./error-helper')
const {
NotFound,
InvalidResponse,
Inaccessible,
} = require('../services/errors')
describe('Standard Error Handler', function() {
it('makes inaccessible badge', function() {
const badgeData = { text: [] }
expect(checkErrorResponse(badgeData, 'something other than null', {})).to.be
.true
expect(badgeData.text[1]).to.equal('inaccessible')
expect(badgeData.colorscheme).to.equal('red')
})
it('makes not found badge', function() {
const badgeData = { text: [] }
expect(checkErrorResponse(badgeData, null, { statusCode: 404 })).to.be.true
expect(badgeData.text[1]).to.equal('not found')
expect(badgeData.colorscheme).to.equal('lightgrey')
})
it('makes not found badge with custom error', function() {
const badgeData = { text: [] }
expect(
checkErrorResponse(
badgeData,
null,
{ statusCode: 404 },
{ 404: 'custom message' }
)
).to.be.true
expect(badgeData.text[1]).to.equal('custom message')
expect(badgeData.colorscheme).to.equal('lightgrey')
})
it('makes invalid badge', function() {
const badgeData = { text: [] }
expect(checkErrorResponse(badgeData, null, { statusCode: 500 })).to.be.true
expect(badgeData.text[1]).to.equal('invalid')
expect(badgeData.colorscheme).to.equal('lightgrey')
})
it('return false on 200 status', function() {
expect(checkErrorResponse({ text: [] }, null, { statusCode: 200 })).to.be
.false
})
})
describe('async error handler', function() {
context('when status is 200', function() {
it('passes through the inputs', async function() {
const args = { buffer: 'buffer', res: { statusCode: 200 } }
expect(await checkErrorResponse.asPromise()(args)).to.deep.equal(args)
})
})
context('when status is 404', function() {
const res = { statusCode: 404 }
it('throws NotFound', async function() {
try {
await checkErrorResponse.asPromise()({ res })
expect.fail('Expected to throw')
} catch (e) {
expect(e).to.be.an.instanceof(NotFound)
expect(e.message).to.equal('Not Found')
expect(e.prettyMessage).to.equal('not found')
}
})
it('displays the custom not found message', async function() {
const notFoundMessage = 'no goblins found'
try {
await checkErrorResponse.asPromise({ 404: notFoundMessage })({ res })
expect.fail('Expected to throw')
} catch (e) {
expect(e).to.be.an.instanceof(NotFound)
expect(e.message).to.equal('Not Found: no goblins found')
expect(e.prettyMessage).to.equal('no goblins found')
}
})
})
context('when status is 4xx', function() {
it('throws InvalidResponse', async function() {
const res = { statusCode: 499 }
try {
await checkErrorResponse.asPromise()({ res })
expect.fail('Expected to throw')
} catch (e) {
expect(e).to.be.an.instanceof(InvalidResponse)
expect(e.message).to.equal(
'Invalid Response: Got status code 499 (expected 200)'
)
expect(e.prettyMessage).to.equal('invalid')
}
})
it('displays the custom error message', async function() {
const res = { statusCode: 403 }
try {
await checkErrorResponse.asPromise({
403: 'access denied',
})({ res })
expect.fail('Expected to throw')
} catch (e) {
expect(e).to.be.an.instanceof(InvalidResponse)
expect(e.message).to.equal(
'Invalid Response: Got status code 403 (expected 200)'
)
expect(e.prettyMessage).to.equal('access denied')
}
})
})
context('when status is 5xx', function() {
it('throws Inaccessible', async function() {
const res = { statusCode: 503 }
try {
await checkErrorResponse.asPromise()({ res })
expect.fail('Expected to throw')
} catch (e) {
expect(e).to.be.an.instanceof(Inaccessible)
expect(e.message).to.equal(
'Inaccessible: Got status code 503 (expected 200)'
)
expect(e.prettyMessage).to.equal('inaccessible')
}
})
it('displays the custom error message', async function() {
const res = { statusCode: 500 }
try {
await checkErrorResponse.asPromise({
500: 'server overloaded',
})({ res })
expect.fail('Expected to throw')
} catch (e) {
expect(e).to.be.an.instanceof(Inaccessible)
expect(e.message).to.equal(
'Inaccessible: Got status code 500 (expected 200)'
)
expect(e.prettyMessage).to.equal('server overloaded')
}
})
})
})

View File

@@ -0,0 +1,45 @@
'use strict'
const fsos = require('fsos')
const githubAuth = require('./github-auth')
const TokenPersistence = require('./token-persistence')
class FsTokenPersistence extends TokenPersistence {
constructor({ path }) {
super()
this.path = path
}
async initialize() {
let contents
try {
contents = await fsos.get(this.path)
} catch (e) {
if (e.code === 'ENOENT') {
contents = '[]'
} else {
throw e
}
}
const tokens = JSON.parse(contents)
tokens.forEach(tokenString => {
githubAuth.addGithubToken(tokenString)
})
}
async save() {
const tokens = githubAuth.getAllTokenIds()
await fsos.set(this.path, JSON.stringify(tokens))
}
async onTokenAdded(token) {
await this.save()
}
async onTokenRemoved(token) {
await this.save()
}
}
module.exports = FsTokenPersistence

View File

@@ -0,0 +1,78 @@
'use strict'
const fs = require('fs')
const tmp = require('tmp')
const readFile = require('fs-readfile-promise')
const { expect } = require('chai')
const FsTokenPersistence = require('./fs-token-persistence')
const githubAuth = require('./github-auth')
describe('File system token persistence', function() {
beforeEach(githubAuth.removeAllTokens)
afterEach(githubAuth.removeAllTokens)
let path, persistence
beforeEach(function() {
path = tmp.tmpNameSync()
persistence = new FsTokenPersistence({ path })
})
context('when the file does not exist', function() {
it('does nothing', async function() {
await persistence.initialize()
expect(githubAuth.getAllTokenIds()).to.deep.equal([])
})
it('saving creates an empty file', async function() {
await persistence.initialize()
await persistence.save()
const json = JSON.parse(await readFile(path))
expect(json).to.deep.deep.equal([])
})
})
context('when the file exists', function() {
const initialTokens = ['a', 'b', 'c'].map(char => char.repeat(40))
beforeEach(async function() {
fs.writeFileSync(path, JSON.stringify(initialTokens))
})
it('loads the contents', async function() {
await persistence.initialize()
expect(githubAuth.getAllTokenIds()).to.deep.equal(initialTokens)
})
context('when tokens are added', function() {
it('saves the change', async function() {
const newToken = 'e'.repeat(40)
const expected = initialTokens.slice()
expected.push(newToken)
await persistence.initialize()
githubAuth.addGithubToken(newToken)
await persistence.noteTokenAdded(newToken)
const savedTokens = JSON.parse(await readFile(path))
expect(savedTokens).to.deep.equal(expected)
})
})
context('when tokens are removed', function() {
it('saves the change', async function() {
const expected = Array.from(initialTokens)
const toRemove = expected.pop()
await persistence.initialize()
githubAuth.rmGithubToken(toRemove)
await persistence.noteTokenRemoved(toRemove)
const savedTokens = JSON.parse(await readFile(path))
expect(savedTokens).to.deep.equal(expected)
})
})
})
})

View File

@@ -1,167 +1,60 @@
var querystring = require('querystring');
var request = require('request');
var autosave = require('json-autosave');
var serverSecrets;
try {
// Everything that cannot be checked in but is useful server-side
// is stored in this JSON data.
serverSecrets = require('../secret.json');
} catch(e) {}
var githubUserTokens;
var githubUserTokensFile = '.github-user-tokens.json';
autosave(githubUserTokensFile, {data:[]}).then(function(f) {
githubUserTokens = f;
for (var i = 0; i < githubUserTokens.data.length; i++) {
addGithubToken(githubUserTokens.data[i]);
}
}).catch(function(e) { console.error('Could not create ' + githubUserTokensFile); });
'use strict'
function setRoutes(server) {
server.route(/^\/github-auth$/, function(data, match, end, ask) {
if (!(serverSecrets && serverSecrets.gh_client_id)) {
return end('This server is missing GitHub client secrets.');
}
var query = querystring.stringify({
client_id: serverSecrets.gh_client_id,
redirect_uri: 'https://img.shields.io/github-auth/done',
});
ask.res.statusCode = 302; // Found.
ask.res.setHeader('Location', 'https://github.com/login/oauth/authorize?' + query);
end('');
});
const { EventEmitter } = require('events')
const crypto = require('crypto')
const queryString = require('query-string')
const serverSecrets = require('./server-secrets')
const mapKeys = require('lodash.mapkeys')
server.route(/^\/github-auth\/done$/, function(data, match, end, ask) {
if (!(serverSecrets && serverSecrets.gh_client_id && serverSecrets.gh_client_secret)) {
return end('This server is missing GitHub client secrets.');
}
if (!data.code) {
return end('GitHub OAuth authentication failed to provide a code.');
}
var options = {
url: 'https://github.com/login/oauth/access_token',
headers: {
'Content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
'User-Agent': 'Shields.io',
},
form: querystring.stringify({
client_id: serverSecrets.gh_client_id,
client_secret: serverSecrets.gh_client_secret,
code: data.code,
}),
method: 'POST',
};
request(options, function(err, res, body) {
if (err != null) { return end('The connection to GitHub failed.'); }
try {
var content = querystring.parse(body);
} catch(e) { return end('The GitHub OAuth token could not be parsed.'); }
var token = content.access_token;
if (!token) {
return end('The GitHub OAuth process did not return a user token.');
}
console.log('GitHub OAuth: ' + token);
ask.res.setHeader('Content-Type', 'text/html');
end('<p>Shields.io has received your app-specific GitHub user token. ' +
'You can revoke it by going to ' +
'<a href="https://github.com/settings/applications">GitHub</a>.</p>' +
'<p>Until you do, you have now increased the rate limit for GitHub ' +
'requests going through Shields.io. GitHub-related badges are ' +
'therefore more robust.</p>' +
'<p>Thanks for contributing to a smoother experience for ' +
'everyone!</p>' +
'<p><a href="/">Back to the website</a></p>');
sendTokenToAllServers(token)
.catch(function(e) {
console.error('GitHub user token transmission failed:', e);
});
});
});
server.route(/^\/github-auth\/add-token$/, function(data, match, end, ask) {
console.log('GitHub add token called with', JSON.stringify(data));
if (data.shieldsSecret !== serverSecrets.shieldsSecret) {
// An unknown entity tries to connect. Let the connection linger for a minute.
return setTimeout(function() { end('Invalid secret.'); }, 60000);
}
addGithubToken(data.token);
end('Thanks!');
});
};
function sendTokenToAllServers(token) {
var ips = serverSecrets.shieldsIps;
return Promise.all(ips.map(function(ip) {
return new Promise(function(resolve, reject) {
var options = {
url: 'https://' + ip + '/github-auth/add-token',
method: 'POST',
form: {
shieldsSecret: serverSecrets.shieldsSecret,
token: token,
},
// We target servers by IP, and we use HTTPS. Assuming that
// 1. Internet routers aren't hacked, and
// 2. We don't unknowingly lose our IP to someone else,
// we're not leaking people's and our information.
// (If we did, it would have no impact, as we only ask for a token,
// no GitHub scope. The malicious entity would only be able to use
// our rate limit pool.)
// FIXME: use letsencrypt.
strictSSL: false,
};
request(options, function(err, res, body) {
if (err != null) { return reject('Posting the GitHub user token failed: ' + err.stack); }
resolve();
});
});
}));
}
// Track rate limit requests remaining.
const userTokenRateLimit = 12500
let githubUserTokens = []
// Ideally, we would want priority queues here.
var reqRemaining = new Map(); // From token to requests remaining.
var reqReset = new Map(); // From token to timestamp.
const reqRemaining = new Map() // From token to requests remaining.
const reqReset = new Map() // From token to timestamp.
const emitter = new EventEmitter()
// Personal tokens allow access to GitHub private repositories.
// You can manage your personal GitHub token at
// <https://github.com/settings/tokens>.
if (serverSecrets && serverSecrets.gh_token) {
addGithubToken(serverSecrets.gh_token)
}
// token: client token as a string.
// reqs: number of requests remaining.
// reset: timestamp when the number of remaining requests is reset.
function setReqRemaining(token, reqs, reset) {
reqRemaining.set(token, reqs);
reqReset.set(token, reset);
reqRemaining.set(token, reqs)
reqReset.set(token, reset)
}
function rmReqRemaining(token) {
reqRemaining.delete(token);
reqReset.delete(token);
reqRemaining.delete(token)
reqReset.delete(token)
}
function utcEpochSeconds() {
return ((Date.now() / 1000) >>> 0);
return (Date.now() / 1000) >>> 0
}
var userTokenRateLimit = 12500;
// Return false if the token cannot reasonably be expected to perform
// a GitHub request.
function isTokenUsable(token, now) {
var reqs = reqRemaining.get(token);
var reset = reqReset.get(token);
const reqs = reqRemaining.get(token)
const reset = reqReset.get(token)
// We don't want to empty more than 3/4 of a user's rate limit.
var hasRemainingReqs = reqs > (userTokenRateLimit / 4);
var isBeyondRateLimitReset = reset < now;
return hasRemainingReqs || isBeyondRateLimitReset;
const hasRemainingReqs = reqs > userTokenRateLimit / 4
const isBeyondRateLimitReset = reset < now
return hasRemainingReqs || isBeyondRateLimitReset
}
// Return a list of tokens (as strings) which can be used for a GitHub request,
// with a reasonable chance that the request will succeed.
function usableTokens() {
var now = utcEpochSeconds();
return githubUserTokens.data.filter(function(token) {
return isTokenUsable(token, now);
});
const now = utcEpochSeconds()
return githubUserTokens.filter(token => isTokenUsable(token, now))
}
// Retrieve a user token if there is one for which we believe there are requests
@@ -170,84 +63,151 @@ function getReqRemainingToken() {
// Go through the user tokens.
// Among usable ones, use the one with the highest number of remaining
// requests.
var tokens = usableTokens();
var highestReq = -1;
var highestToken;
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var reqs = reqRemaining.get(token);
const tokens = usableTokens()
let highestReq = -1
let highestToken
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i]
const reqs = reqRemaining.get(token)
if (reqs > highestReq) {
highestReq = reqs;
highestToken = token;
highestReq = reqs
highestToken = token
}
}
return highestToken;
return highestToken
}
function addGithubToken(token) {
// A reset date of 0 has to be in the past.
setReqRemaining(token, userTokenRateLimit, 0);
setReqRemaining(token, userTokenRateLimit, 0)
// Insert it only if it is not registered yet.
if (githubUserTokens.data.indexOf(token) === -1) {
githubUserTokens.data.push(token);
if (githubUserTokens.indexOf(token) === -1) {
githubUserTokens.push(token)
}
emitter.emit('token-added', token)
}
function rmGithubToken(token) {
rmReqRemaining(token);
rmReqRemaining(token)
// Remove it only if it is in there.
var idx = githubUserTokens.data.indexOf(token);
const idx = githubUserTokens.indexOf(token)
if (idx >= 0) {
githubUserTokens.data.splice(idx, 1);
githubUserTokens.splice(idx, 1)
}
}
// Personal tokens allow access to GitHub private repositories.
// You can manage your personal GitHub token at
// <https://github.com/settings/tokens>.
if (serverSecrets && serverSecrets.gh_token) {
addGithubToken(serverSecrets.gh_token);
// Convert an ES6 Map to an object.
function mapToObject(map) {
const result = {}
for (const [k, v] of map) {
result[k] = v
}
return result
}
// Compute a one-way hash of the input string.
function sha(str) {
return crypto
.createHash('sha256')
.update(str, 'utf-8')
.digest('hex')
}
function getAllTokenIds() {
return githubUserTokens.slice()
}
function removeAllTokens() {
githubUserTokens = []
}
function serializeDebugInfo(options) {
// Apply defaults.
const { sanitize } = Object.assign({ sanitize: true }, options)
const unsanitized = {
tokens: githubUserTokens,
reqRemaining: mapToObject(reqRemaining),
reqReset: mapToObject(reqReset),
utcEpochSeconds: utcEpochSeconds(),
sanitized: false,
}
if (sanitize) {
return {
tokens: unsanitized.tokens.map(k => sha(k)),
reqRemaining: mapKeys(unsanitized.reqRemaining, (v, k) => sha(k)),
reqReset: mapKeys(unsanitized.reqReset, (v, k) => sha(k)),
utcEpochSeconds: unsanitized.utcEpochSeconds,
sanitized: true,
}
} else {
return unsanitized
}
}
// When a global gh_token is configured, use that in place of our shields.io
// token-cycling logic. This produces more predictable behavior when a token
// is provided, and more predictable failures if that token is exhausted.
//
// You can manage your personal GitHub token at https://github.com/settings/tokens
const globalToken = (serverSecrets || {}).gh_token
// Act like request(), but tweak headers and query to avoid hitting a rate
// limit.
function githubRequest(request, url, query, cb) {
query = query || {};
query = query || {}
// A special User-Agent is required:
// http://developer.github.com/v3/#user-agent-required
var headers = {
const headers = {
'User-Agent': 'Shields.io',
'Accept': 'application/vnd.github.v3+json',
};
var githubToken = getReqRemainingToken();
Accept: 'application/vnd.github.v3+json',
}
const githubToken =
globalToken === undefined ? getReqRemainingToken() : globalToken
if (githubToken != null) {
// Typically, GitHub user tokens grants us 12500 req/hour.
headers['Authorization'] = 'token ' + githubToken;
headers['Authorization'] = `token ${githubToken}`
} else if (serverSecrets && serverSecrets.gh_client_id) {
// Using our OAuth App secret grants us 5000 req/hour
// instead of the standard 60 req/hour.
query.client_id = serverSecrets.gh_client_id;
query.client_secret = serverSecrets.gh_client_secret;
query.client_id = serverSecrets.gh_client_id
query.client_secret = serverSecrets.gh_client_secret
}
var qs = querystring.stringify(query);
if (qs) { url += '?' + qs; }
request(url, {headers: headers}, function(err, res, buffer) {
if (githubToken != null) {
if (res.statusCode === 401) { // Unauthorized.
rmGithubToken(githubToken);
const qs = queryString.stringify(query)
if (qs) {
url += `?${qs}`
}
request(url, { headers }, (err, res, buffer) => {
if (globalToken !== null && githubToken !== null && err === null) {
if (res.statusCode === 401) {
// Unauthorized.
rmGithubToken(githubToken)
emitter.emit('token-removed', githubToken)
} else {
var remaining = +res.headers['x-ratelimit-remaining'];
const remaining = +res.headers['x-ratelimit-remaining']
// reset is in UTC epoch seconds.
var reset = +res.headers['x-ratelimit-reset'];
setReqRemaining(githubToken, remaining, reset);
if (remaining === 0) { return; } // Hope for the best in the cache.
const reset = +res.headers['x-ratelimit-reset']
setReqRemaining(githubToken, remaining, reset)
if (remaining === 0) {
return
} // Hope for the best in the cache.
}
}
cb(err, res, buffer);
});
cb(err, res, buffer)
})
}
exports.setRoutes = setRoutes;
exports.request = githubRequest;
module.exports = {
request: githubRequest,
serializeDebugInfo,
addGithubToken,
rmGithubToken,
getAllTokenIds,
removeAllTokens,
emitter,
}

View File

@@ -0,0 +1,69 @@
/**
* Helpers to run a Shields server in process.
*
* Usage:
* let server;
* before('Start running the server', function () {
* this.timeout(5000);
* server = serverHelpers.start();
* });
* after('Shut down the server', function () { serverHelpers.stop(server); });
*/
'use strict'
const config = require('./test-config')
const serverConfig = require('./server-config')
let startCalled = false
/**
* Start the server.
*
* @param {Number} port number (optional)
* @return {Object} The scoutcamp instance
*/
function start() {
if (startCalled) {
throw Error(
'Because of the way Shields works, you can only use this ' +
'once per node process. Once you call stop(), the game is over.'
)
}
startCalled = true
// Modifying config is a bit dirty, but it works, and avoids making bigger
// changes to server.js.
serverConfig.bind = {
host: 'localhost',
port: config.port,
}
const server = require('../server')
return server
}
/**
* Reset the server, to avoid or reduce side effects between tests.
*
* @param {Object} server instance
*/
function reset(server) {
server.reset()
}
/**
* Stop the server.
*
* @param {Object} server instance
*/
async function stop(server) {
if (server) {
await server.stop()
}
}
module.exports = {
start,
reset,
stop,
}

97
lib/licenses.js Normal file
View File

@@ -0,0 +1,97 @@
'use strict'
const { toArray } = require('./badge-data')
const licenseTypes = {
// permissive licenses - not public domain and not copyleft
permissive: {
spdxLicenseIds: [
'AFL-3.0',
'Apache-2.0',
'Artistic-2.0',
'BSD-2-Clause',
'BSD-3-Clause',
'BSD-3-Clause-Clear',
'BSL-1.0',
'CC-BY-4.0',
'ECL-2.0',
'ISC',
'MIT',
'MS-PL',
'NCSA',
'PostgreSQL',
'Zlib',
],
color: 'green',
priority: '2',
},
// copyleft licenses require 'Disclose source' (https://choosealicense.com/appendix/#disclose-source)
// or 'Same license' (https://choosealicense.com/appendix/#same-license)
copyleft: {
spdxLicenseIds: [
'AGPL-3.0',
'CC-BY-SA-4.0',
'EPL-1.0',
'EUPL-1.1',
'GPL-2.0',
'GPL-3.0',
'LGPL-2.1',
'LGPL-3.0',
'LPPL-1.3c',
'MPL-2.0',
'MS-RL',
'OFL-1.1',
'OSL-3.0',
],
color: 'orange',
priority: '1',
},
// public domain licenses do not require 'License and copyright notice' (https://choosealicense.com/appendix/#include-copyright)
'public-domain': {
spdxLicenseIds: ['CC0-1.0', 'Unlicense', 'WTFPL'],
color: '7cd958',
priority: '3',
},
}
const licenseToColorMap = {}
Object.keys(licenseTypes).forEach(licenseType => {
const { spdxLicenseIds, color, priority } = licenseTypes[licenseType]
spdxLicenseIds.forEach(license => {
licenseToColorMap[license] = { color, priority }
})
})
const defaultLicenseColor = 'lightgrey'
const licenseToColor = spdxId => {
if (!Array.isArray(spdxId)) {
return (
(licenseToColorMap[spdxId] && licenseToColorMap[spdxId].color) ||
defaultLicenseColor
)
}
const licenseType = spdxId
.filter(i => licenseToColorMap[i])
.map(i => licenseToColorMap[i])
.reduce((a, b) => (a.priority > b.priority ? a : b), {
color: defaultLicenseColor,
priority: 0,
})
return licenseType.color
}
function renderLicenseBadge({ license, licenses }) {
if (licenses === undefined) {
licenses = toArray(license)
}
if (licenses.length === 0) {
return { message: 'missing', color: 'red' }
}
return {
message: licenses.join(', '),
color: licenseToColor(licenses),
}
}
module.exports = { licenseToColor, renderLicenseBadge }

46
lib/licenses.spec.js Normal file
View File

@@ -0,0 +1,46 @@
'use strict'
const { test, given, forCases } = require('sazerac')
const { licenseToColor, renderLicenseBadge } = require('./licenses')
describe('license helpers', function() {
test(licenseToColor, () => {
given('MIT').expect('green')
given('MPL-2.0').expect('orange')
given('Unlicense').expect('7cd958')
given('unknown-license').expect('lightgrey')
given(null).expect('lightgrey')
given(['CC0-1.0', 'MPL-2.0']).expect('7cd958')
given(['MPL-2.0', 'CC0-1.0']).expect('7cd958')
given(['MIT', 'MPL-2.0']).expect('green')
given(['MPL-2.0', 'MIT']).expect('green')
given(['OFL-1.1', 'MPL-2.0']).expect('orange')
given(['MPL-2.0', 'OFL-1.1']).expect('orange')
given(['CC0-1.0', 'MIT', 'MPL-2.0']).expect('7cd958')
given(['UNKNOWN-1.0', 'MIT']).expect('green')
given(['UNKNOWN-1.0', 'UNKNOWN-2.0']).expect('lightgrey')
})
test(renderLicenseBadge, () => {
forCases([
given({ license: undefined }),
given({ licenses: [] }),
given({}),
]).expect({
message: 'missing',
color: 'red',
})
forCases([
given({ license: 'WTFPL' }),
given({ licenses: ['WTFPL'] }),
]).expect({
message: 'WTFPL',
color: '7cd958',
})
given({ licenses: ['MPL-2.0', 'MIT'] }).expect({
message: 'MPL-2.0, MIT',
color: 'green',
})
})
})

30
lib/load-logos.js Normal file
View File

@@ -0,0 +1,30 @@
'use strict'
const fs = require('fs')
const path = require('path')
const { svg2base64 } = require('./logo-helper')
function loadLogos() {
// Cache svg logos from disk in base64 string
const logos = {}
const logoDir = path.join(__dirname, '..', 'logo')
const logoFiles = fs.readdirSync(logoDir)
logoFiles.forEach(filename => {
if (filename[0] === '.') {
return
}
// filename is eg, github.svg
const svg = fs.readFileSync(`${logoDir}/${filename}`).toString()
const base64 = svg2base64(svg)
// eg, github
const name = filename.slice(0, -'.svg'.length).toLowerCase()
logos[name] = {
svg,
base64,
}
})
return logos
}
module.exports = loadLogos

Some files were not shown because too many files have changed in this diff Show More