diff --git a/README.md b/README.md index a34f8fe..b9b02df 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ This action searches for team pings in issues and pull requests in an organizati - `project-board`: 'The URL of the project board to place issues and pull requests. Must be an org project board. - `project-column`: The id of the column to add issues and pull requests.' - `ignore-team`: Ignores issues and pull requests authored or commented on by members of this team. Issues and pull requests authored or commented on by members of `team` are ignored unless you specify an alternate `ignore-team` parameter. You can use `ignore-team` to specify a larger team or a team that does not match the team ping being searched. The value you specify for `ignore-team` overrides the `team` value. -- `ignore-repos`: Repositories to ignore when searching issues and pull requests. You can add more than one repository by using a comma-separated list. Format: {owner}/{repo}. For example: octocat/hello-world +- `include-repos`: Repositories to include when searching issues and pull requests. You can add more than one repository by using a comma-separated list. Format: {owner}/{repo}. For example: 'octocat/hello-world, octocat/foobar'. Note: This cannot be used with `ignore-repos`. +- `ignore-repos`: Repositories to ignore when searching issues and pull requests. You can add more than one repository by using a comma-separated list. Format: {owner}/{repo}. For example: 'octocat/hello-world, octocat/foobar'. Note: This cannot be used with `include-repos`. - `ignore-authors`: Ignores issues and pull requests authored by these accounts. You can add more than one repository by using a comma-separated list (for example, 'actions-bot, hubot') - `ignore-commenters`: Ignores issues and pull requests commented by thee accounts. You can add more than one repository by using a comma-separated list (for example, 'actions-bot, hubot') - `comment-body`: A comment added to the issue or pull request. @@ -20,19 +21,19 @@ This action searches for team pings in issues and pull requests in an organizati To read and write organization project boards, you need to use an access token with `repo` and `write:org` access. Ensure that you add the user that owns the access token to the project board with admin permission. For help creating an access token or managing project board members see the GitHub docs: - [Creating a personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token#creating-a-token) -- [Managing team access to an organization project board](https://docs.github.com/en/github/setting-up-and-managing-organizations-and-teams/managing-team-access-to-an-organization-project-board) -- [Managing an individual's acces to an organization project board](https://docs.github.com/en/github/setting-up-and-managing-organizations-and-teams/managing-an-individuals-access-to-an-organization-project-board) +- [Managing team access to an organization project board](https://docs.github.com/en/github/setting-up-and-managing-organizations-and-teams/managing-team-access-to-an-organization-project-board) +- [Managing an individual's access to an organization project board](https://docs.github.com/en/github/setting-up-and-managing-organizations-and-teams/managing-an-individuals-access-to-an-organization-project-board) ## Example workflow -This workflow includes two team pings and runs every hour and can also be run manually. +This workflow includes two team pings and runs every hour and can also be run manually. ```yml name: First responder triage on: workflow_dispatch: - schedule: + schedule: - cron: '0 * * * *' jobs: @@ -73,5 +74,5 @@ jobs: ignore-authors: 'sprocketbot, github-actions' ignore-commenters: 'sprocketbot' comment-body: ':robot: Thanks for the ping to team sprockets! :bellhop_bell: This issue was added to our first-responder project board. A team member will be along shortly to review this issue.' - + ``` diff --git a/action.yml b/action.yml index d0199e9..e11cab7 100644 --- a/action.yml +++ b/action.yml @@ -5,16 +5,16 @@ inputs: description: 'An access token.' required: true team: # id of input - description: 'The team ping to search for that is part of the `org` specified below. Do not include the org name (for example, use `docs-content-ecosystem`). Issues and pull requests authored or commented on by members of `team` are ignored unless you specify an alternate `ignore-team` parameter.' + description: 'The team ping to search for that is part of the `org` specified below. Do not include the org name (for example, use `docs-content-ecosystem`). Issues and pull requests authored or commented on by members of `team` are ignored unless you specify an alternate `ignore-team` parameter.' required: true - org: + org: description: 'The organization where the action should search for issues and pull requests.' required: true since: description: 'The start date to search for team pings. The action searches for issues or pull requests created since the date specified. Form: {4 digit year}-{month}-{day}. For example: "2020-5-20"' required: false default: '2020-1-1' - project-board: + project-board: description: 'The URL of the project board to place issues and pull requests. Must be an org project board.' required: true project-column: @@ -23,8 +23,11 @@ inputs: ignore-team: description: 'Ignores issues and pull requests authored or commented on by members of this team. Issues and pull requests authored or commented on by members of `team` are ignored unless you specify an alternate `ignore-team` parameter. You can use `ignore-team` to specify a larger team or a team that does not match the team ping being searched. The value you specify for `ignore-team` overrides the `team` value.' required: false - ignore-repos: - description: 'Repositories to ignore when searching issues and pull requests. You can add more than one repository by using a comma-separated list. Format: {owner}/{repo}. For example: octocat/hello-world' + include-repos: + description: 'Repositories to include when searching issues and pull requests. You can add more than one repository by using a comma-separated list. Format: {owner}/{repo}. For example: "octocat/hello-world, octocat/foobar"' + required: false + ignore-repos: + description: 'Repositories to ignore when searching issues and pull requests. You can add more than one repository by using a comma-separated list. Format: {owner}/{repo}. For example: "octocat/hello-world, octocat/foobar"' required: false ignore-authors: description: 'Ignores issues and pull requests authored by these accounts. You can add more than one repository by using a comma-separated list (for example, "actions-bot, hubot")' @@ -35,7 +38,7 @@ inputs: ignore-labels: description: 'Ignores issues and pull requests with specific labels. You can add more than one label by using a comma-separated list (for example, "space-2x, autogen")' required: false - comment-body: + comment-body: description: 'A comment added to the issue or pull request.' required: false diff --git a/dist/index.js b/dist/index.js index ea031eb..7b24247 100644 --- a/dist/index.js +++ b/dist/index.js @@ -509,6 +509,8 @@ async function run () { const columnId = parseInt(core.getInput('project-column'), 10) const ignoreTeam = core.getInput('ignore-team') const body = core.getInput('comment-body') + const includeRepos = core.getInput('include-repos') !== '' + ? core.getInput('include-repos').split(',').map(x => x.trim()) : [] const ignoreRepos = core.getInput('ignore-repos') !== '' ? core.getInput('ignore-repos').split(',').map(x => x.trim()) : [] const ignoreLabels = core.getInput('ignore-labels') !== '' @@ -521,6 +523,11 @@ async function run () { const projectInfo = await getProjectMetaData(projectBoard, org) + // Only include-repos OR ignore-repos can be passed in but not both. + if (includeRepos.length > 0 && ignoreRepos.length > 0) { + throw new Error('Pass either include-repos or ignore-repos as an option but not both.') + } + // Create a list of users to ignore in the search query let teamMembers = [] if (ignoreTeam === '') { @@ -532,7 +539,7 @@ async function run () { ignoreCommenters = ignoreCommenters.concat(teamMembers) // Assemble and run the issue/pull request search query - const issues = await getTeamPingIssues(octokit, org, fullTeamName, ignoreAuthors, ignoreCommenters, since, projectInfo, ignoreRepos, ignoreLabels) + const issues = await getTeamPingIssues(octokit, org, fullTeamName, ignoreAuthors, ignoreCommenters, since, projectInfo, includeRepos, ignoreRepos, ignoreLabels) if (issues.data.incomplete_results === false) { console.log('🌵🌵🌵 All search results were found. 🌵🌵🌵') @@ -566,7 +573,7 @@ async function run () { return '🏁⛑' } -async function getTeamPingIssues (octokit, org, team, authors, commenters, since = '2019-01-01', projectBoard, ignoreRepos, ignoreLabels) { +async function getTeamPingIssues (octokit, org, team, authors, commenters, since = '2019-01-01', projectBoard, includeRepos, ignoreRepos, ignoreLabels) { // Search for open issues in repositories owned by `org` // and includes a team mention to `team` let query = `per_page=100&q=is%3Aopen+org%3A${org}+team%3A${team}` @@ -580,10 +587,17 @@ async function getTeamPingIssues (octokit, org, team, authors, commenters, since // Add the created since date query query = query.concat(`+created%3A%3E${since}`) - // Add ignore repos query - ignoreRepos.forEach(elem => { - query = query.concat(`+-repo%3A${elem}`) - }) + if (includeRepos.length > 0) { + // Add include repos query + includeRepos.forEach(elem => { + query = query.concat(`+repo%3A${elem}`) + }) + } else if (ignoreRepos.length > 0) { + // Add ignore repos query + ignoreRepos.forEach(elem => { + query = query.concat(`+-repo%3A${elem}`) + }) + } // Add ignore labels query ignoreLabels.forEach(elem => { @@ -2173,7 +2187,7 @@ module.exports = require("https"); /***/ 215: /***/ (function(module) { -module.exports = {"_args":[["@octokit/rest@16.43.1","/Users/rachmari/github-repos/first-responder"]],"_from":"@octokit/rest@16.43.1","_id":"@octokit/rest@16.43.1","_inBundle":false,"_integrity":"sha512-gfFKwRT/wFxq5qlNjnW2dh+qh74XgTQ2B179UX5K1HYCluioWj8Ndbgqw2PVqa1NnVJkGHp2ovMpVn/DImlmkw==","_location":"/@octokit/rest","_phantomChildren":{"@types/node":"14.0.5","deprecation":"2.3.1","once":"1.4.0","os-name":"3.1.0"},"_requested":{"type":"version","registry":true,"raw":"@octokit/rest@16.43.1","name":"@octokit/rest","escapedName":"@octokit%2frest","scope":"@octokit","rawSpec":"16.43.1","saveSpec":null,"fetchSpec":"16.43.1"},"_requiredBy":["/@actions/github"],"_resolved":"https://registry.npmjs.org/@octokit/rest/-/rest-16.43.1.tgz","_spec":"16.43.1","_where":"/Users/rachmari/github-repos/first-responder","author":{"name":"Gregor Martynus","url":"https://github.com/gr2m"},"bugs":{"url":"https://github.com/octokit/rest.js/issues"},"bundlesize":[{"path":"./dist/octokit-rest.min.js.gz","maxSize":"33 kB"}],"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"}],"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"},"description":"GitHub REST API client for Node.js","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":"^3.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":"^5.1.2","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"},"files":["index.js","index.d.ts","lib","plugins"],"homepage":"https://github.com/octokit/rest.js#readme","keywords":["octokit","github","rest","api-client"],"license":"MIT","name":"@octokit/rest","nyc":{"ignore":["test"]},"publishConfig":{"access":"public"},"release":{"publish":["@semantic-release/npm",{"path":"@semantic-release/github","assets":["dist/*","!dist/*.map.gz"]}]},"repository":{"type":"git","url":"git+https://github.com/octokit/rest.js.git"},"scripts":{"build":"npm-run-all build:*","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","build:ts":"npm run -s update-endpoints:typescript","coverage":"nyc report --reporter=html && open coverage/index.html","generate-bundle-report":"webpack-bundle-analyzer dist/bundle-stats.json --mode=static --no-open --report dist/bundle-report.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","postvalidate:ts":"tsc --noEmit --target es6 test/typescript-validate.ts","prebuild:browser":"mkdirp dist/","pretest":"npm run -s lint","prevalidate:ts":"npm run -s build:ts","start-fixtures-server":"octokit-fixtures-server","test":"nyc mocha test/mocha-node-setup.js \"test/*/**/*-test.js\"","test:browser":"cypress run --browser chrome","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","validate:ts":"tsc --target es6 --noImplicitAny index.d.ts"},"types":"index.d.ts","version":"16.43.1"}; +module.exports = {"name":"@octokit/rest","version":"16.43.1","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":"^3.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":"^5.1.2","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"}]}; /***/ }), diff --git a/index.js b/index.js index 03921b1..d98ef8d 100755 --- a/index.js +++ b/index.js @@ -12,6 +12,8 @@ async function run () { const columnId = parseInt(core.getInput('project-column'), 10) const ignoreTeam = core.getInput('ignore-team') const body = core.getInput('comment-body') + const includeRepos = core.getInput('include-repos') !== '' + ? core.getInput('include-repos').split(',').map(x => x.trim()) : [] const ignoreRepos = core.getInput('ignore-repos') !== '' ? core.getInput('ignore-repos').split(',').map(x => x.trim()) : [] const ignoreLabels = core.getInput('ignore-labels') !== '' @@ -24,6 +26,11 @@ async function run () { const projectInfo = await getProjectMetaData(projectBoard, org) + // Only include-repos OR ignore-repos can be passed in but not both. + if (includeRepos.length > 0 && ignoreRepos.length > 0) { + throw new Error('Pass either include-repos or ignore-repos as an option but not both.') + } + // Create a list of users to ignore in the search query let teamMembers = [] if (ignoreTeam === '') { @@ -35,7 +42,7 @@ async function run () { ignoreCommenters = ignoreCommenters.concat(teamMembers) // Assemble and run the issue/pull request search query - const issues = await getTeamPingIssues(octokit, org, fullTeamName, ignoreAuthors, ignoreCommenters, since, projectInfo, ignoreRepos, ignoreLabels) + const issues = await getTeamPingIssues(octokit, org, fullTeamName, ignoreAuthors, ignoreCommenters, since, projectInfo, includeRepos, ignoreRepos, ignoreLabels) if (issues.data.incomplete_results === false) { console.log('🌵🌵🌵 All search results were found. 🌵🌵🌵') @@ -69,7 +76,7 @@ async function run () { return '🏁⛑' } -async function getTeamPingIssues (octokit, org, team, authors, commenters, since = '2019-01-01', projectBoard, ignoreRepos, ignoreLabels) { +async function getTeamPingIssues (octokit, org, team, authors, commenters, since = '2019-01-01', projectBoard, includeRepos, ignoreRepos, ignoreLabels) { // Search for open issues in repositories owned by `org` // and includes a team mention to `team` let query = `per_page=100&q=is%3Aopen+org%3A${org}+team%3A${team}` @@ -83,10 +90,17 @@ async function getTeamPingIssues (octokit, org, team, authors, commenters, since // Add the created since date query query = query.concat(`+created%3A%3E${since}`) - // Add ignore repos query - ignoreRepos.forEach(elem => { - query = query.concat(`+-repo%3A${elem}`) - }) + if (includeRepos.length > 0) { + // Add include repos query + includeRepos.forEach(elem => { + query = query.concat(`+repo%3A${elem}`) + }) + } else if (ignoreRepos.length > 0) { + // Add ignore repos query + ignoreRepos.forEach(elem => { + query = query.concat(`+-repo%3A${elem}`) + }) + } // Add ignore labels query ignoreLabels.forEach(elem => {