Fixes https://github.com/badges/shields/issues/3260
Problem happens when a value of a color in an old PNG static badge is a number: http://localhost:8080/my-label/my-message.png?color=1. In this case `color` in `queryParams` is a number.
0a0b5b3f03/core/server/server.js (L203-L212)
Surprisingly service test listed below is passing currently on master - value `1` is represented in `queryParams` as a String (only in test).
`services/static-badge/static-badge.tester.js`
```js
t.create('Old static badge with a number as a color')
.get('/foo/bar.png?color=1', { followRedirect: false })
.expectStatus(301)
.expectHeader('Location', '/badge/foo-bar-1.png')
```
Moreover I added some code + description allowing to debug server.
* Modernised JSON format and removed _shields_test style
* Added logoWidth and labelColor fields to JSON response
* Reinstated and updated comment
* Extended expectBadge to accept Joi schemas for all fields
This picks up #2068 by adding per-badge stats as discussed in #966.
It ensures every service has a unique `name` property. By default this comes from the class name, and is overridden in all the various places where the class names are duplicated. (Some of those don't seem that useful, like the various download interval services, though those need to be refactored down into a single service anyway.) Tests enforce the names are unique. These are the names used by the service-test runner, so it's a good idea to make them unique anyway. (It was sort of strange before that you had to specify `nuget` instead of e.g. `resharper`.)
I've added validation to `deprecatedService` and `redirector`, and required that every `route` has a `base`, even if it's an empty string.
The name is used to generate unique metric labels, generating metrics like these:
```
service_requests_total{category="activity",family="eclipse-marketplace",service="eclipse_marketplace_update"} 2
service_requests_total{category="activity",family="npm",service="npm_collaborators"} 3
service_requests_total{category="activity",family="steam",service="steam_file_release_date"} 2
service_requests_total{category="analysis",family="ansible",service="ansible_galaxy_content_quality_score"} 2
service_requests_total{category="analysis",family="cii-best-practices",service="cii_best_practices_service"} 4
service_requests_total{category="analysis",family="cocoapods",service="cocoapods_docs"} 2
service_requests_total{category="analysis",family="codacy",service="codacy_grade"} 3
service_requests_total{category="analysis",family="coverity",service="coverity_scan"} 2
service_requests_total{category="analysis",family="coverity",service="deprecated_coverity_ondemand"} 2
service_requests_total{category="analysis",family="dependabot",service="dependabot_semver_compatibility"} 3
service_requests_total{category="analysis",family="lgtm",service="lgtm_alerts"} 2
service_requests_total{category="analysis",family="lgtm",service="lgtm_grade"} 3
service_requests_total{category="analysis",family="snyk",service="snyk_vulnerability_git_hub"} 4
service_requests_total{category="analysis",family="snyk",service="snyk_vulnerability_npm"} 5
service_requests_total{category="analysis",family="symfony",service="sensiolabs_i_redirector"} 1
service_requests_total{category="analysis",family="symfony",service="symfony_insight_grade"} 1
service_requests_total{category="build",family="appveyor",service="app_veyor_ci"} 3
service_requests_total{category="build",family="appveyor",service="app_veyor_tests"} 6
service_requests_total{category="build",family="azure-devops",service="azure_dev_ops_build"} 6
service_requests_total{category="build",family="azure-devops",service="azure_dev_ops_release"} 5
service_requests_total{category="build",family="azure-devops",service="azure_dev_ops_tests"} 6
service_requests_total{category="build",family="azure-devops",service="vso_build_redirector"} 2
service_requests_total{category="build",family="azure-devops",service="vso_release_redirector"} 1
service_requests_total{category="build",family="bitbucket",service="bitbucket_pipelines"} 5
service_requests_total{category="build",family="circleci",service="circle_ci"} 5
```
This is predicated on being able to use Prometheus's [`rate()`](https://prometheus.io/docs/prometheus/latest/querying/functions/#rate) function to visualize a counter's rate of change, as mentioned at https://github.com/badges/shields/issues/2068#issuecomment-466696561. Otherwise the stats will be disrupted every time a server restarts.
The metrics only appear on new-style services.
Fixes#2876 with @paulmelnikow's suggestion
Moved imports of `ServiceTester` and `createServiceTester` to a separate file so that dev dependencies are not imported by service classes.
Continue to implement #2698:
- Add `core/base-service/index.js` (but hold off on moving the things it imports)
- Add shortcuts in `services/index.js` for Base*Service, errors, and deprecatedService. This file will be streamlined later to avoid cluttering it with rarely used bits.
- Apply consistent ordering of imports and use of `module.exports` in testers.
- Remove some renaming of imports.
- Remove obsolete tests here and there.
Numeric colors weren't properly being handled by `makeBadge` after #2742.
Since this function really does not need to be accepting colors as strings, rather than make the function more lenient to work with Scoutcamp, I coerced the types of the colors on the way in.
Two tests cover the functionality in the modern service. I don't feel strongly that the legacy version needs coverage at this point, though I've added one for the moment on the github languages badge where this manifested.
Fix#2778
- Replace the idea of color schemes with the idea of named colors (since none of our colorschemes have used `colorA`)
- Pass through the normalized color to `_shields_test` to harmonize with BaseService and simplify testing
- Update service tests
- Move responsibility for color generation into the npm package
- Remove several color helper functions and their tests
- Update gh-badge public API to accept `color` and `labelColor`
This is a precursor to refactoring some of the logo code for #2473.
Now that the static badge has been moved in #2284, next in line for cleaning out `server.js` is this “static badge, old format.” I imagine this route is _very, very old_. (I wouldn’t be surprised if it’s not used at all. I’d be curious to see some stats on that endpoint. If it's not regularly getting requests I could see dropping it.)
In the case of URLs which have permanently changed, an approach I’d like to try is issuing a 301 Redirect.
The benefit is that if a user pastes the URL into the address bar while they are previewing or editing it, the browser will replace the address with the corrected URL when it loads. I figure this will cause some people to update their URLs with no effort, simply because they previewed the badge in their browser, and others to change over, if they notice it.
We incur a slight cost, which is a second request. However many browsers cache the 301’s indefinitely, and we can set an effectively infinite cache duration so the CDN and most other downstream caches will keep them a long time. And handling the redirect is extremely cheap.
This is a nice way to preserve backward compatibility of old routes without having to complicate the new route, such as in the case of vso -> azure-devops. For maintenance purposes, the route that redirects can effectively be treated separately.
It’s also a nice, gentle, and confidence-inspiring way to signal that users should update their URLs.
We could generalize this code, though I think this is a good place to start. This route is tricky because it needs to be loaded last, complicating a reusable solution.
This 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.