@opentermsarchive/engine 2.3.2 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentermsarchive/engine",
3
- "version": "2.3.2",
3
+ "version": "2.3.3",
4
4
  "description": "Tracks and makes visible changes to the terms of online services",
5
5
  "homepage": "https://opentermsarchive.org",
6
6
  "bugs": {
@@ -28,6 +28,24 @@ export default class GitHub {
28
28
  const [ owner, repo ] = repository.split('/');
29
29
 
30
30
  this.commonParams = { owner, repo };
31
+
32
+ this.issuesCache = new Map();
33
+ this._issuesPromise = null;
34
+ }
35
+
36
+ get issues() {
37
+ if (!this._issuesPromise) {
38
+ logger.info('Loading issues from GitHub…');
39
+ this._issuesPromise = this.loadAllIssues();
40
+ }
41
+
42
+ return this._issuesPromise;
43
+ }
44
+
45
+ clearCache() {
46
+ this.issuesCache.clear();
47
+ this._issuesPromise = null;
48
+ logger.info('Issues cache cleared');
31
49
  }
32
50
 
33
51
  async initialize() {
@@ -53,6 +71,33 @@ export default class GitHub {
53
71
  }
54
72
  }
55
73
 
74
+ async loadAllIssues() {
75
+ try {
76
+ const issues = await this.octokit.paginate('GET /repos/{owner}/{repo}/issues', {
77
+ ...this.commonParams,
78
+ state: GitHub.ISSUE_STATE_ALL,
79
+ per_page: 100,
80
+ });
81
+
82
+ const onlyIssues = issues.filter(issue => !issue.pull_request); // Filter out pull requests since GitHub treats them as a special type of issue
83
+
84
+ onlyIssues.forEach(issue => {
85
+ const cachedIssue = this.issuesCache.get(issue.title);
86
+
87
+ if (!cachedIssue || new Date(issue.created_at) < new Date(cachedIssue.created_at)) { // Only work on the oldest issue if there are duplicates, in order to consolidate the longest history possible
88
+ this.issuesCache.set(issue.title, issue);
89
+ }
90
+ });
91
+
92
+ logger.info(`Cached ${onlyIssues.length} issues from the GitHub repository`);
93
+
94
+ return this.issuesCache;
95
+ } catch (error) {
96
+ logger.error(`Failed to load issues: ${error.message}`);
97
+ throw error;
98
+ }
99
+ }
100
+
56
101
  async getRepositoryLabels() {
57
102
  const { data: labels } = await this.octokit.request('GET /repos/{owner}/{repo}/labels', { ...this.commonParams });
58
103
 
@@ -68,6 +113,10 @@ export default class GitHub {
68
113
  });
69
114
  }
70
115
 
116
+ async getIssue(title) {
117
+ return (await this.issues).get(title);
118
+ }
119
+
71
120
  async createIssue({ title, description: body, labels }) {
72
121
  const { data: issue } = await this.octokit.request('POST /repos/{owner}/{repo}/issues', {
73
122
  ...this.commonParams,
@@ -76,6 +125,8 @@ export default class GitHub {
76
125
  labels,
77
126
  });
78
127
 
128
+ this.issuesCache.set(issue.title, issue);
129
+
79
130
  return issue;
80
131
  }
81
132
 
@@ -87,19 +138,9 @@ export default class GitHub {
87
138
  labels,
88
139
  });
89
140
 
90
- return updatedIssue;
91
- }
92
-
93
- async getIssue({ title, ...searchParams }) {
94
- const issues = await this.octokit.paginate('GET /repos/{owner}/{repo}/issues', {
95
- ...this.commonParams,
96
- per_page: 100,
97
- ...searchParams,
98
- }, response => response.data);
99
-
100
- const [issue] = issues.filter(item => item.title === title); // Since only one is expected, use the first one
141
+ this.issuesCache.set(updatedIssue.title, updatedIssue);
101
142
 
102
- return issue;
143
+ return updatedIssue;
103
144
  }
104
145
 
