Skip to content

Commit

Permalink
[FEATURE] Add support to autofill env-vars in config
Browse files Browse the repository at this point in the history
- Environment variables should be autofilled when the config is loaded

Fixes: #935
  • Loading branch information
menof36go committed Aug 1, 2024
1 parent 380e358 commit 174b695
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 0 deletions.
49 changes: 49 additions & 0 deletions lib/graph/Module.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ function clone(obj) {
* @alias @ui5/project/graph/Module
*/
class Module {
/**
* Regular expression to identify environment variables in strings.
* Environment variables have to be prefixed with "env:", e.g. "env:Path".
*
* @private
* @static
* @readonly
*/
static _ENVIRONMENT_VARIABLE_REGEX = /env:\S+/g;

/**
* @param {object} parameters Module parameters
* @param {string} parameters.id Unique ID for the module
Expand Down Expand Up @@ -403,9 +413,48 @@ class Module {
if (!config.kind) {
config.kind = "project"; // default
}
for (const key of Object.keys(config)) {
this._normalizeConfigValue(config, key);
}
return config;
}

/**
* Normalizes the config value at object[key]. If the config value is an object / array,
* this method will descend depth-first on its properties / elements. If the config value is a string
* and contains any environment variables, they will be filled in at this point.
*
* @private
* @param {(object|any[])} object An object or array
* @param {(string|number)} key A key of the object or an index of the array
*/
_normalizeConfigValue(object, key) {
let value = object[key];
switch (typeof value) {
case "string": {
value = value.replace(Module._ENVIRONMENT_VARIABLE_REGEX, (substring) => {
const envVarName = substring.slice(4);
return process.env[envVarName] || substring;
});
object[key] = value;
break;
}
case "object": {
if (value === null) break;
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
this._normalizeConfigValue(value, i);
}
} else {
for (const key of Object.keys(value)) {
this._normalizeConfigValue(value, key);
}
}
break;
}
}
}

/**
* Resource Access
*/
Expand Down
56 changes: 56 additions & 0 deletions test/lib/graph/Module.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,62 @@ test("Legacy patches are applied", async (t) => {
.map(testLegacyLibrary));
});

test("Environment variables in configuration", async (t) => {
const testEnvVars = ["testEnvVarForString", "testEnvVarForObject", "testEnvVarForArray"].map(
(testEnvVar, index) => {
const wrapper = {
name: testEnvVar,
oldValue: process.env[testEnvVar],
newValue: `testValue${index}`,
};
process.env[testEnvVar] = wrapper.newValue;
return wrapper;
}
);
try {
const ui5Module = new Module({
id: "application.a.id",
version: "1.0.0",
modulePath: applicationAPath,
configuration: {
specVersion: "2.6",
type: "application",
metadata: {
name: "application.a-object",
},
customConfiguration: {
stringWithEnvVar: `env:${testEnvVars[0].name}`,
objectWithEnvVar: {
someKey: `env:${testEnvVars[1].name}`,
},
arrayWithEnvVar: ["a", `env:${testEnvVars[2].name}`, "c"]
},
},
});
const {project} = await ui5Module.getSpecifications();
t.deepEqual(
project.getCustomConfiguration(),
{
stringWithEnvVar: testEnvVars[0].newValue,
objectWithEnvVar: {
someKey: testEnvVars[1].newValue,
},
arrayWithEnvVar: ["a", testEnvVars[2].newValue, "c"],
},
"Environment variable is filled in"
);
} finally {
// Reset all env vars back to their value previous to testing
testEnvVars.forEach((wrapper) => {
if (wrapper.oldValue === undefined) {
delete process.env[wrapper.name];
} else {
process.env[wrapper.name] = wrapper.oldValue;
}
});
}
});

test("Invalid configuration in file", async (t) => {
const ui5Module = new Module({
id: "application.a.id",
Expand Down

0 comments on commit 174b695

Please sign in to comment.