Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Support repo unarchiving #193

Draft
wants to merge 1 commit into
base: main-enterprise
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions lib/plugins/unarchiver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// THIS IS A SPECIAL PLUGIN, DON'T ADD IT TO THE LIST OF PLUGINS IN SETTINGS
const NopCommand = require('../nopcommand')

const UnlockRepoMutation = `
mutation($repoId: ID!) {
unarchiveRepository(input:{clientMutationId:"true",repositoryId: $repoId}) {
repository {
isArchived
}
}
}`
const GetRepoQuery = `query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo){
id,
isArchived,
}
}`

function returnValue (shouldContinue, nop) {
return { shouldContinue, nopCommands: nop }
}

/// Unarchives repos before the other plugins.
/// This is optimized for the case where safe-settings is the source of truth when it cames to the archive config bit.

/// If the archived config is not set then we don't even read the archived status for the repo (it saves one call)
/// This has the implication that if a repo is archived outside safe settings, other plugins may attempt to change the data and fail (it's their responsability to check if the repo is archived)
/// However if the archive config is set, we will return false to indicate other plugins shouldn't be executed if the repo is archived (and archive config is true)
module.exports = class Unarchiver {
constructor (nop, github, repo, settings, log) {
this.github = github
this.repo = repo
this.settings = settings
this.log = log
this.nop = nop
}

// Returns true if should proceed false otherwise
async sync () {
if (typeof (this.settings?.archived) !== 'undefined') {
this.log.debug(`Checking if ${this.repo.owner}/${this.repo.repo} is archived`)
const graphQLResponse = await this.github.graphql(GetRepoQuery, { owner: this.repo.owner, repo: this.repo.repo })
this.log(`Repo ${this.repo.owner}/${this.repo.repo} is ${graphQLResponse.repository.isArchived ? 'archived' : 'not archived'}`)

if (graphQLResponse.repository.isArchived) {
if (this.settings.archived) {
this.log(`Repo ${this.repo.owner}/${this.repo.repo} already archived, inform other plugins should not run.`)
return returnValue(false)
} else {
this.log(`Unarchiving ${this.repo.owner}/${this.repo.repo} ${graphQLResponse.repository.id}`)
if (this.nop) {
return returnValue(true, [new NopCommand('Unarchiver', this.repo, null, 'will unarchive')])
} else {
const graphQLUnlockResponse = await this.github.graphql(UnlockRepoMutation, { repoId: graphQLResponse.repository.id })
this.log.debug(`Unarchived result ${JSON.stringify(graphQLUnlockResponse)}`)

return returnValue(true)
}
}
}
this.log(`Repo ${this.repo.owner}/${this.repo.repo} not archived, ignoring.`)
} else {
this.log(`Repo ${this.repo.owner}/${this.repo.repo} archived config not set, ignoring.`)
}
return returnValue(true)
}
}
69 changes: 40 additions & 29 deletions lib/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const fs = require('fs')
const Glob = require('./glob')
const NopCommand = require('./nopcommand')
const { throws } = require('assert')
const Unarchiver = require('./plugins/unarchiver')
class Settings {

static async syncAll(nop, context, repo, config, ref) {
Expand Down Expand Up @@ -152,39 +153,49 @@ ${this.results.reduce((x,y) => {
if (overrideRepoConfig) {
repoConfig = this.mergeDeep({}, repoConfig, overrideRepoConfig)
}
if (repoConfig) {
try {
this.log.debug(`found a matching repoconfig for this repo ${JSON.stringify(repoConfig)}`)

// Although this is a plugin, it must be handled differently since it cannot run in parallel with the other plugins
// Because if the repo is archived we need to unarchived before all other plugins.
// If the repo is archived but there is no config to unarchive we don't run any plugins since they would fail anyway (and uncessary calls as well)
const {shouldContinue, nopCommands} = await new Unarchiver(this.nop, this.github, repo, repoConfig ?? config, this.log).sync()

if (nopCommands) this.appendToResults(nopCommands)

if(shouldContinue) {
if (repoConfig) {
try {
this.log.debug(`found a matching repoconfig for this repo ${JSON.stringify(repoConfig)}`)
const childPlugins = this.childPluginsList(repo.repo)
const RepoPlugin = Settings.PLUGINS.repository
return new RepoPlugin(this.nop, this.github, repo, repoConfig, this.installation_id, this.log).sync().then( res => {
this.appendToResults(res)
return Promise.all(
childPlugins.map(([Plugin, config]) => {
return new Plugin(this.nop, this.github, repo, config, this.log).sync()
}))
}).then( res => {
this.appendToResults(res)
})
} catch(e) {
if (this.nop) {
const nopcommand = new NopCommand(this.constructor.name, this.repo, null,e, "ERROR")
console.error(`NOPCOMMAND ${JSON.stringify(nopcommand)}`)
this.appendToResults([nopcommand])
//throw e
} else {
throw e
}
}

} else {
this.log.debug(`Didnt find any a matching repoconfig for this repo ${JSON.stringify(repo)} in ${JSON.stringify(this.repoConfigs)}`)
const childPlugins = this.childPluginsList(repo.repo)
const RepoPlugin = Settings.PLUGINS.repository
return new RepoPlugin(this.nop, this.github, repo, repoConfig, this.installation_id, this.log).sync().then( res => {
this.appendToResults(res)
return Promise.all(
childPlugins.map(([Plugin, config]) => {
return new Plugin(this.nop, this.github, repo, config, this.log).sync()
}))
}).then( res => {
return Promise.all(childPlugins.map(([Plugin, config]) => {
return new Plugin(this.nop, this.github, repo, config, this.log).sync().then( res => {
this.appendToResults(res)
})
} catch(e) {
if (this.nop) {
const nopcommand = new NopCommand(this.constructor.name, this.repo, null,e, "ERROR")
console.error(`NOPCOMMAND ${JSON.stringify(nopcommand)}`)
this.appendToResults([nopcommand])
//throw e
} else {
throw e
}
}))
}

} else {
this.log.debug(`Didnt find any a matching repoconfig for this repo ${JSON.stringify(repo)} in ${JSON.stringify(this.repoConfigs)}`)
const childPlugins = this.childPluginsList(repo.repo)
return Promise.all(childPlugins.map(([Plugin, config]) => {
return new Plugin(this.nop, this.github, repo, config, this.log).sync().then( res => {
this.appendToResults(res)
})
}))
}
}

Expand Down