Skip to content

Commit 4768ce9

Browse files
feat: add GitHub Actions support via API
1 parent 9c5ecc2 commit 4768ce9

File tree

4 files changed

+169
-1
lines changed

4 files changed

+169
-1
lines changed
+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
'use strict'
2+
3+
const Joi = require('@hapi/joi')
4+
const { renderBuildStatusBadge } = require('../build-status')
5+
const { nonNegativeInteger } = require('../validators')
6+
const { GithubAuthV3Service } = require('./github-auth-service')
7+
const { documentation, errorMessagesFor } = require('./github-helpers')
8+
const { NotFound } = require('..')
9+
10+
const schema = Joi.object({
11+
total_count: nonNegativeInteger,
12+
check_suites: Joi.array()
13+
.items(
14+
Joi.object({
15+
status: Joi.string().required(),
16+
conclusion: Joi.string()
17+
.required()
18+
.allow(null),
19+
app: Joi.object({
20+
id: nonNegativeInteger,
21+
name: Joi.string().required(),
22+
}).required(),
23+
})
24+
)
25+
.min(0)
26+
.required(),
27+
}).required()
28+
29+
module.exports = class GitHubActions extends GithubAuthV3Service {
30+
static get category() {
31+
return 'build'
32+
}
33+
34+
static get route() {
35+
return {
36+
base: 'github/actions',
37+
pattern: ':user/:repo/:ref',
38+
}
39+
}
40+
41+
static get examples() {
42+
return [
43+
{
44+
title: 'GitHub Actions',
45+
namedParams: {
46+
user: 'actions',
47+
repo: 'setup-node',
48+
ref: 'master',
49+
},
50+
staticPreview: renderBuildStatusBadge({ status: 'success' }),
51+
documentation: `
52+
You can use a branch name, tag, or commit SHA for the ref parameter.
53+
${documentation}
54+
`,
55+
},
56+
]
57+
}
58+
59+
static get defaultBadgeData() {
60+
return {
61+
label: 'workflow',
62+
}
63+
}
64+
65+
static render({ status, conclusion }) {
66+
if (status !== 'completed') {
67+
return {
68+
message: 'in progress',
69+
}
70+
}
71+
return renderBuildStatusBadge({ status: conclusion })
72+
}
73+
74+
async fetch({ user, repo, ref }) {
75+
return this._requestJson({
76+
url: `/repos/${user}/${repo}/commits/${ref}/check-suites`,
77+
options: {
78+
headers: {
79+
Accept: 'application/vnd.github.antiope-preview+json',
80+
},
81+
},
82+
schema,
83+
errorMessages: errorMessagesFor('repo or ref not found'),
84+
})
85+
}
86+
87+
transform(json) {
88+
if (json.total_count === 0) {
89+
throw new NotFound({ prettyMessage: 'no GitHub Actions found' })
90+
}
91+
92+
const actionsSuite = json.check_suites.find(
93+
suite => suite.app.name.toLowerCase() === 'github actions'
94+
)
95+
if (!actionsSuite) {
96+
throw new NotFound({ prettyMessage: 'no GitHub Actions found' })
97+
}
98+
99+
return { status: actionsSuite.status, conclusion: actionsSuite.conclusion }
100+
}
101+
102+
async handle({ user, repo, ref }) {
103+
const json = await this.fetch({ user, repo, ref })
104+
const { status, conclusion } = this.transform(json)
105+
return this.constructor.render({ status, conclusion })
106+
}
107+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict'
2+
3+
const { test, given, forCases } = require('sazerac')
4+
const GitHubActions = require('./github-actions.service')
5+
6+
describe('GitHubActions', function() {
7+
test(GitHubActions.render, () => {
8+
forCases([
9+
given({
10+
status: 'queued',
11+
conclusion: null,
12+
}),
13+
given({
14+
status: 'pending',
15+
conclusion: null,
16+
}),
17+
]).expect({
18+
message: 'in progress',
19+
})
20+
})
21+
})
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict'
2+
3+
const { isBuildStatus } = require('../build-status')
4+
const t = (module.exports = require('../tester').createServiceTester())
5+
6+
t.create('valid repo and ref')
7+
.get('/actions/setup-node/master.json')
8+
.expectBadge({
9+
label: 'workflow',
10+
message: isBuildStatus,
11+
})
12+
13+
t.create('valid repo and invalid ref')
14+
.get('/actions/setup-node/not-a-real-branch-or-tag-or-commit.json')
15+
.expectBadge({
16+
label: 'workflow',
17+
message: 'repo or ref not found',
18+
})
19+
20+
t.create('invalid repo')
21+
.get('/actions/setup-node123abcdef456/master.json')
22+
.expectBadge({
23+
label: 'workflow',
24+
message: 'repo or ref not found',
25+
})
26+
27+
t.create('no check suites')
28+
.get('/badges/ServerScript/master.json')
29+
.expectBadge({
30+
label: 'workflow',
31+
message: 'no GitHub Actions found',
32+
})
33+
34+
t.create('no GitHub Actions')
35+
.get('/badges/shields/master.json')
36+
.expectBadge({
37+
label: 'workflow',
38+
message: 'no GitHub Actions found',
39+
})

services/github/github-api-provider.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ class GithubApiProvider {
185185
baseUrl,
186186
headers: {
187187
'User-Agent': 'Shields.io',
188-
Accept: 'application/vnd.github.v3+json',
188+
Accept:
189+
'application/vnd.github.v3+json, application/vnd.github.antiope-preview+json',
189190
Authorization: `token ${tokenString}`,
190191
},
191192
},

0 commit comments

Comments
 (0)