@agilecustoms/envctl 1.27.0 → 1.28.0

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/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  ## usage
7
7
 
8
8
  ```shell
9
- terraform init -backend-config=key=laxa1986
9
+ envctl init -backend-config=key=laxa1986
10
10
  envctl apply -var-file=versions.tfvars -var="log_level=debug"
11
11
  envctl delete
12
12
  ```
@@ -35,12 +35,6 @@ npm view @agilecustoms/envctl version # show latest version available (without i
35
35
  5. "Set up connection"
36
36
  5. In GH workflow job use `permissions: id-token: write` and release action with input `npm-publish: true`
37
37
 
38
- ## History/motivation
39
-
40
- `env-api` is a microservice hosted in 'maintenance' account and working as garbage collector: every environment first
41
- created in `env-api` and then 'managed' by `env-api`: it deletes env when it is not in use anymore OR can extend lifetime.
42
- Creation API yields unique ID, so you can safely extend lifetime via this ID
43
-
44
38
  ### Authorization
45
39
 
46
40
  Main use cases:
@@ -58,7 +52,7 @@ Then I thought about Node.js - it is available on dev machines and in GitHub act
58
52
  How to distribute it? First I thought about using `ncc` to bundle in one big .js file
59
53
  (as I do for `publish-s3` and `gha-healthcheck`) but it will be hard to use on dev machine...
60
54
 
61
- So I ended up publishing this client as an npm package in npmjs
55
+ So I ended up publishing this client as a npm package in npmjs
62
56
  - CI environments can install it via GH action `agilecustoms/envctl`
63
57
  - developer will install it globally via `npm install -g @agilecustoms/envctl`
64
58
 
