From bf4aa4086aac49f90934b50eaf00162dd112ac75 Mon Sep 17 00:00:00 2001 From: Panaetius Date: Fri, 17 Jan 2020 08:09:17 +0100 Subject: [PATCH] feat(app): Adds negative rules --- src/LabelMatcher.test.ts | 52 ++++++++++++++++++++++++++++++++++++++++ src/LabelMatcher.ts | 37 +++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/LabelMatcher.test.ts b/src/LabelMatcher.test.ts index 7eba543..09ffa72 100644 --- a/src/LabelMatcher.test.ts +++ b/src/LabelMatcher.test.ts @@ -18,6 +18,16 @@ describe("LabelMatcher", () => { expect(matcher.contains({values: ["one", "two", "three"]})).toBeFalsy(); expect(matcher.contains({values: ["one", "two", "three", "test"]})).toBeTruthy(); }); + it("LabelMatcher.not should not return match if any of Github labels matches provided config labels", () => { + const labels: IGithubLabel[] = [ + {name: "bug"}, + {name: "feat"}, + {name: "test"} + ]; + const matcher = new LabelMatcher(labels); + expect(matcher.not({not: ["one", "two", "three"]})).toBeTruthy(); + expect(matcher.not({not: ["one", "two", "three", "test"]})).toBeFalsy(); + }); it("LabelMatcher.startsWith should return match if any of Github labels matches provided config labels", () => { const labels: IGithubLabel[] = [ {name: "bug"}, @@ -39,6 +49,27 @@ describe("LabelMatcher", () => { expect(matcher.startsWith({startsWith: x.input})).toBe(x.result); }); }); + it("LabelMatcher.doesntStartWith shouldn't return match if any of Github labels matches provided config labels", () => { + const labels: IGithubLabel[] = [ + {name: "bug"}, + {name: "feat"}, + {name: "test"} + ]; + const matcher = new LabelMatcher(labels); + const tests = [ + {input: ["one", "two", "three"], result: true}, + {input: ["one", "two", "three", "b"], result: false}, + {input: ["one", "two", "three", "bu"], result: false}, + {input: ["one", "two", "three", "bug"], result: false}, + {input: ["one", "two", "t", "bug"], result: false}, + {input: ["one", "two", "te", "bug"], result: false}, + {input: ["one", "two", "tes", "bug"], result: false}, + {input: ["one", "two", "test", "bug"], result: false} + ]; + tests.forEach((x) => { + expect(matcher.doesntStartWith({doesntStartWith: x.input})).toBe(x.result); + }); + }); it("LabelMatcher.endsWith should return match if any of Github labels matches provided config labels", () => { const labels: IGithubLabel[] = [ {name: "bug"}, @@ -58,6 +89,25 @@ describe("LabelMatcher", () => { expect(matcher.endsWith({endsWith: x.input})).toBe(x.result); }); }); + it("LabelMatcher.doesntEndWith shouldn't return match if any of Github labels matches provided config labels", () => { + const labels: IGithubLabel[] = [ + {name: "bug"}, + {name: "feat"}, + {name: "test"} + ]; + const matcher = new LabelMatcher(labels); + const tests = [ + {input: ["one", "two", "three"], result: true}, + {input: ["one", "two", "three", "b"], result: true}, + {input: ["one", "two", "three", "bu"], result: true}, + {input: ["one", "two", "three", "bug"], result: false}, + {input: ["one", "two", "t", "bu"], result: false}, + {input: ["one", "two", "st", "bu"], result: false} + ]; + tests.forEach((x) => { + expect(matcher.doesntEndWith({doesntEndWith: x.input})).toBe(x.result); + }); + }); describe("LabelMatcher.matches should have match", () => { it("should return true if config is completely empty", () => { const matcher = new LabelMatcher([]); @@ -76,6 +126,8 @@ describe("LabelMatcher", () => { expect(matcher.matches({version: "2", invalidStatus: "failed", labelRule: {startsWith: ["b"], values: ["feat"]}})).toBeFalsy(); expect(matcher.matches({version: "2", invalidStatus: "failed", labelRule: {startsWith: ["b"], endsWith: ["g"], values: ["feat"]}})).toBeFalsy(); expect(matcher.matches({version: "2", invalidStatus: "failed", labelRule: {startsWith: ["b"], endsWith: ["g"], values: ["bug"]}})).toBeTruthy(); + expect(matcher.matches({version: "2", invalidStatus: "failed", labelRule: {doesntStartWith: ["b"], doesntEndWith: ["g"], not: ["feat"]}})).toBeFalsy(); + expect(matcher.matches({version: "2", invalidStatus: "failed", labelRule: {doesntStartWith: ["a"], doesntEndWith: ["b"], not: ["feat"]}})).toBeTruthy(); }); }); diff --git a/src/LabelMatcher.ts b/src/LabelMatcher.ts index 728c75d..639c991 100644 --- a/src/LabelMatcher.ts +++ b/src/LabelMatcher.ts @@ -1,7 +1,8 @@ export interface IGithubConfig { version: string; invalidStatus: "failed" | "pending"; - labelRule: ILabelEndsWithRule | ILabelStartsWithRule | ILabelEqualsRule | {}; + labelRule: ILabelEndsWithRule | ILabelStartsWithRule | ILabelEqualsRule | + ILabelDoesntEndWithRule | ILabelDoesntStartWithRule | ILabelNotRule | {}; } export interface IGithubLabel { @@ -25,6 +26,18 @@ export interface ILabelStartsWithRule { startsWith: string[]; } +export interface ILabelNotRule { + not: string[]; +} + +export interface ILabelDoesntStartWithRule { + doesntStartWith: string[]; +} + +export interface ILabelDoesntEndWithRule { + doesntEndWith: string[]; +} + export class LabelMatcher { constructor(private labels: IGithubLabel[]) {} @@ -44,6 +57,22 @@ export class LabelMatcher { }); } + public not(config: ILabelNotRule): boolean { + return !this.labels.some((x) => config.not.includes(x.name)); + } + + public doesntStartWith(config: ILabelDoesntStartWithRule): boolean { + return !this.labels.some((x) => { + return config.doesntStartWith.some((ruleLabel) => x.name.startsWith(ruleLabel)); + }); + } + + public doesntEndWith(config: ILabelDoesntEndWithRule): boolean { + return !this.labels.some((x) => { + return config.doesntEndWith.some((ruleLabel) => x.name.endsWith(ruleLabel)); + }); + } + public matches(config: IGithubConfig): boolean { return Object.keys(config.labelRule).every((x) => { switch (x) { @@ -53,6 +82,12 @@ export class LabelMatcher { return this.startsWith(config.labelRule as ILabelStartsWithRule); case "values": return this.contains(config.labelRule as ILabelEqualsRule); + case "not": + return this.not(config.labelRule as ILabelNotRule); + case "doesntStartWith": + return this.doesntStartWith(config.labelRule as ILabelDoesntStartWithRule); + case "doesntEndWith": + return this.doesntEndWith(config.labelRule as ILabelDoesntEndWithRule); default: throw new Error(`rule ${x} not supported`); }