Skip to content

Commit 926cb3e

Browse files
bcouetilCopilot
andcommitted
feat: add environment column to --list and --list-csv (#1837)
Display the environment name in --list and --list-csv outputs, placed just before the needs column. Jobs without an environment show an empty value. The list-environment test expects workflow:rules:variables resolution (PR #1833) and will fail until that feature is merged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f67605f commit 926cb3e

5 files changed

Lines changed: 102 additions & 22 deletions

File tree

src/commander.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ export class Commander {
213213
let descriptionPadEnd = 11;
214214
jobs.forEach(j => descriptionPadEnd = Math.max(j.description.length, descriptionPadEnd));
215215

216+
let environmentPadEnd = 11;
217+
jobs.forEach(j => environmentPadEnd = Math.max((j.environment?.name ?? "").length, environmentPadEnd));
218+
216219
const jobNamePad = parser.jobNamePad;
217220

218221
if (!listAll) {
@@ -221,15 +224,16 @@ export class Commander {
221224

222225
writeStreams.stdout(chalk`{grey ${"name".padEnd(jobNamePad)} ${"description".padEnd(descriptionPadEnd)}} `);
223226
writeStreams.stdout(chalk`{grey ${"stage".padEnd(stagePadEnd)} ${"when".padEnd(whenPadEnd)}} `);
224-
writeStreams.stdout(chalk`{grey allow_failure needs}\n`);
227+
writeStreams.stdout(chalk`{grey allow_failure ${"environment".padEnd(environmentPadEnd)} needs}\n`);
225228

226229
const renderLine = (job: Job) => {
227230
const needs = Commander.formatNeeds(job);
228231
const allowFailure = Commander.formatAllowFailure(job.allowFailure);
232+
const environment = job.environment?.name ?? "";
229233
let jobLine = chalk`{blueBright ${job.name.padEnd(jobNamePad)}} ${job.description.padEnd(descriptionPadEnd)} `;
230-
jobLine += chalk`{yellow ${job.stage.padEnd(stagePadEnd)}} ${job.when.padEnd(whenPadEnd)} ${allowFailure.padEnd(11)}`;
234+
jobLine += chalk`{yellow ${job.stage.padEnd(stagePadEnd)}} ${job.when.padEnd(whenPadEnd)} ${allowFailure.padEnd(13)} ${environment.padEnd(environmentPadEnd)}`;
231235
if (needs !== null) {
232-
jobLine += chalk` [{blueBright ${needs}}]`;
236+
jobLine += chalk` [{blueBright ${needs}}]`;
233237
}
234238
writeStreams.stdout(`${jobLine}\n`);
235239
};
@@ -267,13 +271,14 @@ export class Commander {
267271
jobs = jobs.filter(j => j.when !== "never");
268272
}
269273

270-
writeStreams.stdout("name;stage;when;allowFailure;needs\n");
274+
writeStreams.stdout("name;stage;when;allowFailure;environment;needs\n");
271275

272276
jobs.forEach((job) => {
273277
const needs = Commander.formatNeeds(job);
274278
const needsStr = needs === null ? "" : `[${needs.join(",")}]`;
275279
const allowFailure = Commander.formatAllowFailure(job.allowFailure);
276-
const row = [job.name, job.stage, job.when, allowFailure, needsStr].join(";");
280+
const environment = job.environment?.name ?? "";
281+
const row = [job.name, job.stage, job.when, allowFailure, environment, needsStr].join(";");
277282
writeStreams.stdout(`${row}\n`);
278283
});
279284
}

tests/test-cases/list-case/integration.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ test.concurrent("list-case --list", async () => {
1717
}, writeStreams);
1818

1919
const expected = [
20-
chalk`{grey name description} {grey stage when } {grey allow_failure needs}`,
21-
chalk`{blueBright test-job } Run Tests {yellow test } on_success false `,
22-
chalk`{blueBright build-job} {yellow build} on_success true [{blueBright test-job}]`,
20+
chalk`{grey ${"name".padEnd(9)} ${"description".padEnd(11)}} {grey ${"stage".padEnd(5)} ${"when".padEnd(10)}} {grey allow_failure ${"environment".padEnd(11)} needs}`,
21+
chalk`{blueBright ${"test-job".padEnd(9)}} ${"Run Tests".padEnd(11)} {yellow ${"test".padEnd(5)}} ${"on_success".padEnd(10)} ${"false".padEnd(13)} ${"".padEnd(11)}`,
22+
chalk`{blueBright ${"build-job".padEnd(9)}} ${"".padEnd(11)} {yellow ${"build".padEnd(5)}} ${"on_success".padEnd(10)} ${"true".padEnd(13)} ${"".padEnd(11)} [{blueBright test-job}]`,
2323
];
2424
expect(writeStreams.stdoutLines).toEqual(expect.arrayContaining(expected));
2525
});

tests/test-cases/list-csv-case/integration.test.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ test.concurrent("list-csv-case --list-csv", async () => {
1717
}, writeStreams);
1818

1919
const expected = [
20-
"name;stage;when;allowFailure;needs",
21-
"test-job;test;on_success;false;",
22-
"build-job;build;on_success;true;[test-job]",
23-
"exit-codes-job;build;on_success;[42,137];[]",
24-
"deploy-job;deploy;on_success;[1];",
20+
"name;stage;when;allowFailure;environment;needs",
21+
"test-job;test;on_success;false;;",
22+
"build-job;build;on_success;true;;[test-job]",
23+
"exit-codes-job;build;on_success;[42,137];;[]",
24+
"deploy-job;deploy;on_success;[1];;",
2525
];
2626
expect(writeStreams.stdoutLines).toEqual(expect.arrayContaining(expected));
2727
});
@@ -37,9 +37,9 @@ test.concurrent("list-csv-case --list-csv colon should add process descriptors w
3737
}, writeStreams);
3838