@@ -15,6 +15,7 @@ export class Cli {
15
15
  constructor() {
16
16
  }
17
17
  async run(command, args, options = {}) {
18
+ const successCodes = options.successCodes ?? [0];
18
19
  const timeoutMs = options.timeoutMs ?? NO_TIMEOUT;
19
20
  const interactive = options.interactive ?? !!options.inScanner;
20
21
  const stdio = [interactive ? 'pipe' : 'ignore', 'pipe', 'pipe'];
@@ -93,7 +94,7 @@ export class Cli {
93
94
  reject(new TimeoutException(`Process killed after timeout of ${timeoutMs}ms`));
94
95
  return;
95
96
  }
96
- if (code === 0) {
97
+ if (code !== null && successCodes.includes(code)) {
97
98
  if (errorBuffer) {
98
99
  logger.warn('Process completed successfully, but there were errors:\n' + errorBuffer);
99
100
  }
@@ -15,7 +15,7 @@ export function wrap(callable) {
15
15
  else {
16
16
  logger.error('Unknown error: \n' + error.stack);
17
17
  }
18
- process.exit(1);
18
+ process.exitCode = 1;
19
19
  }
20
20
  };
21
21
  }
@@ -20,7 +20,7 @@ export class LocalStateService {
20
20
  logger.info('Load local state config');
21
21
  const filePath = this.filePath();
22
22
  if (!fs.existsSync(filePath)) {
23
- logger.warn('Local state file does not exist, must have been accidentally deleted, re-initializing');
23
+ logger.warn('Local state file does not exist, create new one');
24
24
  return this.createEmptyConfig(filePath);
25
25
  }
26
26
  const data = fs.readFileSync(filePath, 'utf-8');
@@ -1,4 +1,4 @@
1
- import { basename } from 'node:path';
1
+ import { basename, dirname } from 'node:path';
2
2
  import {} from '../client/index.js';
3
3
  import { KnownException } from '../exceptions.js';
4
4
  import { logger } from '../logger.js';
@@ -17,6 +17,11 @@ export class LogService extends BaseService {
17
17
  const urlPath = new URL(url).pathname;
18
18
  const gzName = basename(urlPath);
19
19
  const timestamp = Number(gzName.slice(0, -7)) * 1000;
20
+ const res = await this.envApi.fetch(url);
21
+ if (!res.ok) {
22
+ const msg = await res.text();
23
+ throw new KnownException(`Failed to download logs: ${res.status} ${res.statusText}${msg ? ` - ${msg}` : ''}`);
24
+ }
20
25
  const parts = new Intl.DateTimeFormat(undefined, {
21
26
  year: 'numeric',
22
27
  month: '2-digit',
@@ -28,13 +33,16 @@ export class LogService extends BaseService {
28
33
  }).formatToParts(timestamp);
29
34
  const get = (type) => parts.find(p => p.type === type)?.value ?? '';
30
35
  const outName = `${get('year')}-${get('month')}-${get('day')}_${get('hour')}.${get('minute')}.${get('second')}.log`;
31
- const res = await this.envApi.fetch(url);
32
- if (!res.ok) {
33
- const msg = await res.text();
34
- throw new KnownException(`Failed to download logs: ${res.status} ${res.statusText}${msg ? ` - ${msg}` : ''}`);
35
- }
36
36
  const outPath = await this.cli.writeInTmpFile(res.body, outName);
37
37
  logger.info(`Logs saved to: ${outPath}`);
38
- await this.cli.run('open', ['-R', outPath]);
38
+ if (process.platform === 'darwin') {
39
+ await this.cli.run('open', ['-R', outPath]);
40
+ }
41
+ else if (process.platform === 'win32') {
42
+ await this.cli.run('explorer.exe', [`/select,${outPath}`], { successCodes: [0, 1] });
43
+ }
44
+ else {
45
+ await this.cli.run('xdg-open', [dirname(outPath)]);
46
+ }
39
47
  }
40
48
  }
@@ -126,7 +126,7 @@ export class TerraformAdapter {
126
126
  const config = this.localStateService.load();
127
127
  const fileHash = hash(fileContent);
128
128
  if (fileHash !== config.lockFileHash) {
129
- throw new KnownException(`Make sure you're using envctl init instead of terraform init`);
129
+ throw new KnownException(`Make sure to call 'envctl init' prior to 'envctl plan/apply'`);
130
130
  }
131
131
  const lockUpdated = config.lockHash !== fileHash;
132
132
  config.lockHash = fileHash;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agilecustoms/envctl",
3
- "version": "1.27.0",
3
+ "version": "1.28.0",
4
4
  "description": "node.js CLI client for manage environments",
5
5
  "keywords": [
6
6
  "terraform wrapper",
@@ -31,19 +31,18 @@
31
31
  "_comment0": "to run via `npx` you must use `name` (with scope) and have at least one entry in `bin`. Key does not matter when run via `npx`",
32
32
  "_comment1": "keys become CLI apps (symlinks) when install globally. ex: npm install -g @agilecustoms/envctl; ls $(which alexc-blah) >> lrwxr-xr-x 1 alexc admin 62 Dec 30 14:29 /opt/homebrew/bin/alexc-blah -> ../lib/node_modules/@agilecustoms/envctl-client/dist/index.js",
33
33
  "scripts": {
34
- "prepare": "if [ \"$CI\" != \"true\" ]; then husky; fi",
35
34
  "lint": "eslint *.{ts,mjs} \"src/**/*.ts\" \"test/**/*.ts\"",
36
35
  "lint:fix": "npm run lint -- --fix",
37
36
  "test": "vitest run --coverage",
38
37
  "build": "tsc -p tsconfig.build.json",
39
- "it": "tsc -p tsconfig.build.json --sourceMap true && TEST_CWD=\"$CWD\" node dist/index.js",
38
+ "it": "tsc -p tsconfig.build.json --sourceMap true && cross-env TEST_CWD=$CWD node dist/index.js",
40
39
  "run-help": " npm run it -- --help",
41
40
  "run-version": " npm run it -- --version",
42
41
  "run-configure": "npm run it -- configure",
43
42
  "run-logs": " npm run it -- logs",
44
43
  "-d1-": "",
45
44
  "d1-desc": "dev env (fully fledged ~/.envctl/default.json)",
46
- "d1": "CWD=../tt-core npm run it --",
45
+ "d1": "cross-env CWD=../tt-core npm run it --",
47
46
  "d1-init": " npm run d1 -- init -reconfigure -upgrade -backend-config=key=d1",
48
47
  "d1-status": "npm run d1 -- status --verbose",
49
48
  "d1-apply": " npm run d1 -- apply --auto-approve -var=env_size=min",
@@ -51,29 +50,29 @@
51
50
  "d1-logs": " npm run d1 -- logs",
52
51
  "-d2-": "",
53
52
  "d2-desc": "dev env destroy",
54
- "d2": "CWD=../tt-core npm run it --",
53
+ "d2": "cross-env CWD=../tt-core npm run it --",
55
54
  "d2-init": " npm run d2 -- init -reconfigure -upgrade -backend-config=key=d2",
56
55
  "d2-status": " npm run d2 -- status",
57
56
  "d2-apply": " npm run d2 -- apply --auto-approve",
58
57
  "d2-destroy": "npm run d2 -- destroy -var=env_size=min --auto-approve",
59
58
  "-d3-": "",
60
59
  "d3-desc": "dev env plan apply",
61
- "d3": "CWD=../tt-core npm run it --",
60
+ "d3": "cross-env CWD=../tt-core npm run it --",
62
61
  "d3-init": " npm run d3 -- init -reconfigure -upgrade -backend-config=key=d3",
63
62
  "d3-plan": " npm run d3 -- plan -var=env_size=min -var=env=d3 -out=plan",
64
63
  "d3-apply": " npm run d3 -- apply plan",
65
64
  "d3-delete": "npm run d3 -- delete",
66
65
  "-d4-": "",
67
66
  "d4-desc": "terraform init and then envctl apply",
68
- "d4": "CWD=../tt-core npm run it --",
69
- "d4-init": "cd ../tt-core && rm .terraform.lock.hcl && rm .terraform/envctl.json && terraform init -reconfigure -upgrade -backend-config=key=d4",
67
+ "d4": "cross-env CWD=../tt-core npm run it --",
68
+ "d4-init": "cd ../tt-core && rimraf .terraform.lock.hcl .terraform/envctl.json && terraform init -reconfigure -upgrade -backend-config=key=d4",
70
69
  "d4-init1": " npm run d4 -- init -reconfigure -upgrade -backend-config=key=d4",
71
70
  "d4-apply": " npm run d4 -- apply -auto-approve -var=env_size=min",
72
71
  "d4-delete": "npm run d4 -- delete",
73
72
  "d4-status": "npm run d4 -- status",
74
73
  "-e1-": "",
75
74
  "e1-desc": "ephemeral env in CI (must have ENVCTL_API_KEY_ in env vars)",
76
- "e1": "CWD=../tt-core CI=true ENVCTL_HOME=non-existing ENVCTL_API_KEY=\"$ENVCTL_API_KEY_\" npm run it --",
75
+ "e1": "cross-env CWD=../tt-core CI=true ENVCTL_HOME=non-existing ENVCTL_API_KEY=\"$ENVCTL_API_KEY_\" npm run it --",
77
76
  "e1-create": "npm run e1 -- create-ephemeral e1 --verbose",
78
77
  "e1-init": " npm run e1 -- init -reconfigure -upgrade -backend-config=key=e1",
79
78
  "e1-plan": " npm run e1 -- plan -var=env_size=min -var=env=e1 -out=plan",
@@ -81,15 +80,15 @@
81
80
  "e1-delete": "npm run e1 -- delete",
82
81
  "-tt-": "",
83
82
  "tt-desc": "deploy TT project from local machine",
84
- "tt": "CWD=../tt-gitops AWS_PROFILE=ac-tt-dev-deployer npm run it --",
83
+ "tt": "cross-env CWD=../tt-gitops AWS_PROFILE=ac-tt-dev-deployer npm run it --",
85
84
  "run-init": " npm run tt -- init -reconfigure -upgrade -backend-config=key=laxa1986 -var-file=versions.tfvars",
86
85
  "run-status": " npm run tt -- status",
87
86
  "run-apply": " npm run tt -- apply --auto-approve -var=env_size=min -var-file=versions.tfvars",
88
87
  "run-delete": " npm run tt -- delete"
89
88
  },
90
89
  "dependencies": {
91
- "commander": "^14.0.0",
92
90
  "@inquirer/prompts": "^8.0.0",
91
+ "commander": "^14.0.0",
93
92
  "update-notifier": "^7.3.1"
94
93
  },
95
94
  "devDependencies": {
@@ -97,9 +96,11 @@
97
96
  "@types/node": "^22.10.2",
98
97
  "@types/update-notifier": "^6.0.8",
99
98
  "@vitest/coverage-v8": "^4.0.0",
99
+ "cross-env": "^10.1.0",
100
100
  "eslint": "^9.22.0",
101
101
  "eslint-plugin-import": "^2.31.0",
102
102
  "husky": "^9.1.7",
103
+ "rimraf": "^6.1.3",
103
104
  "typescript": "^6.0.0",
104
105
  "typescript-eslint": "^8.8.1",
105
106
  "vitest": "^4.0.0"