diff --git a/README.md b/README.md index 705c82ca..c84c51b9 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ Using the settings, the following things could be configured: - `Collaborators and permissions` - `Issue labels` - `Branch protections`. If the name of the branch is `default` in the settings, it is applied to the `default` branch of the repo. +- `Autolinks` - `repository name validation` using regex pattern It is possible to provide an `include` or `exclude` settings to restrict the `collaborators`, `teams`, `labels` to a list of repos or exclude a set of repos for a collaborator. @@ -298,6 +299,13 @@ branches: apps: [] users: [] teams: [] + +# See the docs (https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/configuring-autolinks-to-reference-external-resources) for a description of autolinks and replacement values. +autolinks: + - key_prefix: 'JIRA-' + url_template: 'https://jira.github.com/browse/JIRA-' + - key_prefix: 'MYLINK-' + url_template: 'https://mywebsite.com/' validator: #pattern: '[a-zA-Z0-9_-]+_[a-zA-Z0-9_-]+.*' diff --git a/lib/plugins/autolinks.js b/lib/plugins/autolinks.js new file mode 100644 index 00000000..7cc1b396 --- /dev/null +++ b/lib/plugins/autolinks.js @@ -0,0 +1,69 @@ +const Diffable = require('./diffable'); +const NopCommand = require('../nopcommand'); + +module.exports = class Autolinks extends Diffable { + constructor(...args) { + super(...args); + } + + async find() { + const { data } = await this.github.repos.listAutolinks(this.repo); + return data; + } + + comparator(existing, attr) { + return existing.key_prefix === attr.key_prefix && existing.url_template === attr.url_template; + } + + changed(existing, attr) { + return existing.key_prefix === attr.key_prefix && existing.url_template !== attr.url_template; + } + + async update(existing, attr) { + await this.remove(existing); + return this.add(attr); + } + + async add({ key_prefix, url_template }) { + const attrs = { + ...this.repo, + key_prefix, + url_template, + }; + + if (this.nop) { + return new NopCommand( + this.constructor.name, + this.repo, + this.github.repos.createAutolink.endpoint(attrs), + 'Add autolink', + ); + } + + try { + return this.github.repos.createAutolink(attrs); + } catch (e) { + if (e?.response?.data?.errors?.[0]?.code === 'already_exists') { + this.log.debug(`Did not update ${key_prefix}, as it already exists`); + return; + } + throw e; + } + } + + async remove({ id }) { + const attrs = { + ...this.repo, + autolink_id: id, + }; + if (this.nop) { + return new NopCommand( + this.constructor.name, + this.repo, + this.github.repos.deleteAutolink.endpoint(attrs), + 'Remove autolink', + ); + } + return this.github.repos.deleteAutolink(attrs); + } +}; diff --git a/lib/plugins/diffable.js b/lib/plugins/diffable.js index 9426f191..4deb0036 100644 --- a/lib/plugins/diffable.js +++ b/lib/plugins/diffable.js @@ -81,6 +81,12 @@ module.exports = class Diffable { return this.find().then(existingRecords => { const changes = [] + existingRecords.forEach(x => { + if (!filteredEntries.find(y => this.comparator(x, y))) { + changes.push(this.remove(x)) + } + }) + filteredEntries.forEach(attrs => { const existing = existingRecords.find(record => { return this.comparator(record, attrs) @@ -93,11 +99,6 @@ module.exports = class Diffable { } }) - existingRecords.forEach(x => { - if (!filteredEntries.find(y => this.comparator(x, y))) { - changes.push(this.remove(x)) - } - }) if (changes.length === 0) { if (this.nop) { return Promise.resolve([ diff --git a/lib/settings.js b/lib/settings.js index 689e0df0..3b73d0c9 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -637,6 +637,7 @@ Settings.PLUGINS = { teams: require('./plugins/teams'), milestones: require('./plugins/milestones'), branches: require('./plugins/branches'), + autolinks: require('./plugins/autolinks'), validator: require('./plugins/validator') }