105
146
  async addCommentToIssue({ issue, comment: body }) {
@@ -114,25 +155,25 @@ export default class GitHub {
114
155
 
115
156
  async closeIssueWithCommentIfExists({ title, comment }) {
116
157
  try {
117
- const openedIssue = await this.getIssue({ title, state: GitHub.ISSUE_STATE_OPEN });
158
+ const issue = await this.getIssue(title);
118
159
 
119
- if (!openedIssue) {
160
+ if (!issue || issue.state == GitHub.ISSUE_STATE_CLOSED) {
120
161
  return;
121
162
  }
122
163
 
123
- await this.addCommentToIssue({ issue: openedIssue, comment });
124
- logger.info(`Added comment to issue #${openedIssue.number}: ${openedIssue.html_url}`);
164
+ await this.addCommentToIssue({ issue, comment });
165
+
166
+ const updatedIssue = await this.updateIssue(issue, { state: GitHub.ISSUE_STATE_CLOSED });
125
167
 
126
- await this.updateIssue(openedIssue, { state: GitHub.ISSUE_STATE_CLOSED });
127
- logger.info(`Closed issue #${openedIssue.number}: ${openedIssue.html_url}`);
168
+ logger.info(`Closed issue with comment #${updatedIssue.number}: ${updatedIssue.html_url}`);
128
169
  } catch (error) {
129
- logger.error(`Failed to update issue "${title}": ${error.message}`);
170
+ logger.error(`Failed to close issue with comment "${title}": ${error.stack}`);
130
171
  }
131
172
  }
132
173
 
133
174
  async createOrUpdateIssue({ title, description, label }) {
134
175
  try {
135
- const issue = await this.getIssue({ title, state: GitHub.ISSUE_STATE_ALL });
176
+ const issue = await this.getIssue(title);
136
177
 
137
178
  if (!issue) {
138
179
  const createdIssue = await this.createIssue({ title, description, labels: [label] });
@@ -148,16 +189,13 @@ export default class GitHub {
148
189
  return;
149
190
  }
150
191
 
151
- await this.updateIssue(issue, {
152
- state: GitHub.ISSUE_STATE_OPEN,
153
- labels: [ label, ...labelsNotManagedToKeep ],
154
- });
155
- logger.info(`Updated issue #${issue.number}: ${issue.html_url}`);
192
+ const updatedIssue = await this.updateIssue(issue, { state: GitHub.ISSUE_STATE_OPEN, labels: [ label, ...labelsNotManagedToKeep ] });
193
+
156
194
  await this.addCommentToIssue({ issue, comment: description });
157
195
 
158
- logger.info(`Added comment to issue #${issue.number}: ${issue.html_url}`);
196
+ logger.info(`Updated issue with comment #${updatedIssue.number}: ${updatedIssue.html_url}`);
159
197
  } catch (error) {
160
- logger.error(`Failed to update issue "${title}": ${error.message}`);
198
+ logger.error(`Failed to update issue "${title}": ${error.stack}`);
161
199
  }
162
200
  }
163
201
  }
@@ -12,10 +12,17 @@ describe('GitHub', function () {
12
12
 
13
13
  let MANAGED_LABELS;
14
14
  let github;
15
+ const EXISTING_OPEN_ISSUE = { number: 1, title: 'Opened issue', description: 'Issue description', state: GitHub.ISSUE_STATE_OPEN, labels: [{ name: 'location' }] };
16
+ const EXISTING_CLOSED_ISSUE = { number: 2, title: 'Closed issue', description: 'Issue description', state: GitHub.ISSUE_STATE_CLOSED, labels: [{ name: '403' }] };
15
17
 
16
- before(() => {
18
+ before(async () => {
17
19
  MANAGED_LABELS = require('./labels.json');
18
20
  github = new GitHub('owner/repo');
21
+ nock('https://api.github.com')
22
+ .get('/repos/owner/repo/issues')
23
+ .query(true)
24
+ .reply(200, [ EXISTING_OPEN_ISSUE, EXISTING_CLOSED_ISSUE ]);
25
+ await github.clearCache();
19
26
  });
20
27
 
21
28
  describe('#initialize', () => {
@@ -71,77 +78,88 @@ describe('GitHub', function () {
71
78
  });
72
79
 
73
80
  describe('#createLabel', () => {
74
- let scope;
75
81
  const LABEL = { name: 'new_label', color: 'ffffff' };
76
82
 
77
- before(async () => {
78
- scope = nock('https://api.github.com')
83
+ afterEach(nock.cleanAll);
84
+
85
+ it('creates the new label successfully', async () => {
86
+ const scope = nock('https://api.github.com')
79
87
  .post('/repos/owner/repo/labels', body => body.name === LABEL.name)
80
88
  .reply(200, LABEL);
81
89
 
82
90
  await github.createLabel(LABEL);
91
+ expect(scope.isDone()).to.be.true;
83
92
  });
84
93
 
85
- after(nock.cleanAll);
94
+ it('throws an error when creating a label fails', async () => {
95
+ nock('https://api.github.com')
96
+ .post('/repos/owner/repo/labels')
97
+ .reply(400, { message: 'Bad Request' });
86
98
 
87
- it('creates the new label', () => {
88
- expect(scope.isDone()).to.be.true;
99
+ await expect(github.createLabel(LABEL)).to.be.rejected;
89
100
  });
90
101
  });
91
102
 
92
103
  describe('#createIssue', () => {
93
104
  let scope;
94
105
  let result;
106
+
95
107
  const ISSUE = {
96
108
  title: 'New Issue',
97
109
  description: 'Description of the new issue',
98
- labels: ['bug'],
110
+ labels: [{ name: 'bug' }],
99
111
  };
100
112
  const CREATED_ISSUE = { number: 123, ...ISSUE };
101
113
 
102
114
  before(async () => {
103
115
  scope = nock('https://api.github.com')
104
- .post('/repos/owner/repo/issues', request => request.title === ISSUE.title && request.body === ISSUE.description && request.labels[0] === ISSUE.labels[0])
116
+ .post('/repos/owner/repo/issues', request =>
117
+ request.title === ISSUE.title && request.body === ISSUE.description && request.labels[0].name === ISSUE.labels[0].name)
105
118
  .reply(200, CREATED_ISSUE);
106
119
 
107
120
  result = await github.createIssue(ISSUE);
108
121
  });
109
122
 
110
- after(nock.cleanAll);
123
+ after(() => {
124
+ nock.cleanAll();
125
+ github.issuesCache.delete(ISSUE.title);
126
+ });
111
127
 
112
128
  it('creates the new issue', () => {
113
129
  expect(scope.isDone()).to.be.true;
114
130
  });
115
131
 
116
- it('returns the created issue', () => {
132
+ it('returns the newly created issue', () => {
117
133
  expect(result).to.deep.equal(CREATED_ISSUE);
118
134
  });
119
- });
120
135
 
121
- describe('#getIssue', () => {
122
- let scope;
123
- let result;
136
+ it('throws error when creating issue fails', async () => {
137
+ nock('https://api.github.com')
138
+ .post('/repos/owner/repo/issues')
139
+ .reply(400, { message: 'Bad Request' });
124
140
 
125
- const ISSUE = { number: 123, title: 'Test Issue' };
126
- const ANOTHER_ISSUE = { number: 124, title: 'Test Issue 2' };
141
+ await expect(github.createIssue(ISSUE)).to.be.rejected;
142
+ });
143
+ });
127
144
 
128
- before(async () => {
129
- scope = nock('https://api.github.com')
145
+ describe('#getIssue', () => {
146
+ before(() => {
147
+ nock('https://api.github.com')
130
148
  .get('/repos/owner/repo/issues')
131
149
  .query(true)
132
- .reply(200, [ ISSUE, ANOTHER_ISSUE ]);
133
-
134
- result = await github.getIssue({ title: ISSUE.title });
150
+ .reply(200, [ EXISTING_OPEN_ISSUE, EXISTING_CLOSED_ISSUE ]);
135
151
  });
136
152
 
137
- after(nock.cleanAll);
138
-
139
- it('searches for the issue', () => {
140
- expect(scope.isDone()).to.be.true;
153
+ context('when the issue exists in the cache', () => {
154
+ it('returns the cached issue', async () => {
155
+ expect(await github.getIssue(EXISTING_OPEN_ISSUE.title)).to.deep.equal(EXISTING_OPEN_ISSUE);
156
+ });
141
157
  });
142
158
 
143
- it('returns the expected issue', () => {
144
- expect(result).to.deep.equal(ISSUE);
159
+ context('when the issue does not exist in the cache', () => {
160
+ it('returns undefined', async () => {
161
+ expect(await github.getIssue('Non-existent Issue')).to.be.undefined;
162
+ });
145
163
  });
146
164
  });
147
165
 
@@ -163,35 +181,33 @@ describe('GitHub', function () {
163
181
  it('adds the comment to the issue', () => {
164
182
  expect(scope.isDone()).to.be.true;
165
183
  });
184
+
185
+ it('throws an error when adding a comment fails', async () => {
186
+ nock('https://api.github.com')
187
+ .post(`/repos/owner/repo/issues/${ISSUE_NUMBER}/comments`)
188
+ .reply(400, { message: 'Bad Request' });
189
+
190
+ await expect(github.addCommentToIssue({ issue: { number: ISSUE_NUMBER }, comment: COMMENT })).to.be.rejected;
191
+ });
166
192
  });
167
193
 
168
194
  describe('#closeIssueWithCommentIfExists', () => {
169
195
  after(nock.cleanAll);
170
196
 
171
197
  context('when the issue exists and is open', () => {
172
- const ISSUE = {
173
- number: 123,
174
- title: 'Open Issue',
175
- state: GitHub.ISSUE_STATE_OPEN,
176
- };
177
198
  let addCommentScope;
178
199
  let closeIssueScope;
179
200
 
180
201
  before(async () => {
181
- nock('https://api.github.com')
182
- .get('/repos/owner/repo/issues')
183
- .query(true)
184
- .reply(200, [ISSUE]);
185
-
186
202
  addCommentScope = nock('https://api.github.com')
187
- .post(`/repos/owner/repo/issues/${ISSUE.number}/comments`)
203
+ .post(`/repos/owner/repo/issues/${EXISTING_OPEN_ISSUE.number}/comments`)
188
204
  .reply(200);
189
205
 
190
206
  closeIssueScope = nock('https://api.github.com')
191
- .patch(`/repos/owner/repo/issues/${ISSUE.number}`, { state: GitHub.ISSUE_STATE_CLOSED })
207
+ .patch(`/repos/owner/repo/issues/${EXISTING_OPEN_ISSUE.number}`, { state: GitHub.ISSUE_STATE_CLOSED })
192
208
  .reply(200);
193
209
 
194
- await github.closeIssueWithCommentIfExists({ title: ISSUE.title, comment: 'Closing comment' });
210
+ await github.closeIssueWithCommentIfExists({ title: EXISTING_OPEN_ISSUE.title, comment: 'Closing comment' });
195
211
  });
196
212
 
197
213
  it('adds comment to the issue', () => {
@@ -204,29 +220,19 @@ describe('GitHub', function () {
204
220
  });
205
221
 
206
222
  context('when the issue exists and is closed', () => {
207
- const ISSUE = {
208
- number: 123,
209
- title: 'Closed Issue',
210
- state: GitHub.ISSUE_STATE_CLOSED,
211
- };
212
223
  let addCommentScope;
213
224
  let closeIssueScope;
214
225
 
215
226
  before(async () => {
216
- nock('https://api.github.com')
217
- .get('/repos/owner/repo/issues')
218
- .query(true)
219
- .reply(200, []);
220
-
221
227
  addCommentScope = nock('https://api.github.com')
222
- .post(`/repos/owner/repo/issues/${ISSUE.number}/comments`)
228
+ .post(`/repos/owner/repo/issues/${EXISTING_CLOSED_ISSUE.number}/comments`)
223
229
  .reply(200);
224
230
 
225
231
  closeIssueScope = nock('https://api.github.com')
226
- .patch(`/repos/owner/repo/issues/${ISSUE.number}`, { state: GitHub.ISSUE_STATE_CLOSED })
232
+ .patch(`/repos/owner/repo/issues/${EXISTING_CLOSED_ISSUE.number}`, { state: GitHub.ISSUE_STATE_CLOSED })
227
233
  .reply(200);
228
234
 
229
- await github.closeIssueWithCommentIfExists({ title: ISSUE.title, comment: 'Closing comment' });
235
+ await github.closeIssueWithCommentIfExists({ title: EXISTING_CLOSED_ISSUE.title, comment: 'Closing comment' });
230
236
  });
231
237
 
232
238
  it('does not add comment', () => {
@@ -243,11 +249,6 @@ describe('GitHub', function () {
243
249
  let closeIssueScope;
244
250
 
245
251
  before(async () => {
246
- nock('https://api.github.com')
247
- .get('/repos/owner/repo/issues')
248
- .query(true)
249
- .reply(200, []);
250
-
251
252
  addCommentScope = nock('https://api.github.com')
252
253
  .post(/\/repos\/owner\/repo\/issues\/\d+\/comments/)
253
254
  .reply(200);
@@ -270,12 +271,8 @@ describe('GitHub', function () {
270
271
  });
271
272
 
272
273
  describe('#createOrUpdateIssue', () => {
273
- before(async () => {
274
- nock('https://api.github.com')
275
- .get('/repos/owner/repo/labels')
276
- .reply(200, MANAGED_LABELS);
277
-
278
- await github.initialize();
274
+ before(() => {
275
+ github.MANAGED_LABELS = require('./labels.json');
279
276
  });
280
277
 
281
278
  context('when the issue does not exist', () => {
@@ -287,11 +284,6 @@ describe('GitHub', function () {
287
284
  };
288
285
 
289
286
  before(async () => {
290
- nock('https://api.github.com')
291
- .get('/repos/owner/repo/issues')
292
- .query(true)
293
- .reply(200, []); // Simulate that there is no issues on the repository
294
-
295
287
  createIssueScope = nock('https://api.github.com')
296
288
  .post('/repos/owner/repo/issues', {
297
289
  title: ISSUE_TO_CREATE.title,
@@ -303,48 +295,38 @@ describe('GitHub', function () {
303
295
  await github.createOrUpdateIssue(ISSUE_TO_CREATE);
304
296
  });
305
297
 
298
+ afterEach(() => {
299
+ github.issuesCache.delete(ISSUE_TO_CREATE.title);
300
+ });
301
+
306
302
  it('creates the issue', () => {
307
303
  expect(createIssueScope.isDone()).to.be.true;
308
304
  });
309
305
  });
310
306
 
311
307
  context('when the issue already exists', () => {
312
- const ISSUE = {
313
- title: 'Existing Issue',
314
- description: 'New comment',
315
- label: 'location',
316
- };
317
-
318
308
  context('when issue is closed', () => {
319
309
  let updateIssueScope;
320
310
  let addCommentScope;
321
311
 
322
- const GITHUB_RESPONSE_FOR_EXISTING_ISSUE = {
323
- number: 123,
324
- title: ISSUE.title,
325
- description: ISSUE.description,
326
- labels: [{ name: 'selectors' }],
327
- state: GitHub.ISSUE_STATE_CLOSED,
328
- };
329
-
330
312
  before(async () => {
331
- nock('https://api.github.com')
332
- .get('/repos/owner/repo/issues')
333
- .query(true)
334
- .reply(200, [GITHUB_RESPONSE_FOR_EXISTING_ISSUE]);
335
-
336
313
  updateIssueScope = nock('https://api.github.com')
337
- .patch(`/repos/owner/repo/issues/${GITHUB_RESPONSE_FOR_EXISTING_ISSUE.number}`, { state: GitHub.ISSUE_STATE_OPEN, labels: ['location'] })
314
+ .patch(`/repos/owner/repo/issues/${EXISTING_CLOSED_ISSUE.number}`, { state: GitHub.ISSUE_STATE_OPEN, labels: ['location'] })
338
315
  .reply(200);
339
316
 
340
317
  addCommentScope = nock('https://api.github.com')
341
- .post(`/repos/owner/repo/issues/${GITHUB_RESPONSE_FOR_EXISTING_ISSUE.number}/comments`, { body: ISSUE.description })
318
+ .post(`/repos/owner/repo/issues/${EXISTING_CLOSED_ISSUE.number}/comments`, { body: EXISTING_CLOSED_ISSUE.description })
342
319
  .reply(200);
343
320
 
344
- await github.createOrUpdateIssue(ISSUE);
321
+ await github.createOrUpdateIssue({ title: EXISTING_CLOSED_ISSUE.title, description: EXISTING_CLOSED_ISSUE.description, label: 'location' });
322
+ });
323
+
324
+ after(() => {
325
+ github.issuesCache.delete(EXISTING_CLOSED_ISSUE.title);
326
+ github.issuesCache.set(EXISTING_CLOSED_ISSUE.title, EXISTING_CLOSED_ISSUE);
345
327
  });
346
328
 
347
- it('reopens the issue and its labels', () => {
329
+ it('reopens the issue and updates its labels', () => {
348
330
  expect(updateIssueScope.isDone()).to.be.true;
349
331
  });
350
332
 
@@ -354,40 +336,63 @@ describe('GitHub', function () {
354
336
  });
355
337
 
356
338
  context('when issue is already opened', () => {
357
- let addCommentScope;
358
- let updateIssueScope;
359
-
360
- const GITHUB_RESPONSE_FOR_EXISTING_ISSUE = {
361
- number: 123,
362
- title: ISSUE.title,
363
- description: ISSUE.description,
364
- labels: [{ name: 'selectors' }],
365
- state: GitHub.ISSUE_STATE_OPEN,
366
- };
367
-
368
- before(async () => {
369
- nock('https://api.github.com')
370
- .get('/repos/owner/repo/issues')
371
- .query(true)
372
- .reply(200, [GITHUB_RESPONSE_FOR_EXISTING_ISSUE]);
373
-
374
- updateIssueScope = nock('https://api.github.com')
375
- .patch(`/repos/owner/repo/issues/${GITHUB_RESPONSE_FOR_EXISTING_ISSUE.number}`, { state: GitHub.ISSUE_STATE_OPEN, labels: ['location'] })
376
- .reply(200);
377
-
378
- addCommentScope = nock('https://api.github.com')
379
- .post(`/repos/owner/repo/issues/${GITHUB_RESPONSE_FOR_EXISTING_ISSUE.number}/comments`, { body: ISSUE.description })
380
- .reply(200);
381
-
382
- await github.createOrUpdateIssue(ISSUE);
383
- });
384
-
385
- it("updates the issue's labels", () => {
386
- expect(updateIssueScope.isDone()).to.be.true;
339
+ context('when the reason is new', () => {
340
+ let addCommentScope;
341
+ let updateIssueScope;
342
+
343
+ before(async () => {
344
+ updateIssueScope = nock('https://api.github.com')
345
+ .patch(`/repos/owner/repo/issues/${EXISTING_OPEN_ISSUE.number}`, { state: GitHub.ISSUE_STATE_OPEN, labels: ['404'] })
346
+ .reply(200);
347
+
348
+ addCommentScope = nock('https://api.github.com')
349
+ .post(`/repos/owner/repo/issues/${EXISTING_OPEN_ISSUE.number}/comments`, { body: EXISTING_OPEN_ISSUE.description })
350
+ .reply(200);
351
+
352
+ await github.createOrUpdateIssue({ title: EXISTING_OPEN_ISSUE.title, description: EXISTING_OPEN_ISSUE.description, label: '404' });
353
+ });
354
+
355
+ after(() => {
356
+ github.issuesCache.delete(EXISTING_OPEN_ISSUE.title);
357
+ github.issuesCache.set(EXISTING_OPEN_ISSUE.title, EXISTING_OPEN_ISSUE);
358
+ });
359
+
360
+ it("updates the issue's labels", () => {
361
+ expect(updateIssueScope.isDone()).to.be.true;
362
+ });
363
+
364
+ it('adds a comment to the issue', () => {
365
+ expect(addCommentScope.isDone()).to.be.true;
366
+ });
387
367
  });
388
-
389
- it('adds comment to the issue', () => {
390
- expect(addCommentScope.isDone()).to.be.true;
368
+ context('when the reason did not change', () => {
369
+ let addCommentScope;
370
+ let updateIssueScope;
371
+
372
+ before(async () => {
373
+ updateIssueScope = nock('https://api.github.com')
374
+ .patch(`/repos/owner/repo/issues/${EXISTING_OPEN_ISSUE.number}`, { state: GitHub.ISSUE_STATE_OPEN, labels: EXISTING_OPEN_ISSUE.labels })
375
+ .reply(200);
376
+
377
+ addCommentScope = nock('https://api.github.com')
378
+ .post(`/repos/owner/repo/issues/${EXISTING_OPEN_ISSUE.number}/comments`, { body: EXISTING_OPEN_ISSUE.description })
379
+ .reply(200);
380
+
381
+ await github.createOrUpdateIssue({ title: EXISTING_OPEN_ISSUE.title, description: EXISTING_OPEN_ISSUE.description, label: EXISTING_OPEN_ISSUE.labels[0].name });
382
+ });
383
+
384
+ after(() => {
385
+ github.issuesCache.delete(EXISTING_OPEN_ISSUE.title);
386
+ github.issuesCache.set(EXISTING_OPEN_ISSUE.title, EXISTING_OPEN_ISSUE);
387
+ });
388
+
389
+ it('does not attempt to updates the issue’s labels', () => {
390
+ expect(updateIssueScope.isDone()).to.be.false;
391
+ });
392
+
393
+ it('does not attempt to add any comment to the issue', () => {
394
+ expect(addCommentScope.isDone()).to.be.false;
395
+ });
391
396
  });
392
397
  });
393
398
  });
@@ -49,6 +49,10 @@ export default class Reporter {
49
49
  return this.github.initialize();
50
50
  }
51
51
 
52
+ onTrackingStarted() {
53
+ return this.github.clearCache();
54
+ }
55
+
52
56
  async onVersionRecorded(version) {
53
57
  await this.github.closeIssueWithCommentIfExists({
54
58
  title: Reporter.generateTitleID(version.serviceId, version.termsType),