From 8c59eccb9d192d7cb15bff01017c735a92a51337 Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sat, 28 Jan 2023 15:14:15 -0500 Subject: [PATCH 01/17] Rename the getBranchName helper --- src/labeler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/labeler.ts b/src/labeler.ts index 70d74cdb..6f882ca5 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -72,7 +72,7 @@ function getPrNumber(): number | undefined { return pullRequest.number; } -function getBranchName(): string | undefined { +function getHeadBranchName(): string | undefined { const pullRequest = github.context.payload.pull_request; if (!pullRequest) { return undefined; @@ -235,7 +235,7 @@ function matchBranchPattern(matcher: IMinimatch, branchName: string): boolean { } function checkBranch(glob: string | string[]): boolean { - const branchName = getBranchName(); + const branchName = getHeadBranchName(); if (!branchName) { core.debug(` no branch name`); return false; From f2b2513f41be201d9158a7eede74d3f4294362a5 Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sat, 28 Jan 2023 15:34:31 -0500 Subject: [PATCH 02/17] Update the matching to use a regexp rather than minimatch --- __tests__/fixtures/branches.yml | 8 +++---- src/labeler.ts | 38 ++++++++++++++++----------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/__tests__/fixtures/branches.yml b/__tests__/fixtures/branches.yml index 57369f42..266ef961 100644 --- a/__tests__/fixtures/branches.yml +++ b/__tests__/fixtures/branches.yml @@ -1,11 +1,11 @@ test-branch: - - branch: "test/**" + - branch: "^test/" feature-branch: - - branch: "*/feature/*" + - branch: "/feature/" bug-branch: - - branch: "{bug,fix}/*" + - branch: "^bug/|fix/" array-branch: - - branch: ["array/*"] + - branch: ["^array/"] diff --git a/src/labeler.ts b/src/labeler.ts index 6f882ca5..9b3c31b3 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -6,7 +6,7 @@ import {Minimatch, IMinimatch} from 'minimatch'; interface MatchConfig { all?: string[]; any?: string[]; - branch?: string | string[]; + branch?: string[]; } type StringOrMatchConfig = string | MatchConfig; @@ -156,6 +156,11 @@ function toMatchConfig(config: StringOrMatchConfig): MatchConfig { return { any: [config] }; + } else if (typeof config.branch === 'string') { + return { + ...config, + branch: [config.branch] + }; } return config; @@ -223,18 +228,18 @@ function checkAll(changedFiles: string[], globs: string[]): boolean { return true; } -function matchBranchPattern(matcher: IMinimatch, branchName: string): boolean { - core.debug(` - ${printPattern(matcher)}`); - if (matcher.match(branchName)) { +function matchBranchPattern(matcher: RegExp, branchName: string): boolean { + core.debug(` - ${matcher}`); + if (matcher.test(branchName)) { core.debug(` "branch" pattern matched`); return true; } - core.debug(` ${printPattern(matcher)} did not match`); + core.debug(` ${matcher} did not match`); return false; } -function checkBranch(glob: string | string[]): boolean { +function checkBranch(glob: string[]): boolean { const branchName = getHeadBranchName(); if (!branchName) { core.debug(` no branch name`); @@ -242,21 +247,16 @@ function checkBranch(glob: string | string[]): boolean { } core.debug(` checking "branch" pattern against ${branchName}`); - if (Array.isArray(glob)) { - const matchers = glob.map(g => new Minimatch(g)); - for (const matcher of matchers) { - if (matchBranchPattern(matcher, branchName)) { - core.debug(` "branch" patterns matched against ${branchName}`); - return true; - } + const matchers = glob.map(g => new RegExp(g)); + for (const matcher of matchers) { + if (matchBranchPattern(matcher, branchName)) { + core.debug(` "branch" patterns matched against ${branchName}`); + return true; } - - core.debug(` "branch" patterns did not match against ${branchName}`); - return false; - } else { - const matcher = new Minimatch(glob); - return matchBranchPattern(matcher, branchName); } + + core.debug(` "branch" patterns did not match against ${branchName}`); + return false; } function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean { From 23437107778e4f94ed49da88da3ca180dca9e159 Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sat, 28 Jan 2023 15:58:00 -0500 Subject: [PATCH 03/17] Move all the branch checking into its own file --- src/branch.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ src/labeler.ts | 42 ++---------------------------------------- 2 files changed, 44 insertions(+), 40 deletions(-) create mode 100644 src/branch.ts diff --git a/src/branch.ts b/src/branch.ts new file mode 100644 index 00000000..e2637896 --- /dev/null +++ b/src/branch.ts @@ -0,0 +1,42 @@ +import * as core from '@actions/core'; +import * as github from '@actions/github'; + +function getHeadBranchName(): string | undefined { + const pullRequest = github.context.payload.pull_request; + if (!pullRequest) { + return undefined; + } + + return pullRequest.head?.ref; +} + +export function checkBranch(glob: string[]): boolean { + const branchName = getHeadBranchName(); + if (!branchName) { + core.debug(` no branch name`); + return false; + } + + core.debug(` checking "branch" pattern against ${branchName}`); + const matchers = glob.map(g => new RegExp(g)); + for (const matcher of matchers) { + if (matchBranchPattern(matcher, branchName)) { + core.debug(` "branch" patterns matched against ${branchName}`); + return true; + } + } + + core.debug(` "branch" patterns did not match against ${branchName}`); + return false; +} + +function matchBranchPattern(matcher: RegExp, branchName: string): boolean { + core.debug(` - ${matcher}`); + if (matcher.test(branchName)) { + core.debug(` "branch" pattern matched`); + return true; + } + + core.debug(` ${matcher} did not match`); + return false; +} diff --git a/src/labeler.ts b/src/labeler.ts index 9b3c31b3..75bcb4c4 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -3,6 +3,8 @@ import * as github from '@actions/github'; import * as yaml from 'js-yaml'; import {Minimatch, IMinimatch} from 'minimatch'; +import {checkBranch} from './branch'; + interface MatchConfig { all?: string[]; any?: string[]; @@ -72,15 +74,6 @@ function getPrNumber(): number | undefined { return pullRequest.number; } -function getHeadBranchName(): string | undefined { - const pullRequest = github.context.payload.pull_request; - if (!pullRequest) { - return undefined; - } - - return pullRequest.head?.ref; -} - async function getChangedFiles( client: ClientType, prNumber: number @@ -228,37 +221,6 @@ function checkAll(changedFiles: string[], globs: string[]): boolean { return true; } -function matchBranchPattern(matcher: RegExp, branchName: string): boolean { - core.debug(` - ${matcher}`); - if (matcher.test(branchName)) { - core.debug(` "branch" pattern matched`); - return true; - } - - core.debug(` ${matcher} did not match`); - return false; -} - -function checkBranch(glob: string[]): boolean { - const branchName = getHeadBranchName(); - if (!branchName) { - core.debug(` no branch name`); - return false; - } - - core.debug(` checking "branch" pattern against ${branchName}`); - const matchers = glob.map(g => new RegExp(g)); - for (const matcher of matchers) { - if (matchBranchPattern(matcher, branchName)) { - core.debug(` "branch" patterns matched against ${branchName}`); - return true; - } - } - - core.debug(` "branch" patterns did not match against ${branchName}`); - return false; -} - function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean { if (matchConfig.all !== undefined) { if (!checkAll(changedFiles, matchConfig.all)) { From cd3a8df80d79662d01c7d05470e3517c43f6a3fb Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sat, 28 Jan 2023 16:23:47 -0500 Subject: [PATCH 04/17] Create a test file for branch --- __tests__/branch.test.ts | 58 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 __tests__/branch.test.ts diff --git a/__tests__/branch.test.ts b/__tests__/branch.test.ts new file mode 100644 index 00000000..b5849017 --- /dev/null +++ b/__tests__/branch.test.ts @@ -0,0 +1,58 @@ +import {checkBranch} from '../src/branch'; +import * as github from '@actions/github'; + +jest.mock('@actions/core'); +jest.mock('@actions/github'); + +describe('checkBranch', () => { + describe('when a single pattern is provided', () => { + beforeEach(() => { + github.context.payload.pull_request!.head = { + ref: 'test/feature/123' + }; + }); + + describe('and the pattern matches the head branch', () => { + it('returns true', () => { + const result = checkBranch(['^test']); + expect(result).toBe(true); + }); + }); + + describe('and the pattern does not match the head branch', () => { + it('returns false', () => { + const result = checkBranch(['^feature/']); + expect(result).toBe(false); + }); + }); + }); + + describe('when multiple patterns are provided', () => { + beforeEach(() => { + github.context.payload.pull_request!.head = { + ref: 'test/feature/123' + }; + }); + + describe('and at least one pattern matches', () => { + it('returns true', () => { + const result = checkBranch(['^test/', '^feature/']); + expect(result).toBe(true); + }); + }); + + describe('and all patterns match', () => { + it('returns true', () => { + const result = checkBranch(['^test/', '/feature/']); + expect(result).toBe(true); + }); + }); + + describe('and no patterns match', () => { + it('returns false', () => { + const result = checkBranch(['^feature/', '/test$']); + expect(result).toBe(false); + }); + }); + }); +}); From 0b6e68d75ab875b7d7e2da7674c3255958bfd84e Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sat, 28 Jan 2023 17:53:41 -0500 Subject: [PATCH 05/17] Add options for getting the head or base branch --- __mocks__/@actions/github.ts | 8 ++++++- __tests__/branch.test.ts | 43 +++++++++++++++++++++++++----------- src/branch.ts | 14 ++++++++---- src/labeler.ts | 14 ++++++++++++ 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/__mocks__/@actions/github.ts b/__mocks__/@actions/github.ts index ea8319f6..b3629370 100644 --- a/__mocks__/@actions/github.ts +++ b/__mocks__/@actions/github.ts @@ -1,7 +1,13 @@ export const context = { payload: { pull_request: { - number: 123 + number: 123, + head: { + ref: 'head-branch-name' + }, + base: { + ref: 'base-branch-name' + } } }, repo: { diff --git a/__tests__/branch.test.ts b/__tests__/branch.test.ts index b5849017..51855ba5 100644 --- a/__tests__/branch.test.ts +++ b/__tests__/branch.test.ts @@ -1,17 +1,40 @@ -import {checkBranch} from '../src/branch'; +import {getBranchName, checkBranch} from '../src/branch'; import * as github from '@actions/github'; jest.mock('@actions/core'); jest.mock('@actions/github'); -describe('checkBranch', () => { - describe('when a single pattern is provided', () => { - beforeEach(() => { - github.context.payload.pull_request!.head = { - ref: 'test/feature/123' - }; +describe('getBranchName', () => { + describe('when the pull requests base branch is requested', () => { + it('returns the base branch name', () => { + const result = getBranchName('base'); + expect(result).toEqual('base-branch-name'); }); + }); + describe('when the pull requests head branch is requested', () => { + it('returns the head branch name', () => { + const result = getBranchName('head'); + expect(result).toEqual('head-branch-name'); + }); + }); + + describe('when no branch is specified', () => { + it('returns the head branch name', () => { + const result = getBranchName('base'); + expect(result).toEqual('base-branch-name'); + }); + }); +}); + +describe('checkBranch', () => { + beforeEach(() => { + github.context.payload.pull_request!.head = { + ref: 'test/feature/123' + }; + }); + + describe('when a single pattern is provided', () => { describe('and the pattern matches the head branch', () => { it('returns true', () => { const result = checkBranch(['^test']); @@ -28,12 +51,6 @@ describe('checkBranch', () => { }); describe('when multiple patterns are provided', () => { - beforeEach(() => { - github.context.payload.pull_request!.head = { - ref: 'test/feature/123' - }; - }); - describe('and at least one pattern matches', () => { it('returns true', () => { const result = checkBranch(['^test/', '^feature/']); diff --git a/src/branch.ts b/src/branch.ts index e2637896..d6ccc3ad 100644 --- a/src/branch.ts +++ b/src/branch.ts @@ -1,17 +1,23 @@ import * as core from '@actions/core'; import * as github from '@actions/github'; -function getHeadBranchName(): string | undefined { +type BranchBase = 'base' | 'head'; + +export function getBranchName(branchBase?: BranchBase): string | undefined { const pullRequest = github.context.payload.pull_request; if (!pullRequest) { return undefined; } - return pullRequest.head?.ref; + if (branchBase === 'base') { + return pullRequest.base?.ref; + } else { + return pullRequest.head?.ref; + } } -export function checkBranch(glob: string[]): boolean { - const branchName = getHeadBranchName(); +export function checkBranch(glob: string[], branchBase?: BranchBase): boolean { + const branchName = getBranchName(branchBase); if (!branchName) { core.debug(` no branch name`); return false; diff --git a/src/labeler.ts b/src/labeler.ts index 75bcb4c4..cf8e9d4d 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -9,6 +9,8 @@ interface MatchConfig { all?: string[]; any?: string[]; branch?: string[]; + headBranch?: string[]; + baseBranch?: string[]; } type StringOrMatchConfig = string | MatchConfig; @@ -240,6 +242,18 @@ function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean { } } + if (matchConfig.headBranch !== undefined) { + if (!checkBranch(matchConfig.headBranch, 'head')) { + return false; + } + } + + if (matchConfig.baseBranch !== undefined) { + if (!checkBranch(matchConfig.baseBranch, 'base')) { + return false; + } + } + return true; } From 2daf35ae4b9b338e3bc554cac708f6306c09c7fa Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sat, 28 Jan 2023 18:08:48 -0500 Subject: [PATCH 06/17] Add an extra test now that we can check the base branch --- __tests__/branch.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/__tests__/branch.test.ts b/__tests__/branch.test.ts index 51855ba5..a9d60c81 100644 --- a/__tests__/branch.test.ts +++ b/__tests__/branch.test.ts @@ -32,6 +32,9 @@ describe('checkBranch', () => { github.context.payload.pull_request!.head = { ref: 'test/feature/123' }; + github.context.payload.pull_request!.base = { + ref: 'main' + }; }); describe('when a single pattern is provided', () => { @@ -72,4 +75,13 @@ describe('checkBranch', () => { }); }); }); + + describe('when the branch to check is specified as the base branch', () => { + describe('and the pattern matches the base branch', () => { + it('returns true', () => { + const result = checkBranch(['^main$'], 'base'); + expect(result).toBe(true); + }); + }); + }); }); From 231de6bc242d90b525caa928ed430a2c83996fcb Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sat, 28 Jan 2023 22:30:05 -0500 Subject: [PATCH 07/17] Remove the branch option and replace with just head-branch and base-branch --- __tests__/fixtures/branches.yml | 8 ++++---- src/branch.ts | 32 ++++++++++++++++++++++++++++++++ src/labeler.ts | 16 ++-------------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/__tests__/fixtures/branches.yml b/__tests__/fixtures/branches.yml index 266ef961..c4c2e7ba 100644 --- a/__tests__/fixtures/branches.yml +++ b/__tests__/fixtures/branches.yml @@ -1,11 +1,11 @@ test-branch: - - branch: "^test/" + - head-branch: "^test/" feature-branch: - - branch: "/feature/" + - head-branch: "/feature/" bug-branch: - - branch: "^bug/|fix/" + - head-branch: "^bug/|fix/" array-branch: - - branch: ["^array/"] + - head-branch: ["^array/"] diff --git a/src/branch.ts b/src/branch.ts index d6ccc3ad..1c7e87b3 100644 --- a/src/branch.ts +++ b/src/branch.ts @@ -3,6 +3,38 @@ import * as github from '@actions/github'; type BranchBase = 'base' | 'head'; +export function toMatchConfigWithBranches(config: any) { + if (!config['head-branch'] || config['base-branch']) { + return config; + } + + const branchConfig = { + headBranch: config['head-branch'], + baseBranch: config['base-branch'] + }; + + if (branchConfig.headBranch) { + const patterns = branchConfig.headBranch; + if (typeof patterns === 'string') { + branchConfig.headBranch = [patterns]; + } + } + + if (branchConfig.baseBranch) { + const patterns = branchConfig.baseBranch; + if (typeof patterns === 'string') { + branchConfig.baseBranch = [patterns]; + } + } + + return { + ...config, + ['head-branch']: undefined, + ['base-branch']: undefined, + ...branchConfig + }; +} + export function getBranchName(branchBase?: BranchBase): string | undefined { const pullRequest = github.context.payload.pull_request; if (!pullRequest) { diff --git a/src/labeler.ts b/src/labeler.ts index cf8e9d4d..0c24d558 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -3,12 +3,11 @@ import * as github from '@actions/github'; import * as yaml from 'js-yaml'; import {Minimatch, IMinimatch} from 'minimatch'; -import {checkBranch} from './branch'; +import {checkBranch, toMatchConfigWithBranches} from './branch'; interface MatchConfig { all?: string[]; any?: string[]; - branch?: string[]; headBranch?: string[]; baseBranch?: string[]; } @@ -151,14 +150,9 @@ function toMatchConfig(config: StringOrMatchConfig): MatchConfig { return { any: [config] }; - } else if (typeof config.branch === 'string') { - return { - ...config, - branch: [config.branch] - }; } - return config; + return toMatchConfigWithBranches(config); } function printPattern(matcher: IMinimatch): string { @@ -236,12 +230,6 @@ function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean { } } - if (matchConfig.branch !== undefined) { - if (!checkBranch(matchConfig.branch)) { - return false; - } - } - if (matchConfig.headBranch !== undefined) { if (!checkBranch(matchConfig.headBranch, 'head')) { return false; From 922ffdf5ad73c1355b621b9c54e33dfc5070199f Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sat, 28 Jan 2023 22:43:56 -0500 Subject: [PATCH 08/17] Remove deprecated IMinimatch import from labeler.ts --- src/labeler.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/labeler.ts b/src/labeler.ts index 0c24d558..a83181ca 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -1,7 +1,7 @@ import * as core from '@actions/core'; import * as github from '@actions/github'; import * as yaml from 'js-yaml'; -import {Minimatch, IMinimatch} from 'minimatch'; +import {Minimatch} from 'minimatch'; import {checkBranch, toMatchConfigWithBranches} from './branch'; @@ -155,7 +155,7 @@ function toMatchConfig(config: StringOrMatchConfig): MatchConfig { return toMatchConfigWithBranches(config); } -function printPattern(matcher: IMinimatch): string { +function printPattern(matcher: Minimatch): string { return (matcher.negate ? '!' : '') + matcher.pattern; } @@ -173,7 +173,7 @@ export function checkGlobs( return false; } -function isMatch(changedFile: string, matchers: IMinimatch[]): boolean { +function isMatch(changedFile: string, matchers: Minimatch[]): boolean { core.debug(` matching patterns against file ${changedFile}`); for (const matcher of matchers) { core.debug(` - ${printPattern(matcher)}`); From 7a5c525049060d5fabd057d0f303bbed03f895df Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sat, 28 Jan 2023 23:12:53 -0500 Subject: [PATCH 09/17] Create new interfaces for MatchConfig --- src/branch.ts | 14 +++++++------- src/labeler.ts | 19 ++++++++++++++----- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/branch.ts b/src/branch.ts index 1c7e87b3..0a39a1d3 100644 --- a/src/branch.ts +++ b/src/branch.ts @@ -1,9 +1,14 @@ import * as core from '@actions/core'; import * as github from '@actions/github'; +export interface BranchMatchConfig { + headBranch?: string[]; + baseBranch?: string[]; +} + type BranchBase = 'base' | 'head'; -export function toMatchConfigWithBranches(config: any) { +export function toBranchMatchConfig(config: any): BranchMatchConfig { if (!config['head-branch'] || config['base-branch']) { return config; } @@ -27,12 +32,7 @@ export function toMatchConfigWithBranches(config: any) { } } - return { - ...config, - ['head-branch']: undefined, - ['base-branch']: undefined, - ...branchConfig - }; + return branchConfig; } export function getBranchName(branchBase?: BranchBase): string | undefined { diff --git a/src/labeler.ts b/src/labeler.ts index a83181ca..919571fa 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -3,15 +3,19 @@ import * as github from '@actions/github'; import * as yaml from 'js-yaml'; import {Minimatch} from 'minimatch'; -import {checkBranch, toMatchConfigWithBranches} from './branch'; +import {checkBranch, toBranchMatchConfig, BranchMatchConfig} from './branch'; -interface MatchConfig { +interface FilesChangedMatchConfig { all?: string[]; any?: string[]; - headBranch?: string[]; - baseBranch?: string[]; + filesChanged?: { + all?: string[]; + any?: string[]; + }; } +type MatchConfig = FilesChangedMatchConfig & BranchMatchConfig; + type StringOrMatchConfig = string | MatchConfig; type ClientType = ReturnType; @@ -152,7 +156,12 @@ function toMatchConfig(config: StringOrMatchConfig): MatchConfig { }; } - return toMatchConfigWithBranches(config); + const branchConfig = toBranchMatchConfig(config); + + return { + ...config, + ...branchConfig + }; } function printPattern(matcher: Minimatch): string { From 969899da68c826b00b7a9ebce80e7f2a7487d6c4 Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sun, 29 Jan 2023 14:10:07 -0500 Subject: [PATCH 10/17] Add the changedFiles key and update logic in labeler --- __tests__/fixtures/only_pdfs.yml | 3 +- __tests__/labeler.test.ts | 2 +- src/branch.ts | 2 +- src/labeler.ts | 66 +++++++++++++++++++++++--------- 4 files changed, 51 insertions(+), 22 deletions(-) diff --git a/__tests__/fixtures/only_pdfs.yml b/__tests__/fixtures/only_pdfs.yml index 1bcce76a..0f4b61a7 100644 --- a/__tests__/fixtures/only_pdfs.yml +++ b/__tests__/fixtures/only_pdfs.yml @@ -1,2 +1,3 @@ touched-a-pdf-file: - - any: ['*.pdf'] + - changed-files: + - any: ['*.pdf'] diff --git a/__tests__/labeler.test.ts b/__tests__/labeler.test.ts index d684d28b..7ec72b51 100644 --- a/__tests__/labeler.test.ts +++ b/__tests__/labeler.test.ts @@ -10,7 +10,7 @@ beforeAll(() => { }); }); -const matchConfig = [{any: ['*.txt']}]; +const matchConfig = [{changedFiles: {any: ['*.txt']}}]; describe('checkGlobs', () => { it('returns true when our pattern does match changed files', () => { diff --git a/src/branch.ts b/src/branch.ts index 0a39a1d3..1804a37d 100644 --- a/src/branch.ts +++ b/src/branch.ts @@ -10,7 +10,7 @@ type BranchBase = 'base' | 'head'; export function toBranchMatchConfig(config: any): BranchMatchConfig { if (!config['head-branch'] || config['base-branch']) { - return config; + return {}; } const branchConfig = { diff --git a/src/labeler.ts b/src/labeler.ts index 919571fa..551a2203 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -5,18 +5,15 @@ import {Minimatch} from 'minimatch'; import {checkBranch, toBranchMatchConfig, BranchMatchConfig} from './branch'; -interface FilesChangedMatchConfig { - all?: string[]; - any?: string[]; - filesChanged?: { +interface ChangedFilesMatchConfig { + changedFiles?: { all?: string[]; any?: string[]; }; } -type MatchConfig = FilesChangedMatchConfig & BranchMatchConfig; +export type MatchConfig = ChangedFilesMatchConfig & BranchMatchConfig; -type StringOrMatchConfig = string | MatchConfig; type ClientType = ReturnType; export async function run() { @@ -41,7 +38,7 @@ export async function run() { core.debug(`fetching changed files for pr #${prNumber}`); const changedFiles: string[] = await getChangedFiles(client, prNumber); - const labelGlobs: Map = await getLabelGlobs( + const labelGlobs: Map = await getLabelGlobs( client, configPath ); @@ -103,7 +100,7 @@ async function getChangedFiles( async function getLabelGlobs( client: ClientType, configurationPath: string -): Promise> { +): Promise> { const configurationContent: string = await fetchContent( client, configurationPath @@ -132,8 +129,8 @@ async function fetchContent( function getLabelGlobMapFromObject( configObject: any -): Map { - const labelGlobs: Map = new Map(); +): Map { + const labelGlobs: Map = new Map(); for (const label in configObject) { if (typeof configObject[label] === 'string') { labelGlobs.set(label, [configObject[label]]); @@ -149,17 +146,48 @@ function getLabelGlobMapFromObject( return labelGlobs; } -function toMatchConfig(config: StringOrMatchConfig): MatchConfig { - if (typeof config === 'string') { +function toChangedFilesMatchConfig(config: any): ChangedFilesMatchConfig { + if (!config['changed-files']) { + return {}; + } + const changedFiles = config['changed-files']; + + // If the value provided is a string or an array of strings then default to `any` matching + if (typeof changedFiles === 'string') { return { - any: [config] + changedFiles: { + any: [changedFiles] + } }; } + const changedFilesMatchConfig = { + changedFiles: {} + }; + + if (Array.isArray(changedFiles)) { + if (changedFiles.every(entry => typeof entry === 'string')) { + changedFilesMatchConfig.changedFiles = { + any: changedFiles + }; + } else { + // If it is not an array of strings then it should be array of further config options + // so assign them to our `changedFilesMatchConfig` + changedFiles.forEach(element => { + Object.assign(changedFilesMatchConfig.changedFiles, element); + }); + } + } + + return changedFilesMatchConfig; +} + +function toMatchConfig(config: MatchConfig): MatchConfig { + const changedFilesConfig = toChangedFilesMatchConfig(config); const branchConfig = toBranchMatchConfig(config); return { - ...config, + ...changedFilesConfig, ...branchConfig }; } @@ -170,7 +198,7 @@ function printPattern(matcher: Minimatch): string { export function checkGlobs( changedFiles: string[], - globs: StringOrMatchConfig[] + globs: MatchConfig[] ): boolean { for (const glob of globs) { core.debug(` checking pattern ${JSON.stringify(glob)}`); @@ -227,14 +255,14 @@ function checkAll(changedFiles: string[], globs: string[]): boolean { } function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean { - if (matchConfig.all !== undefined) { - if (!checkAll(changedFiles, matchConfig.all)) { + if (matchConfig.changedFiles?.all !== undefined) { + if (!checkAll(changedFiles, matchConfig.changedFiles.all)) { return false; } } - if (matchConfig.any !== undefined) { - if (!checkAny(changedFiles, matchConfig.any)) { + if (matchConfig.changedFiles?.any !== undefined) { + if (!checkAny(changedFiles, matchConfig.changedFiles.any)) { return false; } } From 7d175313b7b0067e9ab5e1609feaa43051b9d279 Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sun, 29 Jan 2023 15:09:06 -0500 Subject: [PATCH 11/17] Update the labeler tests --- __tests__/labeler.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/__tests__/labeler.test.ts b/__tests__/labeler.test.ts index 7ec72b51..9c31ac9e 100644 --- a/__tests__/labeler.test.ts +++ b/__tests__/labeler.test.ts @@ -1,4 +1,4 @@ -import {checkGlobs} from '../src/labeler'; +import {checkGlobs, MatchConfig} from '../src/labeler'; import * as core from '@actions/core'; @@ -10,7 +10,10 @@ beforeAll(() => { }); }); -const matchConfig = [{changedFiles: {any: ['*.txt']}}]; +// I have to double cast here as this is what comes from js-yaml looks like which then gets transformed in toMatchConfig +const matchConfig = [ + {'changed-files': [{any: ['*.txt']}]} +] as unknown as MatchConfig[]; describe('checkGlobs', () => { it('returns true when our pattern does match changed files', () => { From b071d82cb8fcca735d59c7ae03230e74b9d19eea Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sun, 29 Jan 2023 15:09:44 -0500 Subject: [PATCH 12/17] Run the build command --- dist/index.js | 196 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 146 insertions(+), 50 deletions(-) diff --git a/dist/index.js b/dist/index.js index 41943604..ca9a2563 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,6 +1,106 @@ /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ +/***/ 8045: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.checkBranch = exports.getBranchName = exports.toBranchMatchConfig = void 0; +const core = __importStar(__nccwpck_require__(2186)); +const github = __importStar(__nccwpck_require__(5438)); +function toBranchMatchConfig(config) { + if (!config['head-branch'] || config['base-branch']) { + return {}; + } + const branchConfig = { + headBranch: config['head-branch'], + baseBranch: config['base-branch'] + }; + if (branchConfig.headBranch) { + const patterns = branchConfig.headBranch; + if (typeof patterns === 'string') { + branchConfig.headBranch = [patterns]; + } + } + if (branchConfig.baseBranch) { + const patterns = branchConfig.baseBranch; + if (typeof patterns === 'string') { + branchConfig.baseBranch = [patterns]; + } + } + return branchConfig; +} +exports.toBranchMatchConfig = toBranchMatchConfig; +function getBranchName(branchBase) { + var _a, _b; + const pullRequest = github.context.payload.pull_request; + if (!pullRequest) { + return undefined; + } + if (branchBase === 'base') { + return (_a = pullRequest.base) === null || _a === void 0 ? void 0 : _a.ref; + } + else { + return (_b = pullRequest.head) === null || _b === void 0 ? void 0 : _b.ref; + } +} +exports.getBranchName = getBranchName; +function checkBranch(glob, branchBase) { + const branchName = getBranchName(branchBase); + if (!branchName) { + core.debug(` no branch name`); + return false; + } + core.debug(` checking "branch" pattern against ${branchName}`); + const matchers = glob.map(g => new RegExp(g)); + for (const matcher of matchers) { + if (matchBranchPattern(matcher, branchName)) { + core.debug(` "branch" patterns matched against ${branchName}`); + return true; + } + } + core.debug(` "branch" patterns did not match against ${branchName}`); + return false; +} +exports.checkBranch = checkBranch; +function matchBranchPattern(matcher, branchName) { + core.debug(` - ${matcher}`); + if (matcher.test(branchName)) { + core.debug(` "branch" pattern matched`); + return true; + } + core.debug(` ${matcher} did not match`); + return false; +} + + +/***/ }), + /***/ 5272: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { @@ -44,6 +144,7 @@ const core = __importStar(__nccwpck_require__(2186)); const github = __importStar(__nccwpck_require__(5438)); const yaml = __importStar(__nccwpck_require__(1917)); const minimatch_1 = __nccwpck_require__(3973); +const branch_1 = __nccwpck_require__(8045); function run() { return __awaiter(this, void 0, void 0, function* () { try { @@ -96,14 +197,6 @@ function getPrNumber() { } return pullRequest.number; } -function getBranchName() { - var _a; - const pullRequest = github.context.payload.pull_request; - if (!pullRequest) { - return undefined; - } - return (_a = pullRequest.head) === null || _a === void 0 ? void 0 : _a.ref; -} function getChangedFiles(client, prNumber) { return __awaiter(this, void 0, void 0, function* () { const listFilesOptions = client.rest.pulls.listFiles.endpoint.merge({ @@ -155,13 +248,42 @@ function getLabelGlobMapFromObject(configObject) { } return labelGlobs; } -function toMatchConfig(config) { - if (typeof config === 'string') { +function toChangedFilesMatchConfig(config) { + if (!config['changed-files']) { + return {}; + } + const changedFiles = config['changed-files']; + // If the value provided is a string or an array of strings then default to `any` matching + if (typeof changedFiles === 'string') { return { - any: [config] + changedFiles: { + any: [changedFiles] + } }; } - return config; + const changedFilesMatchConfig = { + changedFiles: {} + }; + if (Array.isArray(changedFiles)) { + if (changedFiles.every(entry => typeof entry === 'string')) { + changedFilesMatchConfig.changedFiles = { + any: changedFiles + }; + } + else { + // If it is not an array of strings then it should be array of further config options + // so assign them to our `changedFilesMatchConfig` + changedFiles.forEach(element => { + Object.assign(changedFilesMatchConfig.changedFiles, element); + }); + } + } + return changedFilesMatchConfig; +} +function toMatchConfig(config) { + const changedFilesConfig = toChangedFilesMatchConfig(config); + const branchConfig = (0, branch_1.toBranchMatchConfig)(config); + return Object.assign(Object.assign({}, changedFilesConfig), branchConfig); } function printPattern(matcher) { return (matcher.negate ? '!' : '') + matcher.pattern; @@ -215,51 +337,25 @@ function checkAll(changedFiles, globs) { core.debug(` "all" patterns matched all files`); return true; } -function matchBranchPattern(matcher, branchName) { - core.debug(` - ${printPattern(matcher)}`); - if (matcher.match(branchName)) { - core.debug(` "branch" pattern matched`); - return true; - } - core.debug(` ${printPattern(matcher)} did not match`); - return false; -} -function checkBranch(glob) { - const branchName = getBranchName(); - if (!branchName) { - core.debug(` no branch name`); - return false; - } - core.debug(` checking "branch" pattern against ${branchName}`); - if (Array.isArray(glob)) { - const matchers = glob.map(g => new minimatch_1.Minimatch(g)); - for (const matcher of matchers) { - if (matchBranchPattern(matcher, branchName)) { - core.debug(` "branch" patterns matched against ${branchName}`); - return true; - } - } - core.debug(` "branch" patterns did not match against ${branchName}`); - return false; - } - else { - const matcher = new minimatch_1.Minimatch(glob); - return matchBranchPattern(matcher, branchName); - } -} function checkMatch(changedFiles, matchConfig) { - if (matchConfig.all !== undefined) { - if (!checkAll(changedFiles, matchConfig.all)) { + var _a, _b; + if (((_a = matchConfig.changedFiles) === null || _a === void 0 ? void 0 : _a.all) !== undefined) { + if (!checkAll(changedFiles, matchConfig.changedFiles.all)) { return false; } } - if (matchConfig.any !== undefined) { - if (!checkAny(changedFiles, matchConfig.any)) { + if (((_b = matchConfig.changedFiles) === null || _b === void 0 ? void 0 : _b.any) !== undefined) { + if (!checkAny(changedFiles, matchConfig.changedFiles.any)) { return false; } } - if (matchConfig.branch !== undefined) { - if (!checkBranch(matchConfig.branch)) { + if (matchConfig.headBranch !== undefined) { + if (!(0, branch_1.checkBranch)(matchConfig.headBranch, 'head')) { + return false; + } + } + if (matchConfig.baseBranch !== undefined) { + if (!(0, branch_1.checkBranch)(matchConfig.baseBranch, 'base')) { return false; } } From 0eb9d493306a6f70529da98930efdf1364efe317 Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sun, 29 Jan 2023 15:58:23 -0500 Subject: [PATCH 13/17] reverse the conditions of checkMatch --- src/labeler.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/labeler.ts b/src/labeler.ts index 551a2203..34306cbf 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -256,30 +256,30 @@ function checkAll(changedFiles: string[], globs: string[]): boolean { function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean { if (matchConfig.changedFiles?.all !== undefined) { - if (!checkAll(changedFiles, matchConfig.changedFiles.all)) { - return false; + if (checkAll(changedFiles, matchConfig.changedFiles.all)) { + return true; } } if (matchConfig.changedFiles?.any !== undefined) { - if (!checkAny(changedFiles, matchConfig.changedFiles.any)) { - return false; + if (checkAny(changedFiles, matchConfig.changedFiles.any)) { + return true; } } if (matchConfig.headBranch !== undefined) { - if (!checkBranch(matchConfig.headBranch, 'head')) { - return false; + if (checkBranch(matchConfig.headBranch, 'head')) { + return true; } } if (matchConfig.baseBranch !== undefined) { - if (!checkBranch(matchConfig.baseBranch, 'base')) { - return false; + if (checkBranch(matchConfig.baseBranch, 'base')) { + return true; } } - return true; + return false; } async function addLabels( From 09f085373a3a0851facc68652e4bc89ea775346c Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sun, 19 Feb 2023 12:17:15 -0500 Subject: [PATCH 14/17] Fix some typos in the branch checks --- __tests__/branch.test.ts | 4 ++-- __tests__/main.test.ts | 4 ++-- dist/index.js | 20 ++++++++++---------- src/branch.ts | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/__tests__/branch.test.ts b/__tests__/branch.test.ts index a9d60c81..71386b90 100644 --- a/__tests__/branch.test.ts +++ b/__tests__/branch.test.ts @@ -21,8 +21,8 @@ describe('getBranchName', () => { describe('when no branch is specified', () => { it('returns the head branch name', () => { - const result = getBranchName('base'); - expect(result).toEqual('base-branch-name'); + const result = getBranchName(); + expect(result).toEqual('head-branch-name'); }); }); }); diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index b9d56aec..ead8f29c 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -104,7 +104,7 @@ describe('run', () => { expect(removeLabelMock).toHaveBeenCalledTimes(0); }); - it('adds labels based on the branch names that match the glob pattern', async () => { + it('adds labels based on the branch names that match the regexp pattern', async () => { github.context.payload.pull_request!.head = {ref: 'test/testing-time'}; usingLabelerConfigYaml('branches.yml'); await run(); @@ -118,7 +118,7 @@ describe('run', () => { }); }); - it('adds multiple labels based on branch names that match different glob patterns', async () => { + it('adds multiple labels based on branch names that match different regexp patterns', async () => { github.context.payload.pull_request!.head = { ref: 'test/feature/123' }; diff --git a/dist/index.js b/dist/index.js index ca9a2563..4533491d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -34,7 +34,7 @@ exports.checkBranch = exports.getBranchName = exports.toBranchMatchConfig = void const core = __importStar(__nccwpck_require__(2186)); const github = __importStar(__nccwpck_require__(5438)); function toBranchMatchConfig(config) { - if (!config['head-branch'] || config['base-branch']) { + if (!config['head-branch'] && !config['base-branch']) { return {}; } const branchConfig = { @@ -340,26 +340,26 @@ function checkAll(changedFiles, globs) { function checkMatch(changedFiles, matchConfig) { var _a, _b; if (((_a = matchConfig.changedFiles) === null || _a === void 0 ? void 0 : _a.all) !== undefined) { - if (!checkAll(changedFiles, matchConfig.changedFiles.all)) { - return false; + if (checkAll(changedFiles, matchConfig.changedFiles.all)) { + return true; } } if (((_b = matchConfig.changedFiles) === null || _b === void 0 ? void 0 : _b.any) !== undefined) { - if (!checkAny(changedFiles, matchConfig.changedFiles.any)) { - return false; + if (checkAny(changedFiles, matchConfig.changedFiles.any)) { + return true; } } if (matchConfig.headBranch !== undefined) { - if (!(0, branch_1.checkBranch)(matchConfig.headBranch, 'head')) { - return false; + if ((0, branch_1.checkBranch)(matchConfig.headBranch, 'head')) { + return true; } } if (matchConfig.baseBranch !== undefined) { - if (!(0, branch_1.checkBranch)(matchConfig.baseBranch, 'base')) { - return false; + if ((0, branch_1.checkBranch)(matchConfig.baseBranch, 'base')) { + return true; } } - return true; + return false; } function addLabels(client, prNumber, labels) { return __awaiter(this, void 0, void 0, function* () { diff --git a/src/branch.ts b/src/branch.ts index 1804a37d..e4edd524 100644 --- a/src/branch.ts +++ b/src/branch.ts @@ -9,7 +9,7 @@ export interface BranchMatchConfig { type BranchBase = 'base' | 'head'; export function toBranchMatchConfig(config: any): BranchMatchConfig { - if (!config['head-branch'] || config['base-branch']) { + if (!config['head-branch'] && !config['base-branch']) { return {}; } From ed31b27f2ea3fc83492fb42a81332f2dfb4ffb3c Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sun, 19 Feb 2023 16:46:14 -0500 Subject: [PATCH 15/17] Rename some functions and variables to match what they are doing --- __tests__/labeler.test.ts | 3 ++- dist/index.js | 30 +++++++++++++++--------------- src/branch.ts | 7 +++++-- src/labeler.ts | 26 +++++++++++++------------- 4 files changed, 35 insertions(+), 31 deletions(-) diff --git a/__tests__/labeler.test.ts b/__tests__/labeler.test.ts index 9c31ac9e..e320eb7b 100644 --- a/__tests__/labeler.test.ts +++ b/__tests__/labeler.test.ts @@ -10,7 +10,8 @@ beforeAll(() => { }); }); -// I have to double cast here as this is what comes from js-yaml looks like which then gets transformed in toMatchConfig +// I have to double cast here as this is what the output from js-yaml looks like which then gets +// transformed in toMatchConfig const matchConfig = [ {'changed-files': [{any: ['*.txt']}]} ] as unknown as MatchConfig[]; diff --git a/dist/index.js b/dist/index.js index 4533491d..c2c74d56 100644 --- a/dist/index.js +++ b/dist/index.js @@ -70,14 +70,14 @@ function getBranchName(branchBase) { } } exports.getBranchName = getBranchName; -function checkBranch(glob, branchBase) { +function checkBranch(regexps, branchBase) { const branchName = getBranchName(branchBase); if (!branchName) { core.debug(` no branch name`); return false; } core.debug(` checking "branch" pattern against ${branchName}`); - const matchers = glob.map(g => new RegExp(g)); + const matchers = regexps.map(regexp => new RegExp(regexp)); for (const matcher of matchers) { if (matchBranchPattern(matcher, branchName)) { core.debug(` "branch" patterns matched against ${branchName}`); @@ -164,12 +164,12 @@ function run() { }); core.debug(`fetching changed files for pr #${prNumber}`); const changedFiles = yield getChangedFiles(client, prNumber); - const labelGlobs = yield getLabelGlobs(client, configPath); + const labelConfigs = yield getMatchConfigs(client, configPath); const labels = []; const labelsToRemove = []; - for (const [label, globs] of labelGlobs.entries()) { + for (const [label, configs] of labelConfigs.entries()) { core.debug(`processing ${label}`); - if (checkGlobs(changedFiles, globs)) { + if (checkGlobs(changedFiles, configs)) { labels.push(label); } else if (pullRequest.labels.find(l => l.name === label)) { @@ -213,13 +213,13 @@ function getChangedFiles(client, prNumber) { return changedFiles; }); } -function getLabelGlobs(client, configurationPath) { +function getMatchConfigs(client, configurationPath) { return __awaiter(this, void 0, void 0, function* () { const configurationContent = yield fetchContent(client, configurationPath); // loads (hopefully) a `{[label:string]: string | StringOrMatchConfig[]}`, but is `any`: const configObject = yaml.load(configurationContent); // transform `any` => `Map` or throw if yaml is malformed: - return getLabelGlobMapFromObject(configObject); + return getLabelConfigMapFromObject(configObject); }); } function fetchContent(client, repoPath) { @@ -233,7 +233,7 @@ function fetchContent(client, repoPath) { return Buffer.from(response.data.content, response.data.encoding).toString(); }); } -function getLabelGlobMapFromObject(configObject) { +function getLabelConfigMapFromObject(configObject) { const labelGlobs = new Map(); for (const label in configObject) { if (typeof configObject[label] === 'string') { @@ -252,28 +252,28 @@ function toChangedFilesMatchConfig(config) { if (!config['changed-files']) { return {}; } - const changedFiles = config['changed-files']; + const changedFilesConfig = config['changed-files']; // If the value provided is a string or an array of strings then default to `any` matching - if (typeof changedFiles === 'string') { + if (typeof changedFilesConfig === 'string') { return { changedFiles: { - any: [changedFiles] + any: [changedFilesConfig] } }; } const changedFilesMatchConfig = { changedFiles: {} }; - if (Array.isArray(changedFiles)) { - if (changedFiles.every(entry => typeof entry === 'string')) { + if (Array.isArray(changedFilesConfig)) { + if (changedFilesConfig.every(entry => typeof entry === 'string')) { changedFilesMatchConfig.changedFiles = { - any: changedFiles + any: changedFilesConfig }; } else { // If it is not an array of strings then it should be array of further config options // so assign them to our `changedFilesMatchConfig` - changedFiles.forEach(element => { + changedFilesConfig.forEach(element => { Object.assign(changedFilesMatchConfig.changedFiles, element); }); } diff --git a/src/branch.ts b/src/branch.ts index e4edd524..c177d24a 100644 --- a/src/branch.ts +++ b/src/branch.ts @@ -48,7 +48,10 @@ export function getBranchName(branchBase?: BranchBase): string | undefined { } } -export function checkBranch(glob: string[], branchBase?: BranchBase): boolean { +export function checkBranch( + regexps: string[], + branchBase?: BranchBase +): boolean { const branchName = getBranchName(branchBase); if (!branchName) { core.debug(` no branch name`); @@ -56,7 +59,7 @@ export function checkBranch(glob: string[], branchBase?: BranchBase): boolean { } core.debug(` checking "branch" pattern against ${branchName}`); - const matchers = glob.map(g => new RegExp(g)); + const matchers = regexps.map(regexp => new RegExp(regexp)); for (const matcher of matchers) { if (matchBranchPattern(matcher, branchName)) { core.debug(` "branch" patterns matched against ${branchName}`); diff --git a/src/labeler.ts b/src/labeler.ts index 34306cbf..1510d1cd 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -38,16 +38,16 @@ export async function run() { core.debug(`fetching changed files for pr #${prNumber}`); const changedFiles: string[] = await getChangedFiles(client, prNumber); - const labelGlobs: Map = await getLabelGlobs( + const labelConfigs: Map = await getMatchConfigs( client, configPath ); const labels: string[] = []; const labelsToRemove: string[] = []; - for (const [label, globs] of labelGlobs.entries()) { + for (const [label, configs] of labelConfigs.entries()) { core.debug(`processing ${label}`); - if (checkGlobs(changedFiles, globs)) { + if (checkGlobs(changedFiles, configs)) { labels.push(label); } else if (pullRequest.labels.find(l => l.name === label)) { labelsToRemove.push(label); @@ -97,7 +97,7 @@ async function getChangedFiles( return changedFiles; } -async function getLabelGlobs( +async function getMatchConfigs( client: ClientType, configurationPath: string ): Promise> { @@ -110,7 +110,7 @@ async function getLabelGlobs( const configObject: any = yaml.load(configurationContent); // transform `any` => `Map` or throw if yaml is malformed: - return getLabelGlobMapFromObject(configObject); + return getLabelConfigMapFromObject(configObject); } async function fetchContent( @@ -127,7 +127,7 @@ async function fetchContent( return Buffer.from(response.data.content, response.data.encoding).toString(); } -function getLabelGlobMapFromObject( +function getLabelConfigMapFromObject( configObject: any ): Map { const labelGlobs: Map = new Map(); @@ -150,13 +150,13 @@ function toChangedFilesMatchConfig(config: any): ChangedFilesMatchConfig { if (!config['changed-files']) { return {}; } - const changedFiles = config['changed-files']; + const changedFilesConfig = config['changed-files']; // If the value provided is a string or an array of strings then default to `any` matching - if (typeof changedFiles === 'string') { + if (typeof changedFilesConfig === 'string') { return { changedFiles: { - any: [changedFiles] + any: [changedFilesConfig] } }; } @@ -165,15 +165,15 @@ function toChangedFilesMatchConfig(config: any): ChangedFilesMatchConfig { changedFiles: {} }; - if (Array.isArray(changedFiles)) { - if (changedFiles.every(entry => typeof entry === 'string')) { + if (Array.isArray(changedFilesConfig)) { + if (changedFilesConfig.every(entry => typeof entry === 'string')) { changedFilesMatchConfig.changedFiles = { - any: changedFiles + any: changedFilesConfig }; } else { // If it is not an array of strings then it should be array of further config options // so assign them to our `changedFilesMatchConfig` - changedFiles.forEach(element => { + changedFilesConfig.forEach(element => { Object.assign(changedFilesMatchConfig.changedFiles, element); }); } From da83a1845ffbd8c80b474932af6fc993ac6f8aa7 Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Sun, 19 Feb 2023 18:10:19 -0500 Subject: [PATCH 16/17] Make sure that the changed files config values are an array --- dist/index.js | 10 ++++++++-- src/labeler.ts | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/dist/index.js b/dist/index.js index c2c74d56..ef8dc9a1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -273,8 +273,14 @@ function toChangedFilesMatchConfig(config) { else { // If it is not an array of strings then it should be array of further config options // so assign them to our `changedFilesMatchConfig` - changedFilesConfig.forEach(element => { - Object.assign(changedFilesMatchConfig.changedFiles, element); + changedFilesConfig.forEach(config => { + // Make sure that the values that we assign to our match config are an array + Object.entries(config).forEach(([key, value]) => { + const element = { + [key]: Array.isArray(value) ? value : [value] + }; + Object.assign(changedFilesMatchConfig.changedFiles, element); + }); }); } } diff --git a/src/labeler.ts b/src/labeler.ts index 1510d1cd..9d20e65d 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -173,8 +173,14 @@ function toChangedFilesMatchConfig(config: any): ChangedFilesMatchConfig { } else { // If it is not an array of strings then it should be array of further config options // so assign them to our `changedFilesMatchConfig` - changedFilesConfig.forEach(element => { - Object.assign(changedFilesMatchConfig.changedFiles, element); + changedFilesConfig.forEach(config => { + // Make sure that the values that we assign to our match config are an array + Object.entries(config).forEach(([key, value]) => { + const element = { + [key]: Array.isArray(value) ? value : [value] + }; + Object.assign(changedFilesMatchConfig.changedFiles, element); + }); }); } } From 56347d54a15948763d5141fcbf50e50ec2e0206f Mon Sep 17 00:00:00 2001 From: Josh Dales Date: Tue, 21 Feb 2023 08:30:24 -0500 Subject: [PATCH 17/17] Add unit tests for toBranchMatchConfig --- __tests__/branch.test.ts | 70 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/__tests__/branch.test.ts b/__tests__/branch.test.ts index 71386b90..5bd36aa3 100644 --- a/__tests__/branch.test.ts +++ b/__tests__/branch.test.ts @@ -1,4 +1,9 @@ -import {getBranchName, checkBranch} from '../src/branch'; +import { + getBranchName, + checkBranch, + toBranchMatchConfig, + BranchMatchConfig +} from '../src/branch'; import * as github from '@actions/github'; jest.mock('@actions/core'); @@ -85,3 +90,66 @@ describe('checkBranch', () => { }); }); }); + +describe('toBranchMatchConfig', () => { + describe('when there are no branch keys in the config', () => { + const config = {'changed-files': [{any: ['testing']}]}; + it('returns an empty object', () => { + const result = toBranchMatchConfig(config); + expect(result).toMatchObject({}); + }); + }); + + describe('when the config contains a head-branch option', () => { + const config = {'head-branch': ['testing']}; + it('sets headBranch in the matchConfig', () => { + const result = toBranchMatchConfig(config); + expect(result).toMatchObject({ + headBranch: ['testing'] + }); + }); + + describe('and the matching option is a string', () => { + const stringConfig = {'head-branch': 'testing'}; + + it('sets headBranch in the matchConfig', () => { + const result = toBranchMatchConfig(stringConfig); + expect(result).toMatchObject({ + headBranch: ['testing'] + }); + }); + }); + }); + + describe('when the config contains a base-branch option', () => { + const config = {'base-branch': ['testing']}; + it('sets headBranch in the matchConfig', () => { + const result = toBranchMatchConfig(config); + expect(result).toMatchObject({ + baseBranch: ['testing'] + }); + }); + + describe('and the matching option is a string', () => { + const stringConfig = {'base-branch': 'testing'}; + + it('sets headBranch in the matchConfig', () => { + const result = toBranchMatchConfig(stringConfig); + expect(result).toMatchObject({ + baseBranch: ['testing'] + }); + }); + }); + }); + + describe('when the config contains both a base-branch and head-branch option', () => { + const config = {'base-branch': ['testing'], 'head-branch': ['testing']}; + it('sets headBranch in the matchConfig', () => { + const result = toBranchMatchConfig(config); + expect(result).toMatchObject({ + baseBranch: ['testing'], + headBranch: ['testing'] + }); + }); + }); +});