3939
const expected = [
40-
"name;stage;when;allowFailure;needs",
41-
"test-job;test;on_success;false;",
42-
"build-job;build;on_success;true;[test-job]",
40+
"name;stage;when;allowFailure;environment;needs",
41+
"test-job;test;on_success;false;;",
42+
"build-job;build;on_success;true;;[test-job]",
4343
];
4444
expect(writeStreams.stdoutLines).toEqual(expect.arrayContaining(expected));
4545
});
@@ -53,13 +53,13 @@ test.concurrent("list-csv-case --list", async () => {
5353
stateDir: ".gitlab-ci-local-list-csv-case-list",
5454
}, writeStreams);
5555

56-
// jobNamePad=14 (exit-codes-job), descriptionPadEnd=11, stagePadEnd=6 (deploy), whenPadEnd=10
56+
// jobNamePad=14 (exit-codes-job), descriptionPadEnd=11, stagePadEnd=6 (deploy), whenPadEnd=10, environmentPadEnd=11
5757
const expected = [
58-
chalk`{grey ${"name".padEnd(14)} ${"description".padEnd(11)}} {grey ${"stage".padEnd(6)} ${"when".padEnd(10)}} {grey allow_failure needs}`,
59-
chalk`{blueBright ${"test-job".padEnd(14)}} ${"Run Tests".padEnd(11)} {yellow ${"test".padEnd(6)}} ${"on_success".padEnd(10)} ${"false".padEnd(11)}`,
60-
chalk`{blueBright ${"build-job".padEnd(14)}} ${"".padEnd(11)} {yellow ${"build".padEnd(6)}} ${"on_success".padEnd(10)} ${"true".padEnd(11)} [{blueBright test-job}]`,
61-
chalk`{blueBright ${"exit-codes-job".padEnd(14)}} ${"".padEnd(11)} {yellow ${"build".padEnd(6)}} ${"on_success".padEnd(10)} ${"[42,137]".padEnd(11)} [{blueBright }]`,
62-
chalk`{blueBright ${"deploy-job".padEnd(14)}} ${"".padEnd(11)} {yellow ${"deploy".padEnd(6)}} ${"on_success".padEnd(10)} ${"[1]".padEnd(11)}`,
58+
chalk`{grey ${"name".padEnd(14)} ${"description".padEnd(11)}} {grey ${"stage".padEnd(6)} ${"when".padEnd(10)}} {grey allow_failure ${"environment".padEnd(11)} needs}`,
59+
chalk`{blueBright ${"test-job".padEnd(14)}} ${"Run Tests".padEnd(11)} {yellow ${"test".padEnd(6)}} ${"on_success".padEnd(10)} ${"false".padEnd(13)} ${"".padEnd(11)}`,
60+
chalk`{blueBright ${"build-job".padEnd(14)}} ${"".padEnd(11)} {yellow ${"build".padEnd(6)}} ${"on_success".padEnd(10)} ${"true".padEnd(13)} ${"".padEnd(11)} [{blueBright test-job}]`,
61+
chalk`{blueBright ${"exit-codes-job".padEnd(14)}} ${"".padEnd(11)} {yellow ${"build".padEnd(6)}} ${"on_success".padEnd(10)} ${"[42,137]".padEnd(13)} ${"".padEnd(11)} [{blueBright }]`,
62+
chalk`{blueBright ${"deploy-job".padEnd(14)}} ${"".padEnd(11)} {yellow ${"deploy".padEnd(6)}} ${"on_success".padEnd(10)} ${"[1]".padEnd(13)} ${"".padEnd(11)}`,
6363
];
6464
expect(writeStreams.stdoutLines).toEqual(expect.arrayContaining(expected));
6565
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
workflow:
3+
rules:
4+
- if: $CI_COMMIT_BRANCH
5+
variables:
6+
DEPLOY_ENV: production
7+
8+
stages: [test, build, deploy]
9+
10+
test-job:
11+
stage: test
12+
script:
13+
- echo "testing"
14+
15+
build-job:
16+
stage: build
17+
needs: [test-job]
18+
environment:
19+
name: staging
20+
script:
21+
- echo "building"
22+
23+
deploy-job:
24+
stage: deploy
25+
needs: [build-job]
26+
environment:
27+
name: $DEPLOY_ENV
28+
script:
29+
- echo "deploying"
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {WriteStreamsMock} from "../../../src/write-streams.js";
2+
import {handler} from "../../../src/handler.js";
3+
import chalk from "chalk-template";
4+
import {initSpawnSpy} from "../../mocks/utils.mock.js";
5+
import {WhenStatics} from "../../mocks/when-statics.js";
6+
7+
beforeAll(() => {
8+
initSpawnSpy(WhenStatics.all);
9+
});
10+
11+
test.concurrent("list-environment --list", async () => {
12+
const writeStreams = new WriteStreamsMock();
13+
await handler({
14+
cwd: "tests/test-cases/list-environment/",
15+
list: true,
16+
stateDir: ".gitlab-ci-local-list-environment",
17+
}, writeStreams);
18+
19+
// jobNamePad=10 (deploy-job), descriptionPadEnd=11, stagePadEnd=6 (deploy), whenPadEnd=10, environmentPadEnd=11 (max("production","staging")=10 < 11)
20+
const expected = [
21+
chalk`{grey ${"name".padEnd(10)} ${"description".padEnd(11)}} {grey ${"stage".padEnd(6)} ${"when".padEnd(10)}} {grey allow_failure ${"environment".padEnd(11)} needs}`,
22+
chalk`{blueBright ${"test-job".padEnd(10)}} ${"".padEnd(11)} {yellow ${"test".padEnd(6)}} ${"on_success".padEnd(10)} ${"false".padEnd(13)} ${"".padEnd(11)}`,
23+
chalk`{blueBright ${"build-job".padEnd(10)}} ${"".padEnd(11)} {yellow ${"build".padEnd(6)}} ${"on_success".padEnd(10)} ${"false".padEnd(13)} ${"staging".padEnd(11)} [{blueBright test-job}]`,
24+
// This line depends on PR #1833 (workflow:rules:variables) - without it, $DEPLOY_ENV is not resolved to "production"
25+
chalk`{blueBright ${"deploy-job".padEnd(10)}} ${"".padEnd(11)} {yellow ${"deploy".padEnd(6)}} ${"on_success".padEnd(10)} ${"false".padEnd(13)} ${"production".padEnd(11)} [{blueBright build-job}]`,
26+
];
27+
expect(writeStreams.stdoutLines).toEqual(expect.arrayContaining(expected));
28+
});
29+
30+
test.concurrent("list-environment --list-csv", async () => {
31+
const writeStreams = new WriteStreamsMock();
32+
await handler({
33+
cwd: "tests/test-cases/list-environment/",
34+
listCsv: true,
35+
stateDir: ".gitlab-ci-local-list-environment-csv",
36+
}, writeStreams);
37+
38+
const expected = [
39+
"name;stage;when;allowFailure;environment;needs",
40+
"test-job;test;on_success;false;;",
41+
"build-job;build;on_success;false;staging;[test-job]",
42+
// This line depends on PR #1833 (workflow:rules:variables) - without it, $DEPLOY_ENV is not resolved to "production"
43+
"deploy-job;deploy;on_success;false;production;[build-job]",
44+
];
45+
expect(writeStreams.stdoutLines).toEqual(expect.arrayContaining(expected));
46+
});

0 commit comments

Comments
 (0)