Skip to content

Commit dd6ded1

Browse files
committed
fix: handle missing repo on archive plugin
1 parent a8a27e7 commit dd6ded1

File tree

5 files changed

+291
-172
lines changed

5 files changed

+291
-172
lines changed

index.js

+26
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,32 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) =>
639639
return syncSettings(false, context)
640640
})
641641

642+
robot.on('repository.archived', async context => {
643+
const { payload } = context
644+
const { sender } = payload
645+
646+
if (sender.type === 'Bot') {
647+
robot.log.debug('Repository Archived by a Bot')
648+
return
649+
}
650+
robot.log.debug('Repository Archived by a Human')
651+
652+
return syncSettings(false, context)
653+
})
654+
655+
robot.on('repository.unarchived', async context => {
656+
const { payload } = context
657+
const { sender } = payload
658+
659+
if (sender.type === 'Bot') {
660+
robot.log.debug('Repository Unarchived by a Bot')
661+
return
662+
}
663+
robot.log.debug('Repository Unarchived by a Human')
664+
665+
return syncSettings(false, context)
666+
})
667+
642668
if (process.env.CRON) {
643669
/*
644670
# ┌────────────── second (optional)

lib/plugins/archive.js

+99-77
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,108 @@
1-
const NopCommand = require('../nopcommand');
2-
3-
function returnValue(shouldContinue, nop) {
4-
return { shouldContinue, nopCommands: nop };
5-
}
1+
const NopCommand = require('../nopcommand')
62

73
module.exports = class Archive {
8-
constructor(nop, github, repo, settings, log) {
9-
this.github = github;
10-
this.repo = repo;
11-
this.settings = settings;
12-
this.log = log;
13-
this.nop = nop;
4+
constructor (nop, github, repo, settings, log) {
5+
this.github = github
6+
this.repo = repo
7+
this.settings = settings
8+
this.log = log
9+
this.nop = nop
1410
}
1511

16-
// Returns true if plugin application should continue, false otherwise
17-
async sync() {
18-
// Fetch repository details using REST API
19-
const { data: repoDetails } = await this.github.repos.get({
12+
async getRepo () {
13+
try {
14+
const { data } = await this.github.repos.get({
2015
owner: this.repo.owner,
2116
repo: this.repo.repo
22-
});
23-
if (typeof this.settings?.archived !== 'undefined') {
24-
this.log.debug(`Checking if ${this.repo.owner}/${this.repo.repo} is archived`);
25-
26-
this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is ${repoDetails.archived ? 'archived' : 'not archived'}`);
27-
28-
if (repoDetails.archived) {
29-
if (this.settings.archived) {
30-
this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} already archived, inform other plugins should not run.`);
31-
return returnValue(false);
32-
}
33-
else {
34-
this.log.debug(`Unarchiving ${this.repo.owner}/${this.repo.repo}`);
35-
if (this.nop) {
36-
return returnValue(true, [new NopCommand(this.constructor.name, this.repo, this.github.repos.update.endpoint(this.settings), 'will unarchive')]);
37-
}
38-
else {
39-
// Unarchive the repository using REST API
40-
const updateResponse = await this.github.repos.update({
41-
owner: this.repo.owner,
42-
repo: this.repo.repo,
43-
archived: false
44-
});
45-
this.log.debug(`Unarchive result ${JSON.stringify(updateResponse)}`);
46-
47-
return returnValue(true);
48-
}
49-
}
50-
}
51-
else {
52-
if (this.settings.archived) {
53-
this.log.debug(`Archiving ${this.repo.owner}/${this.repo.repo}`);
54-
if (this.nop) {
55-
return returnValue(false, [new NopCommand(this.constructor.name, this.repo, this.github.repos.update.endpoint(this.settings), 'will archive')]);
56-
}
57-
else {
58-
// Archive the repository using REST API
59-
const updateResponse = await this.github.repos.update({
60-
owner: this.repo.owner,
61-
repo: this.repo.repo,
62-
archived: true
63-
});
64-
this.log.debug(`Archive result ${JSON.stringify(updateResponse)}`);
65-
66-
return returnValue(false);
67-
}
68-
}
69-
else {
70-
this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is not archived, ignoring.`);
71-
return returnValue(true);
72-
}
17+
})
18+
return data
19+
} catch (error) {
20+
if (error.status === 404 && !this.getDesiredArchiveState()) {
21+
return null
7322
}
74-
}
75-
else {
76-
if (repoDetails.archived) {
77-
this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is archived, ignoring.`);
78-
return returnValue(false);
79-
}
80-
else {
81-
this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is not archived, proceed as usual.`);
82-
return returnValue(true);
83-
}
23+
throw error
8424
}
8525
}
86-
};
26+
27+
async updateRepoArchiveStatus (archived) {
28+
const action = archived ? 'archive' : 'unarchive'
29+
30+
if (this.nop) {
31+
const change = { msg: 'Change found', additions: {}, modifications: { archived: action }, deletions: {} }
32+
return new NopCommand(
33+
this.constructor.name,
34+
this.repo,
35+
this.github.repos.update.endpoint(this.settings),
36+
change,
37+
'INFO'
38+
)
39+
}
40+
41+
const { data } = await this.github.repos.update({
42+
owner: this.repo.owner,
43+
repo: this.repo.repo,
44+
archived
45+
})
46+
47+
this.log.debug({ result: data }, `Repo ${this.repo.owner}/${this.repo.repo} ${action}d`)
48+
}
49+
50+
getDesiredArchiveState () {
51+
if (typeof this.settings?.archived === 'undefined') {
52+
return null
53+
}
54+
return typeof this.settings.archived === 'boolean'
55+
? this.settings.archived
56+
: this.settings.archived === 'true'
57+
}
58+
59+
shouldArchive (repository = this.repository) {
60+
const desiredState = this.getDesiredArchiveState()
61+
if (desiredState === null) return false
62+
return !repository.archived && desiredState
63+
}
64+
65+
shouldUnarchive (repository = this.repository) {
66+
const desiredState = this.getDesiredArchiveState()
67+
if (desiredState === null) return false
68+
return repository.archived && !desiredState
69+
}
70+
71+
isArchived () {
72+
return this.repository?.archived
73+
}
74+
75+
async getState () {
76+
this.repository = await this.getRepo()
77+
78+
return {
79+
isArchived: this.isArchived(),
80+
shouldArchive: this.shouldArchive(),
81+
shouldUnarchive: this.shouldUnarchive()
82+
}
83+
}
84+
85+
async sync () {
86+
this.repository = await this.getRepo()
87+
88+
const results = []
89+
90+
if (!this.repository) {
91+
this.log.warn(`Repo ${this.repo.owner}/${this.repo.repo} not found, skipping archive sync`)
92+
return results
93+
}
94+
95+
const shouldArchive = this.shouldArchive()
96+
const shouldUnarchive = this.shouldUnarchive()
97+
98+
if (!shouldArchive && !shouldUnarchive) {
99+
this.log.debug(`No archive changes needed for ${this.repo.owner}/${this.repo.repo}`)
100+
return results
101+
}
102+
103+
const archived = shouldArchive
104+
results.push(await this.updateRepoArchiveStatus(archived))
105+
106+
return results
107+
}
108+
}

lib/plugins/repository.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ const ignorableFields = [
3636
'org',
3737
'force_create',
3838
'auto_init',
39-
'repo'
39+
'repo',
40+
'archived'
4041
]
4142

4243
module.exports = class Repository extends ErrorStash {

lib/settings.js

+47-34
Original file line numberDiff line numberDiff line change
@@ -321,48 +321,61 @@ ${this.results.reduce((x, y) => {
321321
}
322322
}
323323

324-
// Overlay repo config
324+
// Overlay repo config
325325
// RepoConfigs should be preloaded but checking anyway
326326
const overrideRepoConfig = this.repoConfigs[`${repo.repo}.yml`]?.repository
327327
if (overrideRepoConfig) {
328328
repoConfig = this.mergeDeep.mergeDeep({}, repoConfig, overrideRepoConfig)
329329
}
330-
const {shouldContinue, nopCommands} = await new Archive(this.nop, this.github, repo, repoConfig, this.log).sync()
331-
if (nopCommands) this.appendToResults(nopCommands)
332-
if (shouldContinue) {
333-
if (repoConfig) {
334-
try {
335-
this.log.debug(`found a matching repoconfig for this repo ${JSON.stringify(repoConfig)}`)
336-
const childPlugins = this.childPluginsList(repo)
337-
const RepoPlugin = Settings.PLUGINS.repository
338-
return new RepoPlugin(this.nop, this.github, repo, repoConfig, this.installation_id, this.log, this.errors).sync().then(res => {
339-
this.appendToResults(res)
340-
return Promise.all(
341-
childPlugins.map(([Plugin, config]) => {
342-
return new Plugin(this.nop, this.github, repo, config, this.log, this.errors).sync()
343-
}))
344-
}).then(res => {
345-
this.appendToResults(res)
346-
})
347-
} catch (e) {
348-
if (this.nop) {
349-
const nopcommand = new NopCommand(this.constructor.name, this.repo, null, `${e}`, 'ERROR')
350-
this.log.error(`NOPCOMMAND ${JSON.stringify(nopcommand)}`)
351-
this.appendToResults([nopcommand])
352-
// throw e
353-
} else {
354-
throw e
355-
}
356-
}
357-
} else {
358-
this.log.debug(`Didnt find any a matching repoconfig for this repo ${JSON.stringify(repo)} in ${JSON.stringify(this.repoConfigs)}`)
330+
if (repoConfig) {
331+
try {
332+
this.log.debug(`found a matching repoconfig for this repo ${JSON.stringify(repoConfig)}`)
333+
359334
const childPlugins = this.childPluginsList(repo)
360-
return Promise.all(childPlugins.map(([Plugin, config]) => {
361-
return new Plugin(this.nop, this.github, repo, config, this.log, this.errors).sync().then(res => {
362-
this.appendToResults(res)
335+
const RepoPlugin = Settings.PLUGINS.repository
336+
337+
const archivePlugin = new Archive(this.nop, this.github, repo, repoConfig, this.log)
338+
const { shouldArchive, shouldUnarchive } = await archivePlugin.getState()
339+
340+
if (shouldUnarchive) {
341+
this.log.debug(`Unarchiving repo ${repo.repo}`)
342+
const unArchiveResults = await archivePlugin.sync()
343+
this.appendToResults(unArchiveResults)
344+
}
345+
346+
const repoResults = await new RepoPlugin(this.nop, this.github, repo, repoConfig, this.installation_id, this.log, this.errors).sync()
347+
this.appendToResults(repoResults)
348+
349+
const childResults = await Promise.all(
350+
childPlugins.map(([Plugin, config]) => {
351+
return new Plugin(this.nop, this.github, repo, config, this.log, this.errors).sync()
363352
})
364-
}))
353+
)
354+
this.appendToResults(childResults)
355+
356+
if (shouldArchive) {
357+
this.log.debug(`Archiving repo ${repo.repo}`)
358+
const archiveResults = await archivePlugin.sync()
359+
this.appendToResults(archiveResults)
360+
}
361+
} catch (e) {
362+
if (this.nop) {
363+
const nopcommand = new NopCommand(this.constructor.name, this.repo, null, `${e}`, 'ERROR')
364+
this.log.error(`NOPCOMMAND ${JSON.stringify(nopcommand)}`)
365+
this.appendToResults([nopcommand])
366+
// throw e
367+
} else {
368+
throw e
369+
}
365370
}
371+
} else {
372+
this.log.debug(`Didnt find any a matching repoconfig for this repo ${JSON.stringify(repo)} in ${JSON.stringify(this.repoConfigs)}`)
373+
const childPlugins = this.childPluginsList(repo)
374+
return Promise.all(childPlugins.map(([Plugin, config]) => {
375+
return new Plugin(this.nop, this.github, repo, config, this.log, this.errors).sync().then(res => {
376+
this.appendToResults(res)
377+
})
378+
}))
366379
}
367380
}
368381

0 commit comments

Comments
 (0)