From 30bf4429701fdce10a093db2e4631933c159cefd Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Tue, 21 Jun 2022 14:23:42 +0100 Subject: [PATCH] Make the exit type configurable --- README.md | 11 ++++++++ index.js | 18 ++++++++++-- index.test.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 28d322c..c5334d2 100644 --- a/README.md +++ b/README.md @@ -74,3 +74,14 @@ To force an API call, set the `GITHUB_TOKEN` environment variable like so: count: 2 labels: "community-reviewed, team-reviewed, codeowner-reviewed" ``` + +### Exit with a neutral result rather than failure + +```yaml +- uses: mheap/github-action-required-labels@v1 + with: + mode: minimum + count: 2 + labels: "community-reviewed, team-reviewed, codeowner-reviewed" + exit_type: neutral # Can be: failure, neutral or success +``` diff --git a/index.js b/index.js index 8d55782..bed4bd8 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,8 @@ Toolkit.run(async (tools) => { .map((l) => l.trim()) .filter((r) => r); + const exitType = tools.inputs.exit_type || "failure"; + // Validate inputs if (tools.inputs.count === "") { tools.exit.failure(`[count] input is not provided`); @@ -28,6 +30,16 @@ Toolkit.run(async (tools) => { return; } + const allowedExitCodes = ["success", "neutral", "failure"]; + if (!allowedExitCodes.includes(exitType)) { + tools.exit.failure( + `Unknown exit_code input [${exitType}]. Must be one of: ${allowedExitCodes.join( + ", " + )}` + ); + return; + } + // If a token is provided, call the API, otherwise read the event.json file let labels; if (process.env.GITHUB_TOKEN) { @@ -43,7 +55,7 @@ Toolkit.run(async (tools) => { let intersection = allowedLabels.filter((x) => appliedLabels.includes(x)); if (mode === "exactly" && intersection.length !== count) { - tools.exit.failure( + tools.exit[exitType]( `Label error. Requires exactly ${count} of: ${allowedLabels.join( ", " )}. Found: ${appliedLabels.join(", ")}` @@ -52,7 +64,7 @@ Toolkit.run(async (tools) => { } if (mode === "minimum" && intersection.length < count) { - tools.exit.failure( + tools.exit[exitType]( `Label error. Requires at least ${count} of: ${allowedLabels.join( ", " )}. Found: ${appliedLabels.join(", ")}` @@ -61,7 +73,7 @@ Toolkit.run(async (tools) => { } if (mode === "maximum" && intersection.length > count) { - tools.exit.failure( + tools.exit[exitType]( `Label error. Requires at most ${count} of: ${allowedLabels.join( ", " )}. Found: ${appliedLabels.join(", ")}` diff --git a/index.test.js b/index.test.js index fbd6300..ef4122d 100644 --- a/index.test.js +++ b/index.test.js @@ -35,6 +35,7 @@ describe("Required Labels", () => { }; tools.exit.success = jest.fn(); tools.exit.failure = jest.fn(); + tools.exit.neutral = jest.fn(); }); afterEach(() => { @@ -170,6 +171,21 @@ describe("Required Labels", () => { "Unknown mode input [bananas]. Must be one of: exactly, minimum, maximum" ); }); + + it("unknown exit_code", () => { + restoreTest = mockPr(tools, [], { + INPUT_MODE: "exactly", + INPUT_LABELS: "enhancement,bug", + INPUT_COUNT: "1", + INPUT_EXIT_TYPE: "other", + }); + + action(tools); + expect(tools.exit.failure).toBeCalledTimes(1); + expect(tools.exit.failure).toBeCalledWith( + "Unknown exit_code input [other]. Must be one of: success, neutral, failure" + ); + }); }); describe("data integrity", () => { @@ -210,6 +226,68 @@ describe("Required Labels", () => { expect(tools.exit.success).toBeCalledWith("Complete"); }); }); + + describe("configurable exit code", () => { + it("defaults to failure", () => { + // Create a new Toolkit instance + restoreTest = mockPr(tools, ["enhancement", "bug"], { + INPUT_LABELS: "enhancement,bug", + INPUT_MODE: "exactly", + INPUT_COUNT: "1", + }); + + action(tools); + expect(tools.exit.failure).toBeCalledTimes(1); + expect(tools.exit.failure).toBeCalledWith( + "Label error. Requires exactly 1 of: enhancement, bug. Found: enhancement, bug" + ); + }); + + it("explicitly uses failure", () => { + restoreTest = mockPr(tools, ["enhancement", "bug"], { + INPUT_LABELS: "enhancement,bug", + INPUT_MODE: "exactly", + INPUT_COUNT: "1", + INPUT_EXIT_TYPE: "failure", + }); + + action(tools); + expect(tools.exit.failure).toBeCalledTimes(1); + expect(tools.exit.failure).toBeCalledWith( + "Label error. Requires exactly 1 of: enhancement, bug. Found: enhancement, bug" + ); + }); + + it("explicitly uses success", () => { + restoreTest = mockPr(tools, ["enhancement", "bug"], { + INPUT_LABELS: "enhancement,bug", + INPUT_MODE: "exactly", + INPUT_COUNT: "1", + INPUT_EXIT_TYPE: "success", + }); + + action(tools); + expect(tools.exit.success).toBeCalledTimes(1); + expect(tools.exit.success).toBeCalledWith( + "Label error. Requires exactly 1 of: enhancement, bug. Found: enhancement, bug" + ); + }); + + it("explicitly uses neutral", () => { + restoreTest = mockPr(tools, ["enhancement", "bug"], { + INPUT_LABELS: "enhancement,bug", + INPUT_MODE: "exactly", + INPUT_COUNT: "1", + INPUT_EXIT_TYPE: "neutral", + }); + + action(tools); + expect(tools.exit.neutral).toBeCalledTimes(1); + expect(tools.exit.neutral).toBeCalledWith( + "Label error. Requires exactly 1 of: enhancement, bug. Found: enhancement, bug" + ); + }); + }); }); function mockPr(tools, labels, env) {