Support env var parameter substitution

Signed-off-by: solimant <solimant@users.noreply.github.com>
This commit is contained in:
solimant
2024-03-11 05:11:22 +00:00
parent 87e9ed3ccc
commit 99bab65ff7
4 changed files with 61 additions and 2 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/config-loader': minor
---
Support parameter substitution for environment variables
+12
View File
@@ -199,6 +199,18 @@ configuration value will evaluate to `undefined`.
The substitution syntax can be escaped using `$${...}`, which will be resolved
as `${...}`.
Parameter substitution syntax (e.g. `${MY_VAR:-default-value}`) is also
supported to provide a default or fallback value for a given environment
variable if it is unset, or is declared but has no value. For example:
```yaml
app:
baseUrl: https://${HOST:-http://localhost:3000}
```
In the above example, when `HOST` is unset or has no value, it will be
substituted with `http://localhost:3000`.
## Combining Includes and Environment Variable Substitution
The Includes and Environment Variable Substitutions can be combined to do
@@ -55,6 +55,12 @@ describe('substituteTransform', () => {
applied: true,
value: 'hello my-secret',
});
await expect(
substituteTransform('hello ${SECRET:-default-secret}', { dir: '/' }),
).resolves.toEqual({
applied: true,
value: 'hello my-secret',
});
await expect(
substituteTransform('${SECRET } $${} ${TOKEN }', { dir: '/' }),
).resolves.toEqual({ applied: true, value: 'my-secret ${} my-token' });
@@ -64,6 +70,24 @@ describe('substituteTransform', () => {
applied: true,
value: undefined,
});
await expect(
substituteTransform('foo ${MISSING:-}', { dir: '/' }),
).resolves.toEqual({
applied: true,
value: undefined,
});
await expect(
substituteTransform('foo ${MISSING:-default-value}', { dir: '/' }),
).resolves.toEqual({
applied: true,
value: 'foo default-value',
});
await expect(
substituteTransform('foo ${MISSING:-default:-value}', { dir: '/' }),
).resolves.toEqual({
applied: true,
value: 'foo default:-value',
});
await expect(
substituteTransform('empty substitute ${}', { dir: '/' }),
).resolves.toEqual({
@@ -73,6 +97,9 @@ describe('substituteTransform', () => {
await expect(
substituteTransform('foo ${MISSING} ${SECRET}', { dir: '/' }),
).resolves.toEqual({ applied: true, value: undefined });
await expect(
substituteTransform('foo ${MISSING:-} ${SECRET}', { dir: '/' }),
).resolves.toEqual({ applied: true, value: undefined });
await expect(
substituteTransform('foo ${SECRET} ${SECRET}', { dir: '/' }),
).resolves.toEqual({ applied: true, value: 'foo my-secret my-secret' });
@@ -21,7 +21,9 @@ import { SubstitutionFunc } from '../types';
/**
* A environment variable substitution transform that transforms e.g. 'token ${MY_TOKEN}'
* to 'token abc' if MY_TOKEN is 'abc'. If any of the substituted variables are undefined,
* the entire expression ends up undefined.
* the entire expression ends up undefined. Additionally, supports parameter substitution
* syntax to provide a default or fallback value for a given environment variable if it is
* unset; e.g. 'token ${MY_TOKEN:-xyz}' transforms to 'token xyz' if MY_TOKEN is unset.
*/
export function createSubstitutionTransform(
env: SubstitutionFunc,
@@ -37,7 +39,20 @@ export function createSubstitutionTransform(
if (part.startsWith('$$')) {
parts[i] = part.slice(1);
} else {
parts[i] = await env(part.slice(2, -1).trim());
const indexOfFallbackSeparator = part.indexOf(':-');
if (indexOfFallbackSeparator > -1) {
const envVarValue = await env(
part.slice(2, indexOfFallbackSeparator).trim(),
);
const fallbackValue = part
.slice(indexOfFallbackSeparator + ':-'.length, -1)
.trim();
parts[i] = envVarValue || fallbackValue || undefined;
} else {
parts[i] = await env(part.slice(2, -1).trim());
}
}
}