diff --git a/services/github/github-actions-workflow-status.service.js b/services/github/github-actions-workflow-status.service.js index cd0d2cb872ece..d05c2476170de 100644 --- a/services/github/github-actions-workflow-status.service.js +++ b/services/github/github-actions-workflow-status.service.js @@ -1,6 +1,6 @@ import Joi from 'joi' import { isBuildStatus, renderBuildStatusBadge } from '../build-status.js' -import { BaseSvgScrapingService } from '../index.js' +import { BaseSvgScrapingService, pathParam, queryParam } from '../index.js' import { documentation } from './github-helpers.js' const schema = Joi.object({ @@ -14,8 +14,6 @@ const queryParamSchema = Joi.object({ branch: Joi.alternatives().try(Joi.string(), Joi.number().cast('string')), }).required() -const keywords = ['action', 'actions'] - export default class GithubActionsWorkflowStatus extends BaseSvgScrapingService { static category = 'build' @@ -25,53 +23,26 @@ export default class GithubActionsWorkflowStatus extends BaseSvgScrapingService queryParamSchema, } - static examples = [ - { - title: 'GitHub Workflow Status', - namedParams: { - user: 'actions', - repo: 'toolkit', - workflow: 'unit-tests.yml', - }, - staticPreview: renderBuildStatusBadge({ - status: 'passing', - }), - documentation, - keywords, - }, - { - title: 'GitHub Workflow Status (with branch)', - namedParams: { - user: 'actions', - repo: 'toolkit', - workflow: 'unit-tests.yml', - }, - queryParams: { - branch: 'main', + static openApi = { + '/github/actions/workflow/status/{user}/{repo}/{workflow}': { + get: { + summary: 'GitHub Actions Workflow Status', + description: documentation, + parameters: [ + pathParam({ name: 'user', example: 'actions' }), + pathParam({ name: 'repo', example: 'toolkit' }), + pathParam({ name: 'workflow', example: 'unit-tests.yml' }), + queryParam({ name: 'branch', example: 'main' }), + queryParam({ + name: 'event', + example: 'push', + description: + 'See GitHub Actions [Events that trigger workflows](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows) for allowed values.', + }), + ], }, - staticPreview: renderBuildStatusBadge({ - status: 'passing', - }), - documentation, - keywords, }, - { - title: 'GitHub Workflow Status (with event)', - namedParams: { - user: 'actions', - repo: 'toolkit', - workflow: 'unit-tests.yml', - }, - queryParams: { - event: 'push', - }, - staticPreview: renderBuildStatusBadge({ - status: 'passing', - }), - documentation, - keywords, - }, - ] + } static _cacheLength = 60 diff --git a/services/github/github-commit-activity.service.js b/services/github/github-commit-activity.service.js index 07adab1e1274a..f1504f36387b7 100644 --- a/services/github/github-commit-activity.service.js +++ b/services/github/github-commit-activity.service.js @@ -1,7 +1,7 @@ import gql from 'graphql-tag' import Joi from 'joi' import parseLinkHeader from 'parse-link-header' -import { InvalidResponse } from '../index.js' +import { InvalidResponse, pathParam, queryParam } from '../index.js' import { metric } from '../text-formatters.js' import { nonNegativeInteger } from '../validators.js' import { GithubAuthV4Service } from './github-auth-service.js' @@ -35,33 +35,51 @@ export default class GitHubCommitActivity extends GithubAuthV4Service { queryParamSchema, } - static examples = [ - { - title: 'GitHub commit activity', - // Override the pattern to omit the deprecated interval "4w". - pattern: ':interval(t|y|m|w)/:user/:repo', - namedParams: { interval: 'm', user: 'eslint', repo: 'eslint' }, - queryParams: { authorFilter: 'nzakas' }, - staticPreview: this.render({ interval: 'm', commitCount: 457 }), - keywords: ['commits'], - documentation, + static openApi = { + '/github/commit-activity/{interval}/{user}/{repo}': { + get: { + summary: 'GitHub commit activity', + description: documentation, + parameters: [ + pathParam({ + name: 'interval', + example: 'm', + description: 'Commits in the last Week, Month, Year, or Total', + schema: { + type: 'string', + // Override the enum to omit the deprecated interval "4w". + enum: ['w', 'm', 'y', 't'], + }, + }), + pathParam({ name: 'user', example: 'badges' }), + pathParam({ name: 'repo', example: 'squint' }), + queryParam({ name: 'authorFilter', example: 'calebcartwright' }), + ], + }, }, - { - title: 'GitHub commit activity (branch)', - // Override the pattern to omit the deprecated interval "4w". - pattern: ':interval(t|y|m|w)/:user/:repo/:branch*', - namedParams: { - interval: 'm', - user: 'badges', - repo: 'squint', - branch: 'main', + '/github/commit-activity/{interval}/{user}/{repo}/{branch}': { + get: { + summary: 'GitHub commit activity (branch)', + description: documentation, + parameters: [ + pathParam({ + name: 'interval', + example: 'm', + description: 'Commits in the last Week, Month, Year, or Total', + schema: { + type: 'string', + // Override the enum to omit the deprecated interval "4w". + enum: ['w', 'm', 'y', 't'], + }, + }), + pathParam({ name: 'user', example: 'badges' }), + pathParam({ name: 'repo', example: 'squint' }), + pathParam({ name: 'branch', example: 'main' }), + queryParam({ name: 'authorFilter', example: 'calebcartwright' }), + ], }, - queryParams: { authorFilter: 'calebcartwright' }, - staticPreview: this.render({ interval: 'm', commitCount: 5 }), - keywords: ['commits'], - documentation, }, - ] + } static defaultBadgeData = { label: 'commit activity', color: 'blue' } diff --git a/services/github/github-commits-since.service.js b/services/github/github-commits-since.service.js index f74b6140a30e2..687b976e50716 100644 --- a/services/github/github-commits-since.service.js +++ b/services/github/github-commits-since.service.js @@ -1,15 +1,20 @@ import Joi from 'joi' +import { pathParam } from '../index.js' import { metric } from '../text-formatters.js' import { nonNegativeInteger } from '../validators.js' import { GithubAuthV3Service } from './github-auth-service.js' import { fetchLatestRelease, queryParamSchema, + openApiQueryParams, } from './github-common-release.js' import { documentation, httpErrorsFor } from './github-helpers.js' const schema = Joi.object({ ahead_by: nonNegativeInteger }).required() +const latestDocs = + '

The include_prereleases, sort and filter params can be used to configure how we determine the latest version.

' + export default class GithubCommitsSince extends GithubAuthV3Service { static category = 'activity' static route = { @@ -18,110 +23,60 @@ export default class GithubCommitsSince extends GithubAuthV3Service { queryParamSchema, } - static examples = [ - { - title: 'GitHub commits since tagged version', - namedParams: { - user: 'SubtitleEdit', - repo: 'subtitleedit', - version: '3.4.7', - }, - staticPreview: this.render({ - version: '3.4.7', - commitCount: 4225, - }), - documentation, - }, - { - title: 'GitHub commits since tagged version (branch)', - namedParams: { - user: 'SubtitleEdit', - repo: 'subtitleedit', - version: '3.4.7', - branch: 'master', - }, - staticPreview: this.render({ - version: '3.4.7', - commitCount: 4225, - }), - documentation, - }, - { - title: 'GitHub commits since latest release (by date)', - namedParams: { - user: 'SubtitleEdit', - repo: 'subtitleedit', - version: 'latest', - }, - staticPreview: this.render({ - version: '3.5.7', - commitCount: 157, - }), - documentation, - }, - { - title: 'GitHub commits since latest release (by date) for a branch', - namedParams: { - user: 'SubtitleEdit', - repo: 'subtitleedit', - version: 'latest', - branch: 'master', + static openApi = { + '/github/commits-since/{user}/{repo}/{version}': { + get: { + summary: 'GitHub commits since tagged version', + description: documentation, + parameters: [ + pathParam({ name: 'user', example: 'SubtitleEdit' }), + pathParam({ name: 'repo', example: 'subtitleedit' }), + pathParam({ + name: 'version', + example: '3.4.7', + }), + ], }, - staticPreview: this.render({ - version: '3.5.7', - commitCount: 157, - }), - documentation, }, - { - title: - 'GitHub commits since latest release (by date including pre-releases)', - namedParams: { - user: 'SubtitleEdit', - repo: 'subtitleedit', - version: 'latest', + '/github/commits-since/{user}/{repo}/{version}/{branch}': { + get: { + summary: 'GitHub commits since tagged version (branch)', + description: documentation, + parameters: [ + pathParam({ name: 'user', example: 'SubtitleEdit' }), + pathParam({ name: 'repo', example: 'subtitleedit' }), + pathParam({ + name: 'version', + example: '3.4.7', + }), + pathParam({ name: 'branch', example: 'main' }), + ], }, - queryParams: { include_prereleases: null }, - staticPreview: this.render({ - version: 'v3.5.8-alpha.1', - isPrerelease: true, - commitCount: 158, - }), - documentation, }, - { - title: 'GitHub commits since latest release (by SemVer)', - namedParams: { - user: 'SubtitleEdit', - repo: 'subtitleedit', - version: 'latest', + '/github/commits-since/{user}/{repo}/latest': { + get: { + summary: 'GitHub commits since latest release', + description: documentation + latestDocs, + parameters: [ + pathParam({ name: 'user', example: 'SubtitleEdit' }), + pathParam({ name: 'repo', example: 'subtitleedit' }), + ...openApiQueryParams, + ], }, - queryParams: { sort: 'semver' }, - staticPreview: this.render({ - version: 'v4.0.1', - sort: 'semver', - commitCount: 200, - }), - documentation, }, - { - title: - 'GitHub commits since latest release (by SemVer including pre-releases)', - namedParams: { - user: 'SubtitleEdit', - repo: 'subtitleedit', - version: 'latest', + '/github/commits-since/{user}/{repo}/latest/{branch}': { + get: { + summary: 'GitHub commits since latest release (branch)', + description: documentation + latestDocs, + parameters: [ + pathParam({ name: 'user', example: 'SubtitleEdit' }), + pathParam({ name: 'repo', example: 'subtitleedit' }), + pathParam({ name: 'branch', example: 'main' }), + ...openApiQueryParams, + ], }, - queryParams: { sort: 'semver', include_prereleases: null }, - staticPreview: this.render({ - version: 'v4.0.2-alpha.1', - sort: 'semver', - isPrerelease: true, - commitCount: 201, - }), - documentation, }, - ] + } static defaultBadgeData = { label: 'github', namedLogo: 'github' } diff --git a/services/github/github-common-release.js b/services/github/github-common-release.js index 75c123a5cd192..f8efc17462db6 100644 --- a/services/github/github-common-release.js +++ b/services/github/github-common-release.js @@ -2,7 +2,7 @@ import Joi from 'joi' import { matcher } from 'matcher' import { nonNegativeInteger } from '../validators.js' import { latest } from '../version.js' -import { NotFound } from '../index.js' +import { NotFound, queryParams } from '../index.js' import { httpErrorsFor } from './github-helpers.js' const releaseInfoSchema = Joi.object({ @@ -67,21 +67,37 @@ function getLatestRelease({ releases, sort, includePrereleases }) { return releases[0] } +const sortEnum = ['date', 'semver'] + const queryParamSchema = Joi.object({ include_prereleases: Joi.equal(''), - sort: Joi.string().valid('date', 'semver').default('date'), + sort: Joi.string() + .valid(...sortEnum) + .default('date'), filter: Joi.string(), }).required() -const filterDocs = `
-

+const filterDocs = `

The filter param can be used to apply a filter to the project's tag or release names before selecting the latest from the list. Two constructs are available: * is a wildcard matching zero or more characters, and if the pattern starts with a !, the whole pattern is negated. -

-
` +

` + +const openApiQueryParams = queryParams( + { + name: 'include_prereleases', + example: null, + schema: { type: 'boolean' }, + }, + { + name: 'sort', + example: 'semver', + schema: { type: 'string', enum: sortEnum }, + }, + { name: 'filter', example: '*beta*', description: filterDocs }, +) function applyFilter({ releases, filter, displayName }) { if (!filter) { @@ -137,7 +153,7 @@ async function fetchLatestRelease( return latestRelease } -export { fetchLatestRelease, filterDocs, queryParamSchema } +export { fetchLatestRelease, queryParamSchema, openApiQueryParams } // currently only used for tests export const _getLatestRelease = getLatestRelease diff --git a/services/github/github-downloads.tester.js b/services/github/github-downloads.tester.js index 11f833c947f29..35ab63cb806ba 100644 --- a/services/github/github-downloads.tester.js +++ b/services/github/github-downloads.tester.js @@ -10,7 +10,7 @@ const mockLatestRelease = release => nock => const mockReleases = releases => nock => nock('https://api.github.com') - .get('/repos/photonstorm/phaser/releases') + .get('/repos/photonstorm/phaser/releases?per_page=100') .reply(200, releases) t.create('Downloads all releases') diff --git a/services/github/github-go-mod.service.js b/services/github/github-go-mod.service.js index 9feded9bae79d..ed678e38f9f29 100644 --- a/services/github/github-go-mod.service.js +++ b/services/github/github-go-mod.service.js @@ -1,6 +1,6 @@ import Joi from 'joi' import { renderVersionBadge } from '../version.js' -import { InvalidResponse } from '../index.js' +import { InvalidResponse, pathParam, queryParam } from '../index.js' import { ConditionalGithubAuthV3Service } from './github-auth-service.js' import { fetchRepoContent } from './github-common-fetch.js' import { documentation } from './github-helpers.js' @@ -11,7 +11,8 @@ const queryParamSchema = Joi.object({ const goVersionRegExp = /^go (.+)$/m -const keywords = ['golang'] +const filenameDescription = + 'The `filename` param can be used to specify the path to `go.mod`. By default, we look for `go.mod` in the repo root' export default class GithubGoModGoVersion extends ConditionalGithubAuthV3Service { static category = 'version' @@ -21,42 +22,39 @@ export default class GithubGoModGoVersion extends ConditionalGithubAuthV3Service queryParamSchema, } - static examples = [ - { - title: 'GitHub go.mod Go version', - pattern: ':user/:repo', - namedParams: { user: 'gohugoio', repo: 'hugo' }, - staticPreview: this.render({ version: '1.12' }), - documentation, - keywords, + static openApi = { + '/github/go-mod/go-version/{user}/{repo}': { + get: { + summary: 'GitHub go.mod Go version', + description: documentation, + parameters: [ + pathParam({ name: 'user', example: 'gohugoio' }), + pathParam({ name: 'repo', example: 'hugo' }), + queryParam({ + name: 'filename', + example: 'src/go.mod', + description: filenameDescription, + }), + ], + }, }, - { - title: 'GitHub go.mod Go version (branch)', - pattern: ':user/:repo/:branch', - namedParams: { user: 'gohugoio', repo: 'hugo', branch: 'master' }, - staticPreview: this.render({ version: '1.12', branch: 'master' }), - documentation, - keywords, + '/github/go-mod/go-version/{user}/{repo}/{branch}': { + get: { + summary: 'GitHub go.mod Go version (branch)', + description: documentation, + parameters: [ + pathParam({ name: 'user', example: 'gohugoio' }), + pathParam({ name: 'repo', example: 'hugo' }), + pathParam({ name: 'branch', example: 'master' }), + queryParam({ + name: 'filename', + example: 'src/go.mod', + description: filenameDescription, + }), + ], + }, }, - { - title: 'GitHub go.mod Go version (subdirectory of monorepo)', - pattern: ':user/:repo', - namedParams: { user: 'golang', repo: 'go' }, - queryParams: { filename: 'src/go.mod' }, - staticPreview: this.render({ version: '1.14' }), - documentation, - keywords, - }, - { - title: 'GitHub go.mod Go version (branch & subdirectory of monorepo)', - pattern: ':user/:repo/:branch', - namedParams: { user: 'golang', repo: 'go', branch: 'master' }, - queryParams: { filename: 'src/go.mod' }, - staticPreview: this.render({ version: '1.14' }), - documentation, - keywords, - }, - ] + } static defaultBadgeData = { label: 'Go' } diff --git a/services/github/github-pull-request-check-state.tester.js b/services/github/github-pull-request-check-state.tester.js index 6ee4d8142e4a1..a9ee2f697078b 100644 --- a/services/github/github-pull-request-check-state.tester.js +++ b/services/github/github-pull-request-check-state.tester.js @@ -2,8 +2,8 @@ import { createServiceTester } from '../tester.js' export const t = await createServiceTester() t.create('github pull request check state') - .get('/s/pulls/badges/shields/8486.json') - .expectBadge({ label: 'checks', message: 'failure' }) + .get('/s/pulls/badges/shields/9863.json') + .expectBadge({ label: 'checks', message: 'success' }) t.create('github pull request check state (pull request not found)') .get('/s/pulls/badges/shields/5101.json') @@ -26,5 +26,5 @@ t.create( }) t.create('github pull request check contexts') - .get('/contexts/pulls/badges/shields/8486.json') - .expectBadge({ label: 'checks', message: '2 success, 4 failure' }) + .get('/contexts/pulls/badges/shields/9863.json') + .expectBadge({ label: 'checks', message: '1 success' }) diff --git a/services/github/github-release.service.js b/services/github/github-release.service.js index 4d92384625c3d..d76fb0fd822bb 100644 --- a/services/github/github-release.service.js +++ b/services/github/github-release.service.js @@ -1,17 +1,20 @@ import Joi from 'joi' import { addv } from '../text-formatters.js' import { version as versionColor } from '../color-formatters.js' -import { redirector } from '../index.js' +import { redirector, pathParam, queryParam } from '../index.js' import { GithubAuthV3Service } from './github-auth-service.js' import { fetchLatestRelease, - filterDocs, queryParamSchema, + openApiQueryParams, } from './github-common-release.js' import { documentation } from './github-helpers.js' +const displayNameEnum = ['tag', 'release'] const extendedQueryParamSchema = Joi.object({ - display_name: Joi.string().valid('tag', 'release').default('tag'), + display_name: Joi.string() + .valid(...displayNameEnum) + .default('tag'), }) class GithubRelease extends GithubAuthV3Service { @@ -22,86 +25,24 @@ class GithubRelease extends GithubAuthV3Service { queryParamSchema: queryParamSchema.concat(extendedQueryParamSchema), } - static examples = [ - { - title: 'GitHub release (latest by date)', - namedParams: { user: 'expressjs', repo: 'express' }, - queryParams: { display_name: 'tag' }, - staticPreview: this.render({ - version: 'v4.16.4', - sort: 'date', - isPrerelease: false, - }), - documentation, - }, - { - title: 'GitHub release (latest by date including pre-releases)', - namedParams: { user: 'expressjs', repo: 'express' }, - queryParams: { include_prereleases: null, display_name: 'tag' }, - staticPreview: this.render({ - version: 'v5.0.0-alpha.7', - sort: 'date', - isPrerelease: true, - }), - documentation, - }, - { - title: 'GitHub release (latest SemVer)', - namedParams: { user: 'expressjs', repo: 'express' }, - queryParams: { sort: 'semver', display_name: 'tag' }, - staticPreview: this.render({ - version: 'v4.16.4', - sort: 'semver', - isPrerelease: false, - }), - documentation, - }, - { - title: 'GitHub release (latest SemVer including pre-releases)', - namedParams: { user: 'expressjs', repo: 'express' }, - queryParams: { - sort: 'semver', - include_prereleases: null, - display_name: 'tag', - }, - staticPreview: this.render({ - version: 'v5.0.0-alpha.7', - sort: 'semver', - isPrerelease: true, - }), - documentation, - }, - { - title: 'GitHub release (release name instead of tag name)', - namedParams: { user: 'gooddata', repo: 'gooddata-java' }, - queryParams: { - sort: 'date', - include_prereleases: null, - display_name: 'release', - }, - staticPreview: this.render({ - version: '3.7.0+api3', - sort: 'date', - isPrerelease: true, - }), - documentation, - }, - { - title: 'GitHub release (with filter)', - namedParams: { user: 'RetroMusicPlayer', repo: 'RetroMusicPlayer' }, - queryParams: { - sort: 'date', - display_name: 'release', - filter: '*Open Beta', + static openApi = { + '/github/v/release/{user}/{repo}': { + get: { + summary: 'GitHub Release', + description: documentation, + parameters: [ + pathParam({ name: 'user', example: 'expressjs' }), + pathParam({ name: 'repo', example: 'express' }), + ...openApiQueryParams, + queryParam({ + name: 'display_name', + example: 'tag', + schema: { type: 'string', enum: displayNameEnum }, + }), + ], }, - staticPreview: this.render({ - version: 'Release v6.0.2 - Open Beta', - sort: 'date', - isPrerelease: false, - }), - documentation: documentation + filterDocs, }, - ] + } static defaultBadgeData = { label: 'release', namedLogo: 'github' } diff --git a/services/github/github-tag.service.js b/services/github/github-tag.service.js index 1fc7b3f0007b3..2c6fa6224e99a 100644 --- a/services/github/github-tag.service.js +++ b/services/github/github-tag.service.js @@ -4,9 +4,12 @@ import { matcher } from 'matcher' import { addv } from '../text-formatters.js' import { version as versionColor } from '../color-formatters.js' import { latest } from '../version.js' -import { NotFound, redirector } from '../index.js' +import { NotFound, redirector, pathParam } from '../index.js' import { GithubAuthV4Service } from './github-auth-service.js' -import { filterDocs, queryParamSchema } from './github-common-release.js' +import { + queryParamSchema, + openApiQueryParams, +} from './github-common-release.js' import { documentation, transformErrors } from './github-helpers.js' const schema = Joi.object({ @@ -34,44 +37,19 @@ class GithubTag extends GithubAuthV4Service { queryParamSchema, } - static examples = [ - { - title: 'GitHub tag (latest by date)', - namedParams: { user: 'expressjs', repo: 'express' }, - staticPreview: this.render({ - version: 'v5.0.0-alpha.7', - sort: 'date', - }), - documentation, - }, - { - title: 'GitHub tag (latest SemVer)', - namedParams: { user: 'expressjs', repo: 'express' }, - queryParams: { sort: 'semver' }, - staticPreview: this.render({ version: 'v4.16.4', sort: 'semver' }), - documentation, - }, - { - title: 'GitHub tag (latest SemVer pre-release)', - namedParams: { user: 'expressjs', repo: 'express' }, - queryParams: { sort: 'semver', include_prereleases: null }, - staticPreview: this.render({ - version: 'v5.0.0-alpha.7', - sort: 'semver', - }), - documentation, + static openApi = { + '/github/v/tag/{user}/{repo}': { + get: { + summary: 'GitHub Tag', + description: documentation, + parameters: [ + pathParam({ name: 'user', example: 'expressjs' }), + pathParam({ name: 'repo', example: 'express' }), + ...openApiQueryParams, + ], + }, }, - { - title: 'GitHub tag (with filter)', - namedParams: { user: 'badges', repo: 'shields' }, - queryParams: { filter: '!server-*' }, - staticPreview: this.render({ - version: 'v3.3.1', - sort: 'date', - }), - documentation: documentation + filterDocs, - }, - ] + } static defaultBadgeData = { label: 'tag',