Skip to content

Commit d1f00b8

Browse files
authored
ci: Add tests for new update-issues tool (shaka-project#3900)
This ports over internal tests suggested in shaka-project#3889.
1 parent 69b2769 commit d1f00b8

File tree

8 files changed

+967
-23
lines changed

8 files changed

+967
-23
lines changed

.github/workflows/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
Lints the player, and builds and tests each combination of OS and browser.
66
- 'update_issues.yaml':
77
Updates GitHub issues on a timer.
8+
- 'test_update_issues.yaml':
9+
Runs tests on the update-issues tool when it changes.
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Test Update Issues Tool
2+
3+
on:
4+
pull_request: # Trigger for pull requests.
5+
types: [opened, synchronize, reopened]
6+
paths:
7+
.github/workflows/tools/update-issues/**
8+
workflow_dispatch: # Allows for manual triggering.
9+
inputs:
10+
ref:
11+
description: "The ref to build and test."
12+
required: False
13+
14+
jobs:
15+
test:
16+
name: Test Update Issues Tool
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Checkout code
20+
uses: actions/checkout@v2
21+
with:
22+
ref: ${{ github.event.inputs.ref || github.ref }}
23+
24+
- name: Test
25+
run: |
26+
cd .github/workflows/tools/update-issues
27+
npm install
28+
npm test

.github/workflows/tools/update-issues/main.js

+55-20
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ const core = require('@actions/core');
1212
const { Issue, Milestone } = require('./issues.js');
1313

1414
const TYPE_ACCESSIBILITY = 'type: accessibility';
15+
const TYPE_ANNOUNCEMENT = 'type: announcement';
1516
const TYPE_BUG = 'type: bug';
1617
const TYPE_CI = 'type: CI';
1718
const TYPE_CODE_HEALTH = 'type: code health';
1819
const TYPE_DOCS = 'type: docs';
1920
const TYPE_ENHANCEMENT = 'type: enhancement';
2021
const TYPE_PERFORMANCE = 'type: performance';
22+
const TYPE_PROCESS = 'type: process';
2123
const TYPE_QUESTION = 'type: question';
2224

25+
const PRIORITY_P0 = 'priority: P0';
26+
const PRIORITY_P1 = 'priority: P1';
27+
const PRIORITY_P2 = 'priority: P2';
2328
const PRIORITY_P3 = 'priority: P3';
2429
const PRIORITY_P4 = 'priority: P4';
2530

@@ -196,24 +201,9 @@ const ALL_ISSUE_TASKS = [
196201
maintainMilestones,
197202
];
198203

199-
async function main() {
200-
const milestones = await Milestone.getAll();
201-
const issues = await Issue.getAll();
202-
203-
const backlog = milestones.find(m => m.isBacklog());
204-
if (!backlog) {
205-
core.error('No backlog milestone found!');
206-
process.exit(1);
207-
}
204+
async function processIssues(issues, nextMilestone, backlog) {
205+
let success = true;
208206

209-
milestones.sort(Milestone.compare);
210-
const nextMilestone = milestones[0];
211-
if (nextMilestone.version == null) {
212-
core.error('No version milestone found!');
213-
process.exit(1);
214-
}
215-
216-
let failed = false;
217207
for (const issue of issues) {
218208
if (issue.hasLabel(FLAG_IGNORE)) {
219209
core.info(`Ignoring issue #${issue.number}`);
@@ -231,14 +221,59 @@ async function main() {
231221
core.error(
232222
`Failed to process issue #${issue.number} in task ${task.name}: ` +
233223
`${error}\n${error.stack}`);
234-
failed = true;
224+
success = false;
235225
}
236226
}
237227
}
238228

239-
if (failed) {
229+
return success;
230+
}
231+
232+
async function main() {
233+
const milestones = await Milestone.getAll();
234+
const issues = await Issue.getAll();
235+
236+
const backlog = milestones.find(m => m.isBacklog());
237+
if (!backlog) {
238+
core.error('No backlog milestone found!');
239+
process.exit(1);
240+
}
241+
242+
milestones.sort(Milestone.compare);
243+
const nextMilestone = milestones[0];
244+
if (nextMilestone.version == null) {
245+
core.error('No version milestone found!');
246+
process.exit(1);
247+
}
248+
249+
const success = await processIssues(issues, nextMilestone, backlog);
250+
if (!success) {
240251
process.exit(1);
241252
}
242253
}
243254

244-
main();
255+
// If this file is the entrypoint, run main. Otherwise, export certain pieces
256+
// to the tests.
257+
if (require.main == module) {
258+
main();
259+
} else {
260+
module.exports = {
261+
processIssues,
262+
TYPE_ACCESSIBILITY,
263+
TYPE_ANNOUNCEMENT,
264+
TYPE_BUG,
265+
TYPE_CODE_HEALTH,
266+
TYPE_DOCS,
267+
TYPE_ENHANCEMENT,
268+
TYPE_PROCESS,
269+
TYPE_QUESTION,
270+
PRIORITY_P0,
271+
PRIORITY_P1,
272+
PRIORITY_P2,
273+
PRIORITY_P3,
274+
PRIORITY_P4,
275+
STATUS_ARCHIVED,
276+
STATUS_WAITING,
277+
FLAG_IGNORE,
278+
};
279+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*! @license
2+
* Shaka Player
3+
* Copyright 2016 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @fileoverview Mocks for the classes in issues.js
9+
*/
10+
11+
function randomInt() {
12+
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
13+
}
14+
let nextIssueNumber = 1;
15+
16+
class MockGitHubObject {
17+
constructor(subclassDefaults, params) {
18+
const defaults = {
19+
id: randomInt(),
20+
ageInDays: 0,
21+
closedDays: 0,
22+
23+
...subclassDefaults,
24+
};
25+
26+
const mergedParams = {
27+
...defaults,
28+
...params,
29+
};
30+
31+
for (const k in mergedParams) {
32+
this[k] = mergedParams[k];
33+
}
34+
}
35+
36+
toString() {
37+
return JSON.stringify(this, null, ' ');
38+
}
39+
}
40+
41+
class MockMilestone extends MockGitHubObject {
42+
constructor(params) {
43+
const defaults = {
44+
title: 'MockMilestone',
45+
version: null,
46+
closed: false,
47+
isBacklog: () => false,
48+
};
49+
50+
super(defaults, params);
51+
}
52+
}
53+
54+
class MockComment extends MockGitHubObject {
55+
constructor(params) {
56+
const defaults = {
57+
author: 'SomeUser',
58+
body: 'Howdy!',
59+
authorAssociation: 'NONE',
60+
fromTeam: false,
61+
};
62+
63+
super(defaults, params);
64+
}
65+
}
66+
67+
class MockIssue extends MockGitHubObject {
68+
constructor(params) {
69+
const defaults = {
70+
number: nextIssueNumber++,
71+
author: 'SomeUser',
72+
labels: [],
73+
closed: false,
74+
locked: false,
75+
milestone: null,
76+
comments: [],
77+
};
78+
79+
super(defaults, params);
80+
81+
this.getLabelAgeInDays =
82+
jasmine.createSpy('getLabelAgeInDays')
83+
.and.returnValue(params.labelAgeInDays || 0);
84+
this.addLabel = jasmine.createSpy('addLabel').and.callFake((name) => {
85+
console.log(`Adding label ${name}`);
86+
});
87+
this.removeLabel = jasmine.createSpy('removeLabel').and.callFake((name) => {
88+
console.log(`Removing label ${name}`);
89+
});
90+
this.lock = jasmine.createSpy('lock').and.callFake(() => {
91+
console.log('Locking');
92+
});
93+
this.unlock = jasmine.createSpy('unlock').and.callFake(() => {
94+
console.log('Unlocking');
95+
});
96+
this.close = jasmine.createSpy('close').and.callFake(() => {
97+
console.log('Closing');
98+
});
99+
this.reopen = jasmine.createSpy('reopen').and.callFake(() => {
100+
console.log('Reopening');
101+
});
102+
this.setMilestone =
103+
jasmine.createSpy('setMilestone').and.callFake((milestone) => {
104+
console.log(`Setting milestone to "${milestone.title}"`);
105+
});
106+
this.removeMilestone =
107+
jasmine.createSpy('removeMilestone').and.callFake(() => {
108+
console.log('Removing milestone.');
109+
});
110+
this.postComment = jasmine.createSpy('postComment').and.callFake((body) => {
111+
console.log(`Posting comment: ${body}`);
112+
});
113+
this.loadComments = jasmine.createSpy('loadComments');
114+
}
115+
116+
hasLabel(name) {
117+
return this.labels.includes(name);
118+
}
119+
120+
hasAnyLabel(names) {
121+
return this.labels.some(l => names.includes(l));
122+
}
123+
}
124+
125+
module.exports = {
126+
MockMilestone,
127+
MockComment,
128+
MockIssue,
129+
};

0 commit comments

Comments
 (0)