Skip to content

Commit 4e36aa5

Browse files
parksbarcanis
andauthored
Support escaping template variables in environment values (#6935)
## What's the problem this PR addresses? <!-- Describe the rationale of your PR. --> <!-- Link all issues that it closes. (Closes/Resolves #xxxx.) --> Resolves #6491 ```sh $ yarn init -2 $ echo 'CYPRESS_DOWNLOAD_PATH_TEMPLATE="\${endpoint}/\${platform}-\${arch}/cypress.zip"' > .env.yarn $ yarn node -p 'process.env.CYPRESS_DOWNLOAD_PATH_TEMPLATE' # AS-IS Usage Error: Environment variable not found (endpoint) # TO-BE ${endpoint}/${platform}-${arch}/cypress.zip ``` ## How did you fix it? <!-- A detailed description of your implementation. --> Support escaping template variables in environment variable values. When a template variable is escaped with a backslash (e.g., `\${VAR}`), it is now preserved as a literal string `${VAR}` instead of being replaced with an actual environment variable value. I updated the regex to match values starting with a backslash. When a match starts with a backslash, it is treated as an escaped template and returns the value with only the backslash removed (`match.slice(1)`). ## Checklist <!--- Don't worry if you miss something, chores are automatically tested. --> <!--- This checklist exists to help you remember doing the chores when you submit a PR. --> <!--- Put an `x` in all the boxes that apply. --> - [x] I have read the [Contributing Guide](https://yarnpkg.com/advanced/contributing). <!-- See https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released for more details. --> <!-- Check with `yarn version check` and fix with `yarn version check -i` --> - [x] I have set the packages that need to be released for my changes to be effective. <!-- The "Testing chores" workflow validates that your PR follows our guidelines. --> <!-- If it doesn't pass, click on it to see details as to what your PR might be missing. --> - [x] I will check that all automated PR checks pass before the PR gets reviewed. --------- Co-authored-by: Maël Nison <nison.mael@gmail.com>
1 parent b9ccd93 commit 4e36aa5

File tree

3 files changed

+88
-5
lines changed

3 files changed

+88
-5
lines changed

.yarn/versions/3e62b777.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
releases:
2+
"@yarnpkg/cli": minor
3+
"@yarnpkg/core": patch
4+
5+
declined:
6+
- "@yarnpkg/plugin-catalog"
7+
- "@yarnpkg/plugin-compat"
8+
- "@yarnpkg/plugin-constraints"
9+
- "@yarnpkg/plugin-dlx"
10+
- "@yarnpkg/plugin-essentials"
11+
- "@yarnpkg/plugin-exec"
12+
- "@yarnpkg/plugin-file"
13+
- "@yarnpkg/plugin-git"
14+
- "@yarnpkg/plugin-github"
15+
- "@yarnpkg/plugin-http"
16+
- "@yarnpkg/plugin-init"
17+
- "@yarnpkg/plugin-interactive-tools"
18+
- "@yarnpkg/plugin-jsr"
19+
- "@yarnpkg/plugin-link"
20+
- "@yarnpkg/plugin-nm"
21+
- "@yarnpkg/plugin-npm"
22+
- "@yarnpkg/plugin-npm-cli"
23+
- "@yarnpkg/plugin-pack"
24+
- "@yarnpkg/plugin-patch"
25+
- "@yarnpkg/plugin-pnp"
26+
- "@yarnpkg/plugin-pnpm"
27+
- "@yarnpkg/plugin-stage"
28+
- "@yarnpkg/plugin-typescript"
29+
- "@yarnpkg/plugin-version"
30+
- "@yarnpkg/plugin-workspace-tools"
31+
- "@yarnpkg/builder"
32+
- "@yarnpkg/doctor"
33+
- "@yarnpkg/extensions"
34+
- "@yarnpkg/nm"
35+
- "@yarnpkg/pnpify"
36+
- "@yarnpkg/sdks"

packages/yarnpkg-core/sources/miscUtils.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,11 +471,13 @@ export function buildIgnorePattern(ignorePatterns: Array<string>) {
471471
}
472472

473473
export function replaceEnvVariables(value: string, {env}: {env: {[key: string]: string | undefined}}) {
474-
const regex = /\${(?<variableName>[\d\w_]+)(?<colon>:)?(?:-(?<fallback>[^}]*))?}/g;
474+
const regex = /\\?\${(?<variableName>[\d\w_]+)(?<colon>:)?(?:-(?<fallback>[^}]*))?}/g;
475475

476-
return value.replace(regex, (...args) => {
477-
const {variableName, colon, fallback} = args[args.length - 1];
476+
return value.replace(regex, (match, ...args) => {
477+
if (match.startsWith(`\\`))
478+
return match.slice(1);
478479

480+
const {variableName, colon, fallback} = args[args.length - 1];
479481
const variableExist = Object.hasOwn(env, variableName);
480482
const variableValue = env[variableName];
481483

packages/yarnpkg-core/tests/miscUtils.test.ts

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,45 @@ import CJSON from 'comment-json';
33
import * as miscUtils from '../sources/miscUtils';
44

55
describe(`miscUtils`, () => {
6+
describe(`replaceEnvVariables`, () => {
7+
it(`should replace environment variables with their values`, () => {
8+
expect(
9+
miscUtils.replaceEnvVariables(
10+
`VAR_A: \${VAR_A}, VAR_B: \${VAR_B}`,
11+
{
12+
env: {
13+
VAR_A: `ValueA`,
14+
VAR_B: `ValueB`,
15+
},
16+
},
17+
),
18+
).toBe(`VAR_A: ValueA, VAR_B: ValueB`);
19+
});
20+
21+
it(`should use fallback values when environment variables are not set`, () => {
22+
expect(
23+
miscUtils.replaceEnvVariables(
24+
`VAR_A: \${VAR_A:-ValueA}, VAR_B: \${VAR_B:-ValueB}`,
25+
{env: {}},
26+
),
27+
).toBe(`VAR_A: ValueA, VAR_B: ValueB`);
28+
});
29+
30+
it(`should not replace escaped environment variables`, () => {
31+
expect(
32+
miscUtils.replaceEnvVariables(
33+
`VAR_A: \\\${VAR_A}, VAR_B: \\\${VAR_B}`,
34+
{
35+
env: {
36+
VAR_A: `ValueA`,
37+
VAR_B: `ValueB`,
38+
},
39+
},
40+
),
41+
).toBe(`VAR_A: \${VAR_A}, VAR_B: \${VAR_B}`);
42+
});
43+
});
44+
645
describe(`mapAndFind`, () => {
746
it(`should work with a simple example`, () => {
847
expect(
@@ -135,7 +174,9 @@ describe(`miscUtils`, () => {
135174
const b = {n: [4, 5, 6]};
136175
const c = miscUtils.mergeIntoTarget(a, b);
137176

138-
expect(CJSON.stringify(c, null, 2)).toStrictEqual(CJSON.stringify(CJSON.parse(`{
177+
expect(CJSON.stringify(c, null, 2)).toStrictEqual(
178+
CJSON.stringify(
179+
CJSON.parse(`{
139180
// n
140181
"n":
141182
// array
@@ -150,7 +191,11 @@ describe(`miscUtils`, () => {
150191
5,
151192
6
152193
]
153-
}`), null, 2));
194+
}`),
195+
null,
196+
2,
197+
),
198+
);
154199
});
155200
});
156201
});

0 commit comments

Comments
 (0)