diff --git a/README.md b/README.md index f9d14a899..243e50d02 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ The base match object is defined as: - all-globs-to-all-files: ['list', 'of', 'globs'] - base-branch: ['list', 'of', 'regexps'] - head-branch: ['list', 'of', 'regexps'] +- authors: ['list', 'of', 'authors'] # github users ``` There are two top-level keys, `any` and `all`, which both accept the same configuration options: diff --git a/__mocks__/@actions/github.ts b/__mocks__/@actions/github.ts index 5d6ecd56d..993e40aa9 100644 --- a/__mocks__/@actions/github.ts +++ b/__mocks__/@actions/github.ts @@ -2,6 +2,9 @@ export const context = { payload: { pull_request: { number: 123, + user: { + login: 'monalisa' + }, head: { ref: 'head-branch-name' }, diff --git a/__tests__/labeler.test.ts b/__tests__/labeler.test.ts index 75d25ef2f..71c239f34 100644 --- a/__tests__/labeler.test.ts +++ b/__tests__/labeler.test.ts @@ -67,12 +67,14 @@ describe('toMatchConfig', () => { const config = { 'changed-files': [{'any-glob-to-any-file': ['testing-files']}], 'head-branch': ['testing-head'], - 'base-branch': ['testing-base'] + 'base-branch': ['testing-base'], + authors: ['testing-author'] }; const expected: BaseMatchConfig = { changedFiles: [{anyGlobToAnyFile: ['testing-files']}], headBranch: ['testing-head'], - baseBranch: ['testing-base'] + baseBranch: ['testing-base'], + authors: ['testing-author'] }; it('returns a MatchConfig object with all options', () => { @@ -232,4 +234,42 @@ describe('labeler error handling', () => { ); expect(core.setFailed).toHaveBeenCalledWith(error.message); }); + + it('returns true when PR author is in the list of authors', () => { + const matchConfigWithAuthor: MatchConfig[] = [ + { + any: [ + {changedFiles: [{anyGlobToAnyFile: ['*.txt']}]}, + {authors: ['monalisa', 'hubot']} + ] + } + ]; + const changedFiles = ['not_match.pdf']; + + const result = checkMatchConfigs( + changedFiles, + matchConfigWithAuthor, + false + ); + expect(result).toBeTruthy(); + }); + + it('returns false when PR author is not in the list of authors', () => { + const matchConfigWithAuthor: MatchConfig[] = [ + { + any: [ + {changedFiles: [{anyGlobToAnyFile: ['*.txt']}]}, + {authors: ['foo', 'bar']} + ] + } + ]; + const changedFiles = ['not_match.pdf']; + + const result = checkMatchConfigs( + changedFiles, + matchConfigWithAuthor, + false + ); + expect(result).toBeFalsy(); + }); }); diff --git a/dist/index.js b/dist/index.js index 35bb10846..1ff3ab8a6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -277,7 +277,12 @@ const fs_1 = __importDefault(__nccwpck_require__(9896)); const get_content_1 = __nccwpck_require__(6519); const changedFiles_1 = __nccwpck_require__(5145); const branch_1 = __nccwpck_require__(2234); -const ALLOWED_CONFIG_KEYS = ['changed-files', 'head-branch', 'base-branch']; +const ALLOWED_CONFIG_KEYS = [ + 'changed-files', + 'head-branch', + 'base-branch', + 'authors' +]; const getLabelConfigs = (client, configurationPath) => Promise.resolve() .then(() => { if (!fs_1.default.existsSync(configurationPath)) { @@ -352,7 +357,8 @@ function getLabelConfigMapFromObject(configObject) { function toMatchConfig(config) { const changedFilesConfig = (0, changedFiles_1.toChangedFilesMatchConfig)(config); const branchConfig = (0, branch_1.toBranchMatchConfig)(config); - return Object.assign(Object.assign({}, changedFilesConfig), branchConfig); + const authorsConfig = config['authors'] ? { authors: config['authors'] } : {}; + return Object.assign(Object.assign(Object.assign({}, changedFilesConfig), branchConfig), authorsConfig); } @@ -1170,6 +1176,12 @@ function checkAny(matchConfigs, changedFiles, dot) { return true; } } + if (matchConfig.authors) { + if (checkAuthors(matchConfig.authors)) { + core.debug(` "any" patterns matched`); + return true; + } + } } core.debug(` "any" patterns did not match any configs`); return false; @@ -1205,10 +1217,30 @@ function checkAll(matchConfigs, changedFiles, dot) { return false; } } + if (matchConfig.authors) { + if (!checkAuthors(matchConfig.authors)) { + core.debug(` "all" patterns did not match`); + return false; + } + } } core.debug(` "all" patterns matched all configs`); return true; } +function checkAuthors(authors) { + var _a, _b; + const prAuthor = (_b = (_a = github.context.payload.pull_request) === null || _a === void 0 ? void 0 : _a.user) === null || _b === void 0 ? void 0 : _b.login; + if (!prAuthor) { + core.info('Could not get pull request author from context, exiting'); + return false; + } + if (authors.includes(prAuthor)) { + core.debug(` author ${prAuthor} is on the list`); + return true; + } + core.debug(` author ${prAuthor} is not on the list`); + return false; +} /***/ }), diff --git a/src/api/get-label-configs.ts b/src/api/get-label-configs.ts index 4db33f28e..3e87bbc6c 100644 --- a/src/api/get-label-configs.ts +++ b/src/api/get-label-configs.ts @@ -11,14 +11,25 @@ import { import {toBranchMatchConfig, BranchMatchConfig} from '../branch'; +export interface AuthorsMatchConfig { + authors?: string[]; +} + export interface MatchConfig { all?: BaseMatchConfig[]; any?: BaseMatchConfig[]; } -export type BaseMatchConfig = BranchMatchConfig & ChangedFilesMatchConfig; +export type BaseMatchConfig = BranchMatchConfig & + ChangedFilesMatchConfig & + AuthorsMatchConfig; -const ALLOWED_CONFIG_KEYS = ['changed-files', 'head-branch', 'base-branch']; +const ALLOWED_CONFIG_KEYS = [ + 'changed-files', + 'head-branch', + 'base-branch', + 'authors' +]; export const getLabelConfigs = ( client: ClientType, @@ -118,9 +129,11 @@ export function getLabelConfigMapFromObject( export function toMatchConfig(config: any): BaseMatchConfig { const changedFilesConfig = toChangedFilesMatchConfig(config); const branchConfig = toBranchMatchConfig(config); + const authorsConfig = config['authors'] ? {authors: config['authors']} : {}; return { ...changedFilesConfig, - ...branchConfig + ...branchConfig, + ...authorsConfig }; } diff --git a/src/labeler.ts b/src/labeler.ts index 8f9484f34..1b0211a81 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -183,6 +183,13 @@ export function checkAny( return true; } } + + if (matchConfig.authors) { + if (checkAuthors(matchConfig.authors)) { + core.debug(` "any" patterns matched`); + return true; + } + } } core.debug(` "any" patterns did not match any configs`); @@ -230,8 +237,31 @@ export function checkAll( return false; } } + + if (matchConfig.authors) { + if (!checkAuthors(matchConfig.authors)) { + core.debug(` "all" patterns did not match`); + return false; + } + } } core.debug(` "all" patterns matched all configs`); return true; } + +function checkAuthors(authors: string[]): boolean { + const prAuthor = github.context.payload.pull_request?.user?.login; + if (!prAuthor) { + core.info('Could not get pull request author from context, exiting'); + return false; + } + + if (authors.includes(prAuthor)) { + core.debug(` author ${prAuthor} is on the list`); + return true; + } + + core.debug(` author ${prAuthor} is not on the list`); + return false; +}