diff --git a/README.md b/README.md index e7142e3..bb7940c 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,26 @@ jobs: base: main ``` +### Exclude pull requests with specific labels + +```yml + - uses: peter-evans/rebase@v1 + with: + exclude-labels: | + no-rebase + dependencies +``` + +### Action inputs + +| Name | Description | Default | +| --- | --- | --- | +| `token` | `GITHUB_TOKEN` or a `repo` scoped [PAT](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). The `workflow` scope may also be required if rebasing pull requests containing changes to workflows under `.github/workflows`. | `GITHUB_TOKEN` | +| `repository` | The target GitHub repository containing the pull request. | `github.repository` (Current repository) | +| `head` | Filter pull requests by head user or head organization and branch name in the format `user:ref-name` or `organization:ref-name`. For example: `github:new-script-format` or `octocat:test-branch`. | | +| `base` | Filter pull requests by base branch name. Example: `gh-pages`. | | +| `exclude-labels` | A comma or newline separated list of pull request labels to exclude. | | + ### Rebase slash command Use the following two workflows and a `repo` scoped [PAT](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) to add a `/rebase` slash command to pull request comments. @@ -91,15 +111,6 @@ jobs: reaction-type: hooray ``` -### Action inputs - -| Name | Description | Default | -| --- | --- | --- | -| `token` | `GITHUB_TOKEN` or a `repo` scoped [PAT](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). The `workflow` scope may also be required if rebasing pull requests containing changes to workflows under `.github/workflows`. | `GITHUB_TOKEN` | -| `repository` | The target GitHub repository containing the pull request. | `github.repository` (Current repository) | -| `head` | Filter pull requests by head user or head organization and branch name in the format `user:ref-name` or `organization:ref-name`. For example: `github:new-script-format` or `octocat:test-branch`. | | -| `base` | Filter pull requests by base branch name. Example: `gh-pages`. | | - ### Target other repositories You can rebase requests in another repository by using a `repo` scoped [PAT](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) instead of `GITHUB_TOKEN`. diff --git a/action.yml b/action.yml index 8ea5503..e29179d 100644 --- a/action.yml +++ b/action.yml @@ -15,6 +15,8 @@ inputs: description: > Filter pull requests by base branch name. Example: gh-pages. + exclude-labels: + description: 'A comma or newline separated list of pull request labels to exclude' runs: using: 'node12' main: 'dist/index.js' diff --git a/dist/index.js b/dist/index.js index 8fd86a1..818a26f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -5,7 +5,7 @@ /***/ ((module) => { "use strict"; -module.exports = JSON.parse('{"name":"@octokit/rest","version":"16.43.2","publishConfig":{"access":"public"},"description":"GitHub REST API client for Node.js","keywords":["octokit","github","rest","api-client"],"author":"Gregor Martynus (https://github.com/gr2m)","contributors":[{"name":"Mike de Boer","email":"info@mikedeboer.nl"},{"name":"Fabian Jakobs","email":"fabian@c9.io"},{"name":"Joe Gallo","email":"joe@brassafrax.com"},{"name":"Gregor Martynus","url":"https://github.com/gr2m"}],"repository":"https://github.com/octokit/rest.js","dependencies":{"@octokit/auth-token":"^2.4.0","@octokit/plugin-paginate-rest":"^1.1.1","@octokit/plugin-request-log":"^1.0.0","@octokit/plugin-rest-endpoint-methods":"2.4.0","@octokit/request":"^5.2.0","@octokit/request-error":"^1.0.2","atob-lite":"^2.0.0","before-after-hook":"^2.0.0","btoa-lite":"^1.0.0","deprecation":"^2.0.0","lodash.get":"^4.4.2","lodash.set":"^4.3.2","lodash.uniq":"^4.5.0","octokit-pagination-methods":"^1.1.0","once":"^1.4.0","universal-user-agent":"^4.0.0"},"devDependencies":{"@gimenete/type-writer":"^0.1.3","@octokit/auth":"^1.1.1","@octokit/fixtures-server":"^5.0.6","@octokit/graphql":"^4.2.0","@types/node":"^13.1.0","bundlesize":"^0.18.0","chai":"^4.1.2","compression-webpack-plugin":"^3.1.0","cypress":"^4.0.0","glob":"^7.1.2","http-proxy-agent":"^4.0.0","lodash.camelcase":"^4.3.0","lodash.merge":"^4.6.1","lodash.upperfirst":"^4.3.1","lolex":"^6.0.0","mkdirp":"^1.0.0","mocha":"^7.0.1","mustache":"^4.0.0","nock":"^11.3.3","npm-run-all":"^4.1.2","nyc":"^15.0.0","prettier":"^1.14.2","proxy":"^1.0.0","semantic-release":"^17.0.0","sinon":"^8.0.0","sinon-chai":"^3.0.0","sort-keys":"^4.0.0","string-to-arraybuffer":"^1.0.0","string-to-jsdoc-comment":"^1.0.0","typescript":"^3.3.1","webpack":"^4.0.0","webpack-bundle-analyzer":"^3.0.0","webpack-cli":"^3.0.0"},"types":"index.d.ts","scripts":{"coverage":"nyc report --reporter=html && open coverage/index.html","lint":"prettier --check \'{lib,plugins,scripts,test}/**/*.{js,json,ts}\' \'docs/*.{js,json}\' \'docs/src/**/*\' index.js README.md package.json","lint:fix":"prettier --write \'{lib,plugins,scripts,test}/**/*.{js,json,ts}\' \'docs/*.{js,json}\' \'docs/src/**/*\' index.js README.md package.json","pretest":"npm run -s lint","test":"nyc mocha test/mocha-node-setup.js \\"test/*/**/*-test.js\\"","test:browser":"cypress run --browser chrome","build":"npm-run-all build:*","build:ts":"npm run -s update-endpoints:typescript","prebuild:browser":"mkdirp dist/","build:browser":"npm-run-all build:browser:*","build:browser:development":"webpack --mode development --entry . --output-library=Octokit --output=./dist/octokit-rest.js --profile --json > dist/bundle-stats.json","build:browser:production":"webpack --mode production --entry . --plugin=compression-webpack-plugin --output-library=Octokit --output-path=./dist --output-filename=octokit-rest.min.js --devtool source-map","generate-bundle-report":"webpack-bundle-analyzer dist/bundle-stats.json --mode=static --no-open --report dist/bundle-report.html","update-endpoints":"npm-run-all update-endpoints:*","update-endpoints:fetch-json":"node scripts/update-endpoints/fetch-json","update-endpoints:typescript":"node scripts/update-endpoints/typescript","prevalidate:ts":"npm run -s build:ts","validate:ts":"tsc --target es6 --noImplicitAny index.d.ts","postvalidate:ts":"tsc --noEmit --target es6 test/typescript-validate.ts","start-fixtures-server":"octokit-fixtures-server"},"license":"MIT","files":["index.js","index.d.ts","lib","plugins"],"nyc":{"ignore":["test"]},"release":{"publish":["@semantic-release/npm",{"path":"@semantic-release/github","assets":["dist/*","!dist/*.map.gz"]}]},"bundlesize":[{"path":"./dist/octokit-rest.min.js.gz","maxSize":"33 kB"}],"_resolved":"https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz","_integrity":"sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==","_from":"@octokit/rest@16.43.2"}'); +module.exports = JSON.parse('{"name":"@octokit/rest","version":"16.43.2","publishConfig":{"access":"public"},"description":"GitHub REST API client for Node.js","keywords":["octokit","github","rest","api-client"],"author":"Gregor Martynus (https://github.com/gr2m)","contributors":[{"name":"Mike de Boer","email":"info@mikedeboer.nl"},{"name":"Fabian Jakobs","email":"fabian@c9.io"},{"name":"Joe Gallo","email":"joe@brassafrax.com"},{"name":"Gregor Martynus","url":"https://github.com/gr2m"}],"repository":"https://github.com/octokit/rest.js","dependencies":{"@octokit/auth-token":"^2.4.0","@octokit/plugin-paginate-rest":"^1.1.1","@octokit/plugin-request-log":"^1.0.0","@octokit/plugin-rest-endpoint-methods":"2.4.0","@octokit/request":"^5.2.0","@octokit/request-error":"^1.0.2","atob-lite":"^2.0.0","before-after-hook":"^2.0.0","btoa-lite":"^1.0.0","deprecation":"^2.0.0","lodash.get":"^4.4.2","lodash.set":"^4.3.2","lodash.uniq":"^4.5.0","octokit-pagination-methods":"^1.1.0","once":"^1.4.0","universal-user-agent":"^4.0.0"},"devDependencies":{"@gimenete/type-writer":"^0.1.3","@octokit/auth":"^1.1.1","@octokit/fixtures-server":"^5.0.6","@octokit/graphql":"^4.2.0","@types/node":"^13.1.0","bundlesize":"^0.18.0","chai":"^4.1.2","compression-webpack-plugin":"^3.1.0","cypress":"^4.0.0","glob":"^7.1.2","http-proxy-agent":"^4.0.0","lodash.camelcase":"^4.3.0","lodash.merge":"^4.6.1","lodash.upperfirst":"^4.3.1","lolex":"^6.0.0","mkdirp":"^1.0.0","mocha":"^7.0.1","mustache":"^4.0.0","nock":"^11.3.3","npm-run-all":"^4.1.2","nyc":"^15.0.0","prettier":"^1.14.2","proxy":"^1.0.0","semantic-release":"^17.0.0","sinon":"^8.0.0","sinon-chai":"^3.0.0","sort-keys":"^4.0.0","string-to-arraybuffer":"^1.0.0","string-to-jsdoc-comment":"^1.0.0","typescript":"^3.3.1","webpack":"^4.0.0","webpack-bundle-analyzer":"^3.0.0","webpack-cli":"^3.0.0"},"types":"index.d.ts","scripts":{"coverage":"nyc report --reporter=html && open coverage/index.html","lint":"prettier --check \'{lib,plugins,scripts,test}/**/*.{js,json,ts}\' \'docs/*.{js,json}\' \'docs/src/**/*\' index.js README.md package.json","lint:fix":"prettier --write \'{lib,plugins,scripts,test}/**/*.{js,json,ts}\' \'docs/*.{js,json}\' \'docs/src/**/*\' index.js README.md package.json","pretest":"npm run -s lint","test":"nyc mocha test/mocha-node-setup.js \\"test/*/**/*-test.js\\"","test:browser":"cypress run --browser chrome","build":"npm-run-all build:*","build:ts":"npm run -s update-endpoints:typescript","prebuild:browser":"mkdirp dist/","build:browser":"npm-run-all build:browser:*","build:browser:development":"webpack --mode development --entry . --output-library=Octokit --output=./dist/octokit-rest.js --profile --json > dist/bundle-stats.json","build:browser:production":"webpack --mode production --entry . --plugin=compression-webpack-plugin --output-library=Octokit --output-path=./dist --output-filename=octokit-rest.min.js --devtool source-map","generate-bundle-report":"webpack-bundle-analyzer dist/bundle-stats.json --mode=static --no-open --report dist/bundle-report.html","update-endpoints":"npm-run-all update-endpoints:*","update-endpoints:fetch-json":"node scripts/update-endpoints/fetch-json","update-endpoints:typescript":"node scripts/update-endpoints/typescript","prevalidate:ts":"npm run -s build:ts","validate:ts":"tsc --target es6 --noImplicitAny index.d.ts","postvalidate:ts":"tsc --noEmit --target es6 test/typescript-validate.ts","start-fixtures-server":"octokit-fixtures-server"},"license":"MIT","files":["index.js","index.d.ts","lib","plugins"],"nyc":{"ignore":["test"]},"release":{"publish":["@semantic-release/npm",{"path":"@semantic-release/github","assets":["dist/*","!dist/*.map.gz"]}]},"bundlesize":[{"path":"./dist/octokit-rest.min.js.gz","maxSize":"33 kB"}]}'); /***/ }), @@ -375,6 +375,7 @@ const pulls_helper_1 = __nccwpck_require__(3633); const rebase_helper_1 = __nccwpck_require__(7965); const util_1 = __nccwpck_require__(1669); const uuid_1 = __nccwpck_require__(5840); +const utils = __importStar(__nccwpck_require__(918)); function run() { return __awaiter(this, void 0, void 0, function* () { try { @@ -382,12 +383,13 @@ function run() { token: core.getInput('token'), repository: core.getInput('repository'), head: core.getInput('head'), - base: core.getInput('base') + base: core.getInput('base'), + excludeLabels: utils.getInputAsArray('exclude-labels') }; core.debug(`Inputs: ${util_1.inspect(inputs)}`); const [headOwner, head] = inputValidator.parseHead(inputs.head); const pullsHelper = new pulls_helper_1.PullsHelper(inputs.token); - const pulls = yield pullsHelper.get(inputs.repository, head, headOwner, inputs.base); + const pulls = yield pullsHelper.get(inputs.repository, head, headOwner, inputs.base, inputs.excludeLabels); if (pulls.length > 0) { core.info(`${pulls.length} pull request(s) found.`); // Checkout @@ -474,7 +476,7 @@ class PullsHelper { } }); } - get(repository, head, headOwner, base) { + get(repository, head, headOwner, base, excludeLabels) { return __awaiter(this, void 0, void 0, function* () { const [owner, repo] = repository.split('/'); const params = { @@ -499,6 +501,11 @@ class PullsHelper { headRepositoryOwner { login } + labels(first: 100) { + nodes { + name + } + } maintainerCanModify } } @@ -517,7 +524,12 @@ class PullsHelper { p.node.headRepositoryOwner.login == headOwner) && // Filter heads from forks where 'maintainer can modify' is false (p.node.headRepositoryOwner.login == owner || - p.node.maintainerCanModify)) { + p.node.maintainerCanModify) && + // Filter out pull requests with labels in the exclude list + p.node.labels.nodes.every(function (value) { + // Label is not in the exclude list + return !excludeLabels.includes(value.name); + })) { return new Pull(p.node.baseRefName, p.node.headRepository.url, p.node.headRepository.nameWithOwner, p.node.headRefName); } }) @@ -690,7 +702,8 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.fileExistsSync = void 0; +exports.getInputAsArray = exports.fileExistsSync = void 0; +const core = __importStar(__nccwpck_require__(2186)); const fs = __importStar(__nccwpck_require__(5747)); function fileExistsSync(path) { if (!path) { @@ -712,6 +725,16 @@ function fileExistsSync(path) { return false; } exports.fileExistsSync = fileExistsSync; +function getInputAsArray(name, options) { + return getStringAsArray(core.getInput(name, options)); +} +exports.getInputAsArray = getInputAsArray; +function getStringAsArray(str) { + return str + .split(/[\n,]+/) + .map(s => s.trim()) + .filter(x => x !== ''); +} /***/ }), diff --git a/package-lock.json b/package-lock.json index b2087c4..eb7b8fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,15 +18,15 @@ "devDependencies": { "@types/jest": "26.0.23", "@types/node": "15.6.1", - "@typescript-eslint/eslint-plugin": "^4.31.2", + "@typescript-eslint/eslint-plugin": "4.31.2", "@typescript-eslint/parser": "4.25.0", "@vercel/ncc": "0.28.6", "eslint": "7.32.0", - "eslint-config-prettier": "^8.3.0", + "eslint-config-prettier": "8.3.0", "eslint-plugin-github": "4.1.3", - "eslint-plugin-import": "^2.24.2", + "eslint-plugin-import": "2.24.2", "eslint-plugin-jest": "24.3.6", - "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-prettier": "4.0.0", "jest": "27.0.1", "jest-circus": "27.0.1", "js-yaml": "4.1.0", diff --git a/src/main.ts b/src/main.ts index f17bd93..6a10d20 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,6 +8,7 @@ import {PullsHelper} from './pulls-helper' import {RebaseHelper} from './rebase-helper' import {inspect} from 'util' import {v4 as uuidv4} from 'uuid' +import * as utils from './utils' async function run(): Promise { try { @@ -15,7 +16,8 @@ async function run(): Promise { token: core.getInput('token'), repository: core.getInput('repository'), head: core.getInput('head'), - base: core.getInput('base') + base: core.getInput('base'), + excludeLabels: utils.getInputAsArray('exclude-labels') } core.debug(`Inputs: ${inspect(inputs)}`) @@ -26,7 +28,8 @@ async function run(): Promise { inputs.repository, head, headOwner, - inputs.base + inputs.base, + inputs.excludeLabels ) if (pulls.length > 0) { diff --git a/src/pulls-helper.ts b/src/pulls-helper.ts index 93b18f9..a614eea 100644 --- a/src/pulls-helper.ts +++ b/src/pulls-helper.ts @@ -19,7 +19,8 @@ export class PullsHelper { repository: string, head: string, headOwner: string, - base: string + base: string, + excludeLabels: string[] ): Promise { const [owner, repo] = repository.split('/') const params: OctokitTypes.RequestParameters = { @@ -42,6 +43,11 @@ export class PullsHelper { headRepositoryOwner { login } + labels(first: 100) { + nodes { + name + } + } maintainerCanModify } } @@ -61,7 +67,12 @@ export class PullsHelper { p.node.headRepositoryOwner.login == headOwner) && // Filter heads from forks where 'maintainer can modify' is false (p.node.headRepositoryOwner.login == owner || - p.node.maintainerCanModify) + p.node.maintainerCanModify) && + // Filter out pull requests with labels in the exclude list + p.node.labels.nodes.every(function (value: Label): boolean { + // Label is not in the exclude list + return !excludeLabels.includes(value.name) + }) ) { return new Pull( p.node.baseRefName, @@ -78,6 +89,10 @@ export class PullsHelper { } } +type Label = { + name: string +} + type Edge = { node: { baseRefName: string @@ -89,6 +104,9 @@ type Edge = { headRepositoryOwner: { login: string } + labels: { + nodes: Label[] + } maintainerCanModify: boolean } } diff --git a/src/utils.ts b/src/utils.ts index c32dabd..2509712 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,4 @@ +import * as core from '@actions/core' import * as fs from 'fs' export function fileExistsSync(path: string): boolean { @@ -8,7 +9,7 @@ export function fileExistsSync(path: string): boolean { let stats: fs.Stats try { stats = fs.statSync(path) - } catch (error) { + } catch (error: any) { if (error.code === 'ENOENT') { return false } @@ -24,3 +25,17 @@ export function fileExistsSync(path: string): boolean { return false } + +export function getInputAsArray( + name: string, + options?: core.InputOptions +): string[] { + return getStringAsArray(core.getInput(name, options)) +} + +function getStringAsArray(str: string): string[] { + return str + .split(/[\n,]+/) + .map(s => s.trim()) + .filter(x => x !== '') +}