Skip to content

Commit 919561f

Browse files
committed
Make the exit type configurable
1 parent f2470dc commit 919561f

File tree

3 files changed

+104
-3
lines changed

3 files changed

+104
-3
lines changed

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,14 @@ To force an API call, set the `GITHUB_TOKEN` environment variable like so:
7474
count: 2
7575
labels: "community-reviewed, team-reviewed, codeowner-reviewed"
7676
```
77+
78+
### Exit with a neutral result rather than failure
79+
80+
```yaml
81+
- uses: mheap/github-action-required-labels@v1
82+
with:
83+
mode: minimum
84+
count: 2
85+
labels: "community-reviewed, team-reviewed, codeowner-reviewed"
86+
exit_type: neutral # Can be: failure, neutral or success
87+
```

index.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Toolkit.run(async (tools) => {
99
.map((l) => l.trim())
1010
.filter((r) => r);
1111

12+
const exitType = tools.inputs.exit_type || "failure";
13+
1214
// Validate inputs
1315
if (tools.inputs.count === "") {
1416
tools.exit.failure(`[count] input is not provided`);
@@ -28,6 +30,16 @@ Toolkit.run(async (tools) => {
2830
return;
2931
}
3032

33+
const allowedExitCodes = ["success", "neutral", "failure"];
34+
if (!allowedExitCodes.includes(exitType)) {
35+
tools.exit.failure(
36+
`Unknown exit_code input [${exitType}]. Must be one of: ${allowedExitCodes.join(
37+
", "
38+
)}`
39+
);
40+
return;
41+
}
42+
3143
// If a token is provided, call the API, otherwise read the event.json file
3244
let labels;
3345
if (process.env.GITHUB_TOKEN) {
@@ -43,7 +55,7 @@ Toolkit.run(async (tools) => {
4355
let intersection = allowedLabels.filter((x) => appliedLabels.includes(x));
4456

4557
if (mode === "exactly" && intersection.length !== count) {
46-
tools.exit.failure(
58+
tools.exit[exitType](
4759
`Label error. Requires exactly ${count} of: ${allowedLabels.join(
4860
", "
4961
)}. Found: ${appliedLabels.join(", ")}`
@@ -52,7 +64,7 @@ Toolkit.run(async (tools) => {
5264
}
5365

5466
if (mode === "minimum" && intersection.length < count) {
55-
tools.exit.failure(
67+
tools.exit[exitType](
5668
`Label error. Requires at least ${count} of: ${allowedLabels.join(
5769
", "
5870
)}. Found: ${appliedLabels.join(", ")}`
@@ -61,7 +73,7 @@ Toolkit.run(async (tools) => {
6173
}
6274

6375
if (mode === "maximum" && intersection.length > count) {
64-
tools.exit.failure(
76+
tools.exit[exitType](
6577
`Label error. Requires at most ${count} of: ${allowedLabels.join(
6678
", "
6779
)}. Found: ${appliedLabels.join(", ")}`

index.test.js

+78
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ describe("Required Labels", () => {
3535
};
3636
tools.exit.success = jest.fn();
3737
tools.exit.failure = jest.fn();
38+
tools.exit.neutral = jest.fn();
3839
});
3940

4041
afterEach(() => {
@@ -170,6 +171,21 @@ describe("Required Labels", () => {
170171
"Unknown mode input [bananas]. Must be one of: exactly, minimum, maximum"
171172
);
172173
});
174+
175+
it("unknown exit_code", () => {
176+
restoreTest = mockPr(tools, [], {
177+
INPUT_MODE: "exactly",
178+
INPUT_LABELS: "enhancement,bug",
179+
INPUT_COUNT: "1",
180+
INPUT_EXIT_TYPE: "other",
181+
});
182+
183+
action(tools);
184+
expect(tools.exit.failure).toBeCalledTimes(1);
185+
expect(tools.exit.failure).toBeCalledWith(
186+
"Unknown exit_code input [other]. Must be one of: success, neutral, failure"
187+
);
188+
});
173189
});
174190

175191
describe("data integrity", () => {
@@ -210,6 +226,68 @@ describe("Required Labels", () => {
210226
expect(tools.exit.success).toBeCalledWith("Complete");
211227
});
212228
});
229+
230+
describe("configurable exit code", () => {
231+
it("defaults to failure", () => {
232+
// Create a new Toolkit instance
233+
restoreTest = mockPr(tools, ["enhancement", "bug"], {
234+
INPUT_LABELS: "enhancement,bug",
235+
INPUT_MODE: "exactly",
236+
INPUT_COUNT: "1",
237+
});
238+
239+
action(tools);
240+
expect(tools.exit.failure).toBeCalledTimes(1);
241+
expect(tools.exit.failure).toBeCalledWith(
242+
"Label error. Requires exactly 1 of: enhancement, bug. Found: enhancement, bug"
243+
);
244+
});
245+
246+
it("explicitly uses failure", () => {
247+
restoreTest = mockPr(tools, ["enhancement", "bug"], {
248+
INPUT_LABELS: "enhancement,bug",
249+
INPUT_MODE: "exactly",
250+
INPUT_COUNT: "1",
251+
INPUT_EXIT_TYPE: "failure",
252+
});
253+
254+
action(tools);
255+
expect(tools.exit.failure).toBeCalledTimes(1);
256+
expect(tools.exit.failure).toBeCalledWith(
257+
"Label error. Requires exactly 1 of: enhancement, bug. Found: enhancement, bug"
258+
);
259+
});
260+
261+
it("explicitly uses success", () => {
262+
restoreTest = mockPr(tools, ["enhancement", "bug"], {
263+
INPUT_LABELS: "enhancement,bug",
264+
INPUT_MODE: "exactly",
265+
INPUT_COUNT: "1",
266+
INPUT_EXIT_TYPE: "success",
267+
});
268+
269+
action(tools);
270+
expect(tools.exit.success).toBeCalledTimes(1);
271+
expect(tools.exit.success).toBeCalledWith(
272+
"Label error. Requires exactly 1 of: enhancement, bug. Found: enhancement, bug"
273+
);
274+
});
275+
276+
it("explicitly uses neutral", () => {
277+
restoreTest = mockPr(tools, ["enhancement", "bug"], {
278+
INPUT_LABELS: "enhancement,bug",
279+
INPUT_MODE: "exactly",
280+
INPUT_COUNT: "1",
281+
INPUT_EXIT_TYPE: "neutral",
282+
});
283+
284+
action(tools);
285+
expect(tools.exit.neutral).toBeCalledTimes(1);
286+
expect(tools.exit.neutral).toBeCalledWith(
287+
"Label error. Requires exactly 1 of: enhancement, bug. Found: enhancement, bug"
288+
);
289+
});
290+
});
213291
});
214292

215293
function mockPr(tools, labels, env) {

0 commit comments

Comments
 (0)