Skip to content

Commit d2a0dcf

Browse files
committed
fix(cli): ensure trailing newline in GitHub Actions outputs and env vars (#4003)
1 parent 414e5a2 commit d2a0dcf

3 files changed

Lines changed: 117 additions & 8 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"trigger.dev": patch
3+
---
4+
5+
Ensure GitHub Actions environment variables and step outputs are terminated with a trailing newline.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { readFileSync, writeFileSync, unlinkSync, existsSync } from "node:fs";
2+
import { tmpdir } from "node:os";
3+
import { join } from "node:path";
4+
import { afterEach, beforeEach, describe, expect, test } from "vitest";
5+
import { setGithubActionsOutputAndEnvVars } from "./githubActions.js";
6+
7+
describe("setGithubActionsOutputAndEnvVars", () => {
8+
const originalEnv = process.env;
9+
let envFilePath: string;
10+
let outputFilePath: string;
11+
12+
beforeEach(() => {
13+
process.env = { ...originalEnv };
14+
const id = Math.random().toString(36).substring(2, 9);
15+
envFilePath = join(tmpdir(), `gh-env-test-${id}.txt`);
16+
outputFilePath = join(tmpdir(), `gh-output-test-${id}.txt`);
17+
writeFileSync(envFilePath, "");
18+
writeFileSync(outputFilePath, "");
19+
process.env.GITHUB_ENV = envFilePath;
20+
process.env.GITHUB_OUTPUT = outputFilePath;
21+
});
22+
23+
afterEach(() => {
24+
process.env = originalEnv;
25+
if (existsSync(envFilePath)) {
26+
unlinkSync(envFilePath);
27+
}
28+
if (existsSync(outputFilePath)) {
29+
unlinkSync(outputFilePath);
30+
}
31+
});
32+
33+
test("writes entries with trailing newline", () => {
34+
setGithubActionsOutputAndEnvVars({
35+
envVars: {
36+
VAR_ONE: "value1",
37+
VAR_TWO: "value2",
38+
},
39+
outputs: {
40+
outOne: "val1",
41+
outTwo: "val2",
42+
},
43+
});
44+
45+
const envContent = readFileSync(envFilePath, "utf-8");
46+
const outputContent = readFileSync(outputFilePath, "utf-8");
47+
48+
expect(envContent).toBe("VAR_ONE=value1\nVAR_TWO=value2\n");
49+
expect(outputContent).toBe("outOne=val1\noutTwo=val2\n");
50+
});
51+
52+
test("multiple sequential calls terminate each line and do not concatenate keys", () => {
53+
setGithubActionsOutputAndEnvVars({
54+
envVars: {
55+
TRIGGER_VERSION: "1.0.0",
56+
},
57+
outputs: {
58+
needsPromotion: "false",
59+
},
60+
});
61+
62+
setGithubActionsOutputAndEnvVars({
63+
envVars: {
64+
NEXT_VAR: "next",
65+
},
66+
outputs: {
67+
subsequentOutput: "hello",
68+
},
69+
});
70+
71+
const envContent = readFileSync(envFilePath, "utf-8");
72+
const outputContent = readFileSync(outputFilePath, "utf-8");
73+
74+
expect(envContent).toBe("TRIGGER_VERSION=1.0.0\nNEXT_VAR=next\n");
75+
expect(outputContent).toBe("needsPromotion=false\nsubsequentOutput=hello\n");
76+
});
77+
78+
test("empty entries do not append trailing newline or modify file", () => {
79+
setGithubActionsOutputAndEnvVars({
80+
envVars: {},
81+
outputs: {},
82+
});
83+
84+
expect(readFileSync(envFilePath, "utf-8")).toBe("");
85+
expect(readFileSync(outputFilePath, "utf-8")).toBe("");
86+
});
87+
88+
test("does nothing if GITHUB_ENV or GITHUB_OUTPUT are not set", () => {
89+
delete process.env.GITHUB_ENV;
90+
delete process.env.GITHUB_OUTPUT;
91+
92+
expect(() => {
93+
setGithubActionsOutputAndEnvVars({
94+
envVars: { FOO: "bar" },
95+
outputs: { BAZ: "qux" },
96+
});
97+
}).not.toThrow();
98+
99+
expect(readFileSync(envFilePath, "utf-8")).toBe("");
100+
expect(readFileSync(outputFilePath, "utf-8")).toBe("");
101+
});
102+
});

‎packages/cli-v3/src/utilities/githubActions.ts‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@ export function setGithubActionsOutputAndEnvVars({
99
}) {
1010
// Set environment variables
1111
if (process.env.GITHUB_ENV) {
12-
const contents = Object.entries(envVars)
13-
.map(([key, value]) => `${key}=${value}`)
14-
.join("\n");
12+
const entries = Object.entries(envVars);
13+
if (entries.length > 0) {
14+
const contents = `${entries.map(([key, value]) => `${key}=${value}`).join("\n")}\n`;
1515

16-
appendFileSync(process.env.GITHUB_ENV, contents);
16+
appendFileSync(process.env.GITHUB_ENV, contents);
17+
}
1718
}
1819

1920
// Set outputs
2021
if (process.env.GITHUB_OUTPUT) {
21-
const contents = Object.entries(outputs)
22-
.map(([key, value]) => `${key}=${value}`)
23-
.join("\n");
22+
const entries = Object.entries(outputs);
23+
if (entries.length > 0) {
24+
const contents = `${entries.map(([key, value]) => `${key}=${value}`).join("\n")}\n`;
2425

25-
appendFileSync(process.env.GITHUB_OUTPUT, contents);
26+
appendFileSync(process.env.GITHUB_OUTPUT, contents);
27+
}
2628
}
2729
}

0 commit comments

Comments
 (0)