@benshawmean/envedit 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +41 -20
- package/cmd/environment/add.ts +110 -0
- package/cmd/environment/edit.ts +82 -0
- package/cmd/environment/list.ts +19 -0
- package/cmd/environment/remove.ts +50 -0
- package/cmd/environment.ts +21 -0
- package/cmd/setup.ts +64 -0
- package/cmd/use.ts +62 -0
- package/cmd/variable/add.ts +94 -0
- package/cmd/variable/edit.ts +161 -0
- package/cmd/variable/list.ts +43 -0
- package/cmd/variable/remove.ts +44 -0
- package/cmd/variable.ts +21 -0
- package/index.ts +14 -555
- package/lib/config.ts +15 -6
- package/lib/logger.ts +15 -0
- package/package.json +3 -1
- package/tsconfig.json +1 -0
- package/bun.lock +0 -118
package/.gitlab-ci.yml
CHANGED
|
@@ -1,44 +1,65 @@
|
|
|
1
1
|
stages:
|
|
2
2
|
- test
|
|
3
|
-
- build
|
|
4
3
|
- deploy
|
|
5
4
|
|
|
6
5
|
workflow:
|
|
7
6
|
rules:
|
|
8
7
|
- if: $CI_COMMIT_BRANCH
|
|
8
|
+
- if: $CI_COMMIT_TAG
|
|
9
9
|
|
|
10
10
|
default:
|
|
11
11
|
image: oven/bun:debian
|
|
12
12
|
before_script:
|
|
13
13
|
- apt-get update -y > /dev/null
|
|
14
|
-
- apt-get install -qy git curl > /dev/null
|
|
15
|
-
-
|
|
14
|
+
- apt-get install -qy git curl jq build-essential > /dev/null
|
|
15
|
+
- curl -sSf https://sh.rustup.rs | bash -s -- -y -q > /dev/null
|
|
16
|
+
- . "$HOME/.cargo/env"
|
|
17
|
+
- bun install --quiet
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
stage:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
19
|
+
test:
|
|
20
|
+
stage: test
|
|
21
|
+
script:
|
|
22
|
+
- bun test
|
|
23
|
+
- sed 's/amp;//' coverage/junit.xml > coverage/junit.xml.tmp # remove amp; from junit report to prevent gitlab parsing issues
|
|
24
|
+
- mv coverage/junit.xml.tmp coverage/junit.xml # make the change permanent
|
|
25
|
+
- cargo install -q lcov2xml # used to convert lcov output to cobertura-xml for gitlab code coverage parsing
|
|
26
|
+
- lcov2xml coverage/lcov.info -o coverage/cobertura-coverage.xml
|
|
27
|
+
coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
|
|
28
|
+
artifacts:
|
|
29
|
+
reports:
|
|
30
|
+
junit: ./coverage/junit.xml
|
|
31
|
+
coverage_report:
|
|
32
|
+
coverage_format: cobertura
|
|
33
|
+
path: ./coverage/cobertura-coverage.xml
|
|
25
34
|
|
|
26
|
-
deploy
|
|
27
|
-
|
|
28
|
-
# Bun seems to struggle publishing to npm on the CI job, so we'll use npm for this one
|
|
29
|
-
image: node:latest
|
|
30
|
-
before_script: [] # skip the default before_script
|
|
35
|
+
deploy:
|
|
36
|
+
stage: deploy
|
|
31
37
|
id_tokens:
|
|
32
38
|
SIGSTORE_ID_TOKEN:
|
|
33
39
|
aud: sigstore
|
|
34
40
|
NPM_ID_TOKEN:
|
|
35
41
|
aud: "npm:registry.npmjs.org"
|
|
42
|
+
rules:
|
|
43
|
+
- if: $CI_COMMIT_REF_PROTECTED && $CI_COMMIT_TAG && $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+(-\S*)?$/
|
|
36
44
|
script:
|
|
37
|
-
-
|
|
45
|
+
- |
|
|
46
|
+
export PACKAGE_NAME=$(jq -r '.name' package.json)
|
|
47
|
+
export CURR_VER=$(jq -r '.version' package.json)
|
|
48
|
+
export LIVE_VER=$(bun info $PACKAGE_NAME version)
|
|
49
|
+
if [ "$LIVE_VER" == "$CURR_VER" ]; then
|
|
50
|
+
echo "Version $CURR_VER is already published. Skipping deployment."
|
|
51
|
+
exit 9001
|
|
52
|
+
fi
|
|
38
53
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
54
|
+
- bun pm pack --filename package.tgz
|
|
55
|
+
|
|
56
|
+
# Publish the package to npm
|
|
57
|
+
- bunx npm publish package.tgz
|
|
58
|
+
|
|
59
|
+
# Publish the package to GitLab's npm registry
|
|
42
60
|
- echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}" > .npmrc
|
|
43
61
|
- echo "@benshawmean:registry=https://${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/" >> .npmrc
|
|
44
62
|
- bun publish
|
|
63
|
+
allow_failure:
|
|
64
|
+
exit_codes:
|
|
65
|
+
- 9001
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { confirm, input, password, select } from "@inquirer/prompts";
|
|
4
|
+
import type { CommandModule } from "yargs";
|
|
5
|
+
|
|
6
|
+
import { Configuration, EnvironmentFile, VariableType } from "#lib/config";
|
|
7
|
+
import { NotFoundError } from "#lib/error";
|
|
8
|
+
import { logger } from "#lib/logger";
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
command: 'add',
|
|
12
|
+
describe: 'Add a new environment',
|
|
13
|
+
builder: (yargs) => yargs,
|
|
14
|
+
handler: async (_args) => {
|
|
15
|
+
const config = new Configuration().loadConfigurationFile();
|
|
16
|
+
|
|
17
|
+
const name = await input({
|
|
18
|
+
message: "Enter the environment name:",
|
|
19
|
+
validate: (input) => {
|
|
20
|
+
if (!input) {
|
|
21
|
+
return "Environment name cannot be empty";
|
|
22
|
+
}
|
|
23
|
+
if (config.getEnvironment(input)) {
|
|
24
|
+
return "Environment name already exists";
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const prefix = await input({
|
|
31
|
+
message: "Enter the environment prefix:",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const file = await input({
|
|
35
|
+
message: "Enter the environment file path:",
|
|
36
|
+
default: `.env.${prefix}`,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const isActive = await confirm({
|
|
40
|
+
message: "Is this environment active?",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
logger
|
|
44
|
+
.debug(`Adding new environment "${name}" with prefix "${prefix}" and file: "${file}"`);
|
|
45
|
+
|
|
46
|
+
config
|
|
47
|
+
.addEnvironment({ name, prefix, file, isActive })
|
|
48
|
+
.saveConfigurationFile();
|
|
49
|
+
|
|
50
|
+
const envFile = new EnvironmentFile(file).load();
|
|
51
|
+
|
|
52
|
+
const valuesToSet: Array<[string, string]> = []
|
|
53
|
+
|
|
54
|
+
if (!fs.existsSync(file)) {
|
|
55
|
+
logger.debug(`Environment file not found: ${file}`);
|
|
56
|
+
|
|
57
|
+
const shouldClone = await confirm({
|
|
58
|
+
message: "Do you want to clone a pre-existing environment into the new file?",
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (shouldClone) {
|
|
62
|
+
logger.debug(`Cloning a pre-existing environment into the new file: ${file}`);
|
|
63
|
+
|
|
64
|
+
const clonedEnv = await select({
|
|
65
|
+
message: "Select the environment to clone from:",
|
|
66
|
+
choices: config.configuration.environments.map(env => ({
|
|
67
|
+
name: env.name,
|
|
68
|
+
value: env.name,
|
|
69
|
+
})),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const selectedEnv = config.getEnvironment(clonedEnv);
|
|
73
|
+
|
|
74
|
+
if (!selectedEnv) {
|
|
75
|
+
throw new NotFoundError(`Environment not found: ${clonedEnv}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const selectedEnvFile = new EnvironmentFile(selectedEnv.file).load();
|
|
79
|
+
|
|
80
|
+
for (const [key, value] of Object.entries(selectedEnvFile.content)) {
|
|
81
|
+
valuesToSet.push([key, value]);
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
for (const variable of config.configuration.variables) {
|
|
85
|
+
const request = {
|
|
86
|
+
message: `Enter the value for ${variable.name} in environment ${name}:`,
|
|
87
|
+
mask: variable.type === VariableType.Private ? "*" : undefined,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const value = variable.type === VariableType.Private
|
|
91
|
+
? await password(request)
|
|
92
|
+
: await input(request);
|
|
93
|
+
|
|
94
|
+
logger
|
|
95
|
+
.debug(`Setting variable "${variable.name}" with value "${value}" in environment "${name}"`);
|
|
96
|
+
|
|
97
|
+
valuesToSet.push([variable.name, value]);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const [key, value] of valuesToSet) {
|
|
102
|
+
logger
|
|
103
|
+
.debug(`Setting variable "${key}" with value "${value}" in environment file: ${file}`);
|
|
104
|
+
envFile.setVariable(key, value);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
envFile.save();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} satisfies CommandModule;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { confirm, input, select, checkbox } from "@inquirer/prompts";
|
|
4
|
+
import type { CommandModule } from "yargs";
|
|
5
|
+
|
|
6
|
+
import { Configuration } from "#lib/config";
|
|
7
|
+
import { NotFoundError } from "#lib/error";
|
|
8
|
+
import { logger } from "#lib/logger";
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
command: 'edit',
|
|
12
|
+
describe: 'Edit an environment',
|
|
13
|
+
builder: (yargs) => yargs,
|
|
14
|
+
handler: async (_args) => {
|
|
15
|
+
const config = new Configuration().loadConfigurationFile();
|
|
16
|
+
|
|
17
|
+
const name = await select({
|
|
18
|
+
message: "Select the environment to edit:",
|
|
19
|
+
choices: config.configuration.environments.map(env => ({
|
|
20
|
+
name: env.name,
|
|
21
|
+
value: env.name,
|
|
22
|
+
})),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const selectedEnv = config.getEnvironment(name);
|
|
26
|
+
|
|
27
|
+
if (!selectedEnv) {
|
|
28
|
+
throw new NotFoundError(`Environment not found: ${name}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const itemsToEdit = await checkbox({
|
|
32
|
+
message: "Select the items to edit:",
|
|
33
|
+
choices: [
|
|
34
|
+
{ name: "Name", value: "name" },
|
|
35
|
+
{ name: "Prefix", value: "prefix" },
|
|
36
|
+
{ name: "File", value: "file" },
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const updatedEnv = { ...selectedEnv };
|
|
41
|
+
|
|
42
|
+
if (itemsToEdit.includes("name")) {
|
|
43
|
+
logger.debug(`Editing environment name from "${selectedEnv.name}" to "${updatedEnv.name}"`);
|
|
44
|
+
updatedEnv.name = await input({
|
|
45
|
+
message: "Enter the new environment name:",
|
|
46
|
+
default: selectedEnv.name,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (itemsToEdit.includes("prefix")) {
|
|
51
|
+
logger.debug(`Editing environment prefix from "${selectedEnv.prefix}" to "${updatedEnv.prefix}"`);
|
|
52
|
+
updatedEnv.prefix = await input({
|
|
53
|
+
message: "Enter the new environment prefix:",
|
|
54
|
+
default: selectedEnv.prefix,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (itemsToEdit.includes("file")) {
|
|
59
|
+
logger.debug(`Editing environment file from "${selectedEnv.file}" to "${updatedEnv.file}"`);
|
|
60
|
+
updatedEnv.file = await input({
|
|
61
|
+
message: "Enter the new environment file path:",
|
|
62
|
+
default: selectedEnv.file,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
config
|
|
67
|
+
.editEnvironment(name, updatedEnv)
|
|
68
|
+
.saveConfigurationFile();
|
|
69
|
+
|
|
70
|
+
if (itemsToEdit.includes("file") && fs.existsSync(selectedEnv.file)) {
|
|
71
|
+
logger.debug(`Old environment file found: ${selectedEnv.file}`);
|
|
72
|
+
const toRename = await confirm({
|
|
73
|
+
message: `Old environment file found: ${selectedEnv.file}. Do you want to rename it to the new file path: ${updatedEnv.file}?`
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (toRename) {
|
|
77
|
+
logger.debug(`Renaming environment file from "${selectedEnv.file}" to "${updatedEnv.file}"`);
|
|
78
|
+
fs.renameSync(selectedEnv.file, updatedEnv.file);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} satisfies CommandModule;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
|
|
3
|
+
import { Configuration } from "#lib/config";
|
|
4
|
+
import { logger } from "#lib/logger";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
command: 'list',
|
|
8
|
+
describe: 'List all environments',
|
|
9
|
+
builder: (yargs) => yargs,
|
|
10
|
+
handler: async (_args) => {
|
|
11
|
+
const config = new Configuration().loadConfigurationFile();
|
|
12
|
+
|
|
13
|
+
logger.debug(`Listing all environments`);
|
|
14
|
+
|
|
15
|
+
console.log(
|
|
16
|
+
JSON.stringify(config.configuration.environments, null, 2)
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
} satisfies CommandModule;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { confirm, select } from "@inquirer/prompts";
|
|
4
|
+
import type { CommandModule } from "yargs";
|
|
5
|
+
|
|
6
|
+
import { Configuration } from "#lib/config";
|
|
7
|
+
import { NotFoundError } from "#lib/error";
|
|
8
|
+
import { logger } from "#lib/logger";
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
command: 'remove',
|
|
12
|
+
describe: 'Remove an environment',
|
|
13
|
+
builder: (yargs) => yargs,
|
|
14
|
+
handler: async (_args) => {
|
|
15
|
+
const config = new Configuration().loadConfigurationFile();
|
|
16
|
+
|
|
17
|
+
const name = await select({
|
|
18
|
+
message: "Select the environment to remove:",
|
|
19
|
+
choices: config.configuration.environments.map(env => ({
|
|
20
|
+
name: env.name,
|
|
21
|
+
value: env.name,
|
|
22
|
+
})),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const selectedEnv = config.getEnvironment(name);
|
|
26
|
+
|
|
27
|
+
if (!selectedEnv) {
|
|
28
|
+
throw new NotFoundError(`Environment not found: ${name}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
logger
|
|
32
|
+
.debug(`Removing environment "${name}" with file: "${selectedEnv.file}"`);
|
|
33
|
+
|
|
34
|
+
config
|
|
35
|
+
.removeEnvironment(name)
|
|
36
|
+
.saveConfigurationFile();
|
|
37
|
+
|
|
38
|
+
if (fs.existsSync(selectedEnv.file)) {
|
|
39
|
+
const toDelete = await confirm({
|
|
40
|
+
message: `Environment file found: ${selectedEnv.file}. Do you want to delete it?`
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (toDelete) {
|
|
44
|
+
logger
|
|
45
|
+
.debug(`Deleting environment file: ${selectedEnv.file}`);
|
|
46
|
+
fs.unlinkSync(selectedEnv.file);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} satisfies CommandModule;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
|
|
3
|
+
import Add from "./environment/add";
|
|
4
|
+
import Edit from "./environment/edit";
|
|
5
|
+
import List from "./environment/list";
|
|
6
|
+
import Remove from "./environment/remove";
|
|
7
|
+
|
|
8
|
+
const data = {
|
|
9
|
+
command: 'environment',
|
|
10
|
+
describe: 'Manage environments',
|
|
11
|
+
builder: (yargs) => yargs
|
|
12
|
+
.usage('Usage: envedit environment <command> [options]')
|
|
13
|
+
.command([Add, Edit, List, Remove])
|
|
14
|
+
.demandCommand(),
|
|
15
|
+
handler: async (_args) => {}
|
|
16
|
+
} satisfies CommandModule;
|
|
17
|
+
|
|
18
|
+
export const command = data.command;
|
|
19
|
+
export const describe = data.describe;
|
|
20
|
+
export const builder = data.builder;
|
|
21
|
+
export const handler = data.handler;
|
package/cmd/setup.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { confirm } from "@inquirer/prompts";
|
|
4
|
+
import type { CommandModule } from "yargs";
|
|
5
|
+
|
|
6
|
+
import { Configuration } from "#lib/config";
|
|
7
|
+
import { logger } from "#lib/logger";
|
|
8
|
+
|
|
9
|
+
const data = {
|
|
10
|
+
command: 'setup',
|
|
11
|
+
describe: 'Setup the project for use with envedit',
|
|
12
|
+
builder: (yargs) => yargs
|
|
13
|
+
.usage('Usage: envedit setup'),
|
|
14
|
+
handler: async (_args) => {
|
|
15
|
+
new Configuration().loadConfigurationFile();
|
|
16
|
+
|
|
17
|
+
if (fs.existsSync('.git')) {
|
|
18
|
+
logger.debug(`Git repository found. Checking for git ignore file.`);
|
|
19
|
+
|
|
20
|
+
const gitignorePath = '.gitignore';
|
|
21
|
+
|
|
22
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
23
|
+
logger.debug(`Git ignore file not found: ${gitignorePath}`);
|
|
24
|
+
|
|
25
|
+
const toCreate = await confirm({
|
|
26
|
+
message: `Git Repository without a git ignore file not found: ${gitignorePath}. Do you want to create it?`
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (toCreate) {
|
|
30
|
+
console.error(`Git Repository without a git ignore file not found: ${gitignorePath}`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fs.writeFileSync(gitignorePath, "");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const expectedItems = ['.env', '.env.*', 'env.config.yaml'];
|
|
38
|
+
|
|
39
|
+
logger.debug(`Checking for expected items in git ignore file: ${expectedItems.join(", ")}`);
|
|
40
|
+
|
|
41
|
+
for (const item of expectedItems) {
|
|
42
|
+
if (!fs.readFileSync(gitignorePath, "utf-8").includes(item)) {
|
|
43
|
+
logger.debug(`Item not found in git ignore file: ${item}`);
|
|
44
|
+
|
|
45
|
+
const toAdd = await confirm({
|
|
46
|
+
message: `The item ${item} is not in the git ignore file. Do you want to add it?`
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (!toAdd) {
|
|
50
|
+
console.error(`The item ${item} is not in the git ignore file.`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fs.appendFileSync(gitignorePath, `\n${item}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} satisfies CommandModule;
|
|
60
|
+
|
|
61
|
+
export const command = data.command;
|
|
62
|
+
export const describe = data.describe;
|
|
63
|
+
export const builder = data.builder;
|
|
64
|
+
export const handler = data.handler;
|
package/cmd/use.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { select } from "@inquirer/prompts";
|
|
4
|
+
import type { CommandModule } from "yargs";
|
|
5
|
+
|
|
6
|
+
import { Configuration } from "#lib/config";
|
|
7
|
+
import { NotFoundError } from "#lib/error";
|
|
8
|
+
import { logger } from "#lib/logger";
|
|
9
|
+
|
|
10
|
+
const data = {
|
|
11
|
+
command: 'use',
|
|
12
|
+
describe: 'Set the current environment to use',
|
|
13
|
+
builder: (yargs) => yargs
|
|
14
|
+
.usage('Usage: envedit use'),
|
|
15
|
+
handler: async (_args) => {
|
|
16
|
+
const config = new Configuration().loadConfigurationFile();
|
|
17
|
+
|
|
18
|
+
const name = await select({
|
|
19
|
+
message: "Select the environment to use",
|
|
20
|
+
choices: config.configuration.environments.map(env => ({
|
|
21
|
+
name: env.name + (env.isActive ? " (active)" : ""),
|
|
22
|
+
value: env.name,
|
|
23
|
+
})),
|
|
24
|
+
default: config.getActiveEnvironment()?.name,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const selectedEnv = config.getEnvironment(name);
|
|
28
|
+
|
|
29
|
+
if (!selectedEnv) {
|
|
30
|
+
throw new NotFoundError(`Environment not found: ${name}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
logger.debug(`Setting current environment to "${name}" with file: "${selectedEnv.file}"`);
|
|
34
|
+
|
|
35
|
+
if (!selectedEnv.isActive) {
|
|
36
|
+
logger.debug(`Updating active environment in configuration file to "${name}"`);
|
|
37
|
+
|
|
38
|
+
for (const env of config.configuration.environments) {
|
|
39
|
+
env.isActive = env.name === name;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
config.saveConfigurationFile();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
logger.debug(`Creating symlink to environment file: ${selectedEnv.file}`);
|
|
46
|
+
|
|
47
|
+
const envFilePath = selectedEnv.file;
|
|
48
|
+
|
|
49
|
+
if (fs.existsSync('.env')) {
|
|
50
|
+
logger.debug(`Removing existing symlink or file: .env`);
|
|
51
|
+
|
|
52
|
+
fs.unlinkSync('.env');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fs.symlinkSync(envFilePath, '.env', 'file');
|
|
56
|
+
}
|
|
57
|
+
} satisfies CommandModule;
|
|
58
|
+
|
|
59
|
+
export const command = data.command;
|
|
60
|
+
export const describe = data.describe;
|
|
61
|
+
export const builder = data.builder;
|
|
62
|
+
export const handler = data.handler;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { confirm, input, password, select } from "@inquirer/prompts";
|
|
2
|
+
import type { CommandModule } from "yargs";
|
|
3
|
+
|
|
4
|
+
import { Configuration, EnvironmentFile, VariableType } from "#lib/config";
|
|
5
|
+
import { NotFoundError } from "#lib/error";
|
|
6
|
+
import { logger } from "#lib/logger";
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
command: 'add',
|
|
10
|
+
describe: 'Add a new environment variable',
|
|
11
|
+
builder: (yargs) => yargs,
|
|
12
|
+
handler: async (_args) => {
|
|
13
|
+
const config = new Configuration().loadConfigurationFile();
|
|
14
|
+
|
|
15
|
+
const name = await input({
|
|
16
|
+
message: "Enter the variable name:",
|
|
17
|
+
validate: (input) => {
|
|
18
|
+
if (!input) {
|
|
19
|
+
return "Variable name cannot be empty";
|
|
20
|
+
}
|
|
21
|
+
if (config.getVariable(input)) {
|
|
22
|
+
return "Variable name already exists";
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const type = await select({
|
|
29
|
+
message: "Select the variable type:",
|
|
30
|
+
choices: [
|
|
31
|
+
{ name: "Public", value: VariableType.Public },
|
|
32
|
+
{ name: "Private", value: VariableType.Private },
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
logger
|
|
37
|
+
.debug(`Adding new variable "${name}" with type "${type}"`);
|
|
38
|
+
|
|
39
|
+
config
|
|
40
|
+
.addVariable({ name, type })
|
|
41
|
+
.saveConfigurationFile();
|
|
42
|
+
|
|
43
|
+
const shouldGloballySet = await confirm({
|
|
44
|
+
message: "Do you want to set this variable with a global value for all environments?",
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const valuesToSet = config.configuration.environments.map(env => ({
|
|
48
|
+
envName: env.name,
|
|
49
|
+
value: '',
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
if (shouldGloballySet) {
|
|
53
|
+
const request = {
|
|
54
|
+
message: `Enter the global value for ${name}:`,
|
|
55
|
+
mask: type === VariableType.Private ? "*" : undefined,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const globalValue = type === VariableType.Private
|
|
59
|
+
? await password(request)
|
|
60
|
+
: await input(request);
|
|
61
|
+
|
|
62
|
+
logger
|
|
63
|
+
.debug(`Setting variable "${name}" with global value "${globalValue}" for all environments`);
|
|
64
|
+
|
|
65
|
+
valuesToSet.forEach((envValue) => { envValue.value = globalValue });
|
|
66
|
+
} else {
|
|
67
|
+
for (const envValue of valuesToSet) {
|
|
68
|
+
const request = {
|
|
69
|
+
message: `Enter the value for ${name} in environment ${envValue.envName}:`,
|
|
70
|
+
mask: type === VariableType.Private ? "*" : undefined,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
envValue.value = type === VariableType.Private
|
|
74
|
+
? await password(request)
|
|
75
|
+
: await input(request);
|
|
76
|
+
|
|
77
|
+
logger
|
|
78
|
+
.debug(`Setting variable "${name}" with value "${envValue.value}" for environment "${envValue.envName}"`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const envValue of valuesToSet) {
|
|
83
|
+
const env = config.getEnvironment(envValue.envName);
|
|
84
|
+
logger
|
|
85
|
+
.debug(`Retrieving environment: ${envValue.envName}`);
|
|
86
|
+
|
|
87
|
+
if (!env) {
|
|
88
|
+
throw new NotFoundError(`Environment not found: ${envValue.envName}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
EnvironmentFile.quickUpdate(env.file, name, envValue.value);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} satisfies CommandModule;
|