Files
shields/services/github/github-check-runs.service.js
Marc Bernard 12f54f3375 Add [GithubCheckRuns] service (#7759)
* Add [GithubCheckRuns] service

* Adjust ref parameter

* Rework

* Prettier

* Prettier

* Function

* Prettier

* Change CR to LF

* Adjust after #9233

* Lint camelCase

* Fix camelCase

* Fix prettier

* Switch to openAPI spec for examples

* Fix type of parameters

* Fix too many brackets

* Lint

* Add optional name filter

* Update tests

* Remove logo
2024-05-25 10:35:25 +00:00

170 lines
4.7 KiB
JavaScript

import Joi from 'joi'
import countBy from 'lodash.countby'
import { pathParam, queryParam } from '../index.js'
import { nonNegativeInteger } from '../validators.js'
import { renderBuildStatusBadge } from '../build-status.js'
import { GithubAuthV3Service } from './github-auth-service.js'
import {
documentation as commonDocumentation,
httpErrorsFor,
} from './github-helpers.js'
const description = `
The Check Runs service shows the status of GitHub action runs.
${commonDocumentation}
`
const schema = Joi.object({
total_count: nonNegativeInteger,
check_runs: Joi.array()
.items(
Joi.object({
name: Joi.string().required(),
status: Joi.equal('completed', 'in_progress', 'queued').required(),
conclusion: Joi.equal(
'action_required',
'cancelled',
'failure',
'neutral',
'skipped',
'success',
'timed_out',
null,
).required(),
}),
)
.default([]),
}).required()
const queryParamSchema = Joi.object({
nameFilter: Joi.string(),
})
export default class GithubCheckRuns extends GithubAuthV3Service {
static category = 'build'
static route = {
base: 'github/check-runs',
pattern: ':user/:repo/:ref+',
queryParamSchema,
}
static openApi = {
'/github/check-runs/{user}/{repo}/{branch}': {
get: {
summary: 'GitHub branch check runs',
description,
parameters: [
pathParam({ name: 'user', example: 'badges' }),
pathParam({ name: 'repo', example: 'shields' }),
pathParam({ name: 'branch', example: 'master' }),
queryParam({
name: 'nameFilter',
description: 'Name of a check run',
example: 'test-lint',
}),
],
},
},
'/github/check-runs/{user}/{repo}/{commit}': {
get: {
summary: 'GitHub commit check runs',
description,
parameters: [
pathParam({ name: 'user', example: 'badges' }),
pathParam({ name: 'repo', example: 'shields' }),
pathParam({
name: 'commit',
example: '91b108d4b7359b2f8794a4614c11cb1157dc9fff',
}),
queryParam({
name: 'nameFilter',
description: 'Name of a check run',
example: 'test-lint',
}),
],
},
},
'/github/check-runs/{user}/{repo}/{tag}': {
get: {
summary: 'GitHub tag check runs',
description,
parameters: [
pathParam({ name: 'user', example: 'badges' }),
pathParam({ name: 'repo', example: 'shields' }),
pathParam({ name: 'tag', example: '3.3.0' }),
queryParam({
name: 'nameFilter',
description: 'Name of a check run',
example: 'test-lint',
}),
],
},
},
}
static defaultBadgeData = { label: 'checks' }
static transform(
{ total_count: totalCount, check_runs: checkRuns },
nameFilter,
) {
const filteredCheckRuns =
nameFilter && nameFilter.length > 0
? checkRuns.filter(checkRun => checkRun.name === nameFilter)
: checkRuns
return {
total: totalCount,
statusCounts: countBy(filteredCheckRuns, 'status'),
conclusionCounts: countBy(filteredCheckRuns, 'conclusion'),
}
}
static mapState({ total, statusCounts, conclusionCounts }) {
let state
if (total === 0) {
state = 'no check runs'
} else if (statusCounts.queued) {
state = 'queued'
} else if (statusCounts.in_progress) {
state = 'pending'
} else if (statusCounts.completed) {
// all check runs are completed, now evaluate conclusions
const orangeStates = ['action_required', 'stale']
const redStates = ['cancelled', 'failure', 'timed_out']
// assume "passing (green)"
state = 'passing'
for (const stateValue of Object.keys(conclusionCounts)) {
if (orangeStates.includes(stateValue)) {
// orange state renders "passing (orange)"
state = 'partially succeeded'
} else if (redStates.includes(stateValue)) {
// red state renders "failing (red)"
state = 'failing'
break
}
}
} else {
state = 'unknown status'
}
return state
}
async handle({ user, repo, ref }, { nameFilter }) {
// https://docs.github.com/en/rest/checks/runs#list-check-runs-for-a-git-reference
const json = await this._requestJson({
url: `/repos/${user}/${repo}/commits/${ref}/check-runs`,
httpErrors: httpErrorsFor('ref or repo not found'),
schema,
})
const state = this.constructor.mapState(
this.constructor.transform(json, nameFilter),
)
return renderBuildStatusBadge({ status: state })
}
}