Skip to content

Commit ee6d39f

Browse files
authored
feat: support needs specified inside rules (#1743)
* feat: support needs specified inside rules Closes #1602 * refactor: simplify rule needs with optional chaining
1 parent f277c93 commit ee6d39f

File tree

4 files changed

+65
-3
lines changed

4 files changed

+65
-3
lines changed

src/job.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export type JobRule = {
8181
exists?: string[];
8282
allow_failure?: boolean;
8383
variables?: {[name: string]: string};
84+
needs?: any[];
8485
};
8586

8687
export class Job {
@@ -205,6 +206,9 @@ export class Job {
205206
this.when = ruleResult.when;
206207
this.allowFailure = ruleResult.allowFailure;
207208
ruleVariables = ruleResult.variables;
209+
if (ruleResult.needs) {
210+
this.jobData["needs"] = ruleResult.needs;
211+
}
208212
this._variables = {...this._variables, ...ruleVariables, ...argvVariables};
209213
}
210214

src/utils.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import "./global.js";
22
import {RE2JS} from "re2js";
33
import chalk from "chalk-template";
4-
import {Job, JobRule} from "./job.js";
4+
import {Job, JobRule, Need} from "./job.js";
5+
import {needsComplex} from "./data-expander.js";
56
import fs from "fs-extra";
67
import checksum from "checksum";
78
import base64url from "base64url";
@@ -188,13 +189,14 @@ export class Utils {
188189
return envMatchedVariables;
189190
}
190191

191-
static getRulesResult (opt: RuleResultOpt, gitData: GitData, jobWhen: string = "on_success", jobAllowFailure: boolean | {exit_codes: number | number[]} = false): {when: string; allowFailure: boolean | {exit_codes: number | number[]}; variables?: {[name: string]: string}} {
192+
static getRulesResult (opt: RuleResultOpt, gitData: GitData, jobWhen: string = "on_success", jobAllowFailure: boolean | {exit_codes: number | number[]} = false): {when: string; allowFailure: boolean | {exit_codes: number | number[]}; variables?: {[name: string]: string}; needs?: Need[]} {
192193
let when = "never";
193194
const {evaluateRuleChanges} = opt.argv;
194195

195196
// optional manual jobs allowFailure defaults to true https://docs.gitlab.com/ee/ci/jobs/job_control.html#types-of-manual-jobs
196197
let allowFailure = jobWhen === "manual" ? true : jobAllowFailure;
197198
let ruleVariable: {[name: string]: string} | undefined;
199+
let ruleNeeds: Need[] | undefined;
198200

199201
for (const rule of opt.rules) {
200202
if (!Utils.evaluateRuleIf(rule.if, opt.variables)) continue;
@@ -204,11 +206,12 @@ export class Utils {
204206
when = rule.when ? rule.when : jobWhen;
205207
allowFailure = rule.allow_failure ?? allowFailure;
206208
ruleVariable = rule.variables;
209+
ruleNeeds = rule.needs?.map((n: any) => needsComplex(n));
207210

208211
break; // Early return, will not evaluate the remaining rules
209212
}
210213

211-
return {when, allowFailure, variables: ruleVariable};
214+
return {when, allowFailure, variables: ruleVariable, needs: ruleNeeds};
212215
}
213216

214217
static evaluateRuleIf (ruleIf: string | undefined, envs: {[key: string]: string}): boolean {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
stages:
3+
- build
4+
- test
5+
6+
build-dev:
7+
stage: build
8+
script: echo "build-dev"
9+
10+
build-production:
11+
stage: build
12+
script: echo "build-production"
13+
14+
test-job:
15+
stage: test
16+
script: echo "test-job"
17+
needs:
18+
- build-dev
19+
rules:
20+
- if: $CI_COMMIT_BRANCH == "main"
21+
needs:
22+
- build-production
23+
- when: on_success
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import {WriteStreamsMock} from "../../../src/write-streams.js";
2+
import {handler} from "../../../src/handler.js";
3+
import {initSpawnSpy} from "../../mocks/utils.mock.js";
4+
import {WhenStatics} from "../../mocks/when-statics.js";
5+
6+
beforeAll(() => {
7+
initSpawnSpy(WhenStatics.all);
8+
});
9+
10+
test("rules-needs - default branch uses rule needs", async () => {
11+
const writeStreams = new WriteStreamsMock();
12+
await handler({
13+
cwd: "tests/test-cases/rules-needs",
14+
variable: ["CI_COMMIT_BRANCH=main"],
15+
}, writeStreams);
16+
17+
const output = writeStreams.stdoutLines.join("\n");
18+
expect(output).toContain("test-job");
19+
expect(output).not.toContain("build-dev started");
20+
});
21+
22+
test("rules-needs - non-default branch uses job-level needs", async () => {
23+
const writeStreams = new WriteStreamsMock();
24+
await handler({
25+
cwd: "tests/test-cases/rules-needs",
26+
variable: ["CI_COMMIT_BRANCH=feature"],
27+
}, writeStreams);
28+
29+
const output = writeStreams.stdoutLines.join("\n");
30+
expect(output).toContain("test-job");
31+
expect(output).toContain("build-dev");
32+
});

0 commit comments

Comments
 (0)