hereya-cli 0.3.4 → 0.4.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
@@ -20,7 +20,7 @@ $ npm install -g hereya-cli
20
20
  $ hereya COMMAND
21
21
  running command...
22
22
  $ hereya (--version)
23
- hereya-cli/0.3.4 linux-x64 node-v20.13.1
23
+ hereya-cli/0.4.0 linux-x64 node-v20.13.1
24
24
  $ hereya --help [COMMAND]
25
25
  USAGE
26
26
  $ hereya COMMAND
@@ -31,6 +31,7 @@ USAGE
31
31
  <!-- commands -->
32
32
  * [`hereya add PACKAGE`](#hereya-add-package)
33
33
  * [`hereya bootstrap INFRASTRUCTURETYPE`](#hereya-bootstrap-infrastructuretype)
34
+ * [`hereya deploy`](#hereya-deploy)
34
35
  * [`hereya down`](#hereya-down)
35
36
  * [`hereya env`](#hereya-env)
36
37
  * [`hereya help [COMMAND]`](#hereya-help-command)
@@ -38,6 +39,7 @@ USAGE
38
39
  * [`hereya remote exec [PKGPATH]`](#hereya-remote-exec-pkgpath)
39
40
  * [`hereya remove PACKAGE`](#hereya-remove-package)
40
41
  * [`hereya run CMD`](#hereya-run-cmd)
42
+ * [`hereya undeploy`](#hereya-undeploy)
41
43
  * [`hereya up`](#hereya-up)
42
44
  * [`hereya workspace create NAME`](#hereya-workspace-create-name)
43
45
  * [`hereya workspace delete NAME`](#hereya-workspace-delete-name)
@@ -68,7 +70,7 @@ EXAMPLES
68
70
  $ hereya add cloudy/docker_postgres
69
71
  ```
70
72
 
71
- _See code: [src/commands/add/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/add/index.ts)_
73
+ _See code: [src/commands/add/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/add/index.ts)_
72
74
 
73
75
  ## `hereya bootstrap INFRASTRUCTURETYPE`
74
76
 
@@ -93,7 +95,28 @@ EXAMPLES
93
95
  $ hereya bootstrap local
94
96
  ```
95
97
 
96
- _See code: [src/commands/bootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/bootstrap/index.ts)_
98
+ _See code: [src/commands/bootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/bootstrap/index.ts)_
99
+
100
+ ## `hereya deploy`
101
+
102
+ Deploy a hereya project using the project deployment package
103
+
104
+ ```
105
+ USAGE
106
+ $ hereya deploy [--chdir <value>] [-w <value>]
107
+
108
+ FLAGS
109
+ -w, --workspace=<value> name of the workspace to deploy the packages for
110
+ --chdir=<value> directory to run command in
111
+
112
+ DESCRIPTION
113
+ Deploy a hereya project using the project deployment package
114
+
115
+ EXAMPLES
116
+ $ hereya deploy
117
+ ```
118
+
119
+ _See code: [src/commands/deploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/deploy/index.ts)_
97
120
 
98
121
  ## `hereya down`
99
122
 
@@ -114,7 +137,7 @@ EXAMPLES
114
137
  $ hereya down
115
138
  ```
116
139
 
117
- _See code: [src/commands/down/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/down/index.ts)_
140
+ _See code: [src/commands/down/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/down/index.ts)_
118
141
 
119
142
  ## `hereya env`
120
143
 
@@ -137,7 +160,7 @@ EXAMPLES
137
160
  $ hereya env -w dev
138
161
  ```
139
162
 
140
- _See code: [src/commands/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/env/index.ts)_
163
+ _See code: [src/commands/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/env/index.ts)_
141
164
 
142
165
  ## `hereya help [COMMAND]`
143
166
 
@@ -183,7 +206,7 @@ EXAMPLES
183
206
  $ hereya init myProject -w=defaultWorkspace --chdir=./myProject
184
207
  ```
185
208
 
186
- _See code: [src/commands/init/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/init/index.ts)_
209
+ _See code: [src/commands/init/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/init/index.ts)_
187
210
 
188
211
  ## `hereya remote exec [PKGPATH]`
189
212
 
@@ -191,13 +214,14 @@ remotely provision or destroy a package
191
214
 
192
215
  ```
193
216
  USAGE
194
- $ hereya remote exec [PKGPATH] [-o <value>]
217
+ $ hereya remote exec [PKGPATH] [-o <value>] [-s <value>]
195
218
 
196
219
  ARGUMENTS
197
220
  PKGPATH The path to the package to provision or destroy
198
221
 
199
222
  FLAGS
200
223
  -o, --output=<value> The path to store the output env in
224
+ -s, --source=<value> The source of the project to provision or destroy the package for
201
225
 
202
226
  DESCRIPTION
203
227
  remotely provision or destroy a package
@@ -206,7 +230,7 @@ EXAMPLES
206
230
  $ hereya remote exec
207
231
  ```
208
232
 
209
- _See code: [src/commands/remote/exec/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/remote/exec/index.ts)_
233
+ _See code: [src/commands/remote/exec/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/remote/exec/index.ts)_
210
234
 
211
235
  ## `hereya remove PACKAGE`
212
236
 
@@ -229,7 +253,7 @@ EXAMPLES
229
253
  $ hereya remove cloudy/docker_postgres
230
254
  ```
231
255
 
232
- _See code: [src/commands/remove/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/remove/index.ts)_
256
+ _See code: [src/commands/remove/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/remove/index.ts)_
233
257
 
234
258
  ## `hereya run CMD`
235
259
 
@@ -255,7 +279,28 @@ EXAMPLES
255
279
  $ hereya run -w uat -- node index.js
256
280
  ```
257
281
 
258
- _See code: [src/commands/run/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/run/index.ts)_
282
+ _See code: [src/commands/run/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/run/index.ts)_
283
+
284
+ ## `hereya undeploy`
285
+
286
+ Undeploy a hereya project by removing all resources.
287
+
288
+ ```
289
+ USAGE
290
+ $ hereya undeploy [--chdir <value>] [-w <value>]
291
+
292
+ FLAGS
293
+ -w, --workspace=<value> name of the workspace to undeploy the packages for
294
+ --chdir=<value> directory to run command in
295
+
296
+ DESCRIPTION
297
+ Undeploy a hereya project by removing all resources.
298
+
299
+ EXAMPLES
300
+ $ hereya undeploy
301
+ ```
302
+
303
+ _See code: [src/commands/undeploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/undeploy/index.ts)_
259
304
 
260
305
  ## `hereya up`
261
306
 
@@ -276,7 +321,7 @@ EXAMPLES
276
321
  $ hereya up
277
322
  ```
278
323
 
279
- _See code: [src/commands/up/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/up/index.ts)_
324
+ _See code: [src/commands/up/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/up/index.ts)_
280
325
 
281
326
  ## `hereya workspace create NAME`
282
327
 
@@ -296,7 +341,7 @@ EXAMPLES
296
341
  $ hereya workspace create dev
297
342
  ```
298
343
 
299
- _See code: [src/commands/workspace/create/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/workspace/create/index.ts)_
344
+ _See code: [src/commands/workspace/create/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/workspace/create/index.ts)_
300
345
 
301
346
  ## `hereya workspace delete NAME`
302
347
 
@@ -316,7 +361,7 @@ EXAMPLES
316
361
  $ hereya workspace delete dev
317
362
  ```
318
363
 
319
- _See code: [src/commands/workspace/delete/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/workspace/delete/index.ts)_
364
+ _See code: [src/commands/workspace/delete/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/workspace/delete/index.ts)_
320
365
 
321
366
  ## `hereya workspace env`
322
367
 
@@ -336,7 +381,7 @@ EXAMPLES
336
381
  $ hereya workspace env -w dev
337
382
  ```
338
383
 
339
- _See code: [src/commands/workspace/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/workspace/env/index.ts)_
384
+ _See code: [src/commands/workspace/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/workspace/env/index.ts)_
340
385
 
341
386
  ## `hereya workspace install PACKAGE`
342
387
 
@@ -362,7 +407,7 @@ EXAMPLES
362
407
  $ hereya workspace install hereya/aws-cognito
363
408
  ```
364
409
 
365
- _See code: [src/commands/workspace/install/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/workspace/install/index.ts)_
410
+ _See code: [src/commands/workspace/install/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/workspace/install/index.ts)_
366
411
 
367
412
  ## `hereya workspace uninstall PACKAGE`
368
413
 
@@ -388,5 +433,5 @@ EXAMPLES
388
433
  $ hereya workspace uninstall hereya/aws-cognito
389
434
  ```
390
435
 
391
- _See code: [src/commands/workspace/uninstall/index.ts](https://github.com/hereya/hereya-cli/blob/v0.3.4/src/commands/workspace/uninstall/index.ts)_
436
+ _See code: [src/commands/workspace/uninstall/index.ts](https://github.com/hereya/hereya-cli/blob/v0.4.0/src/commands/workspace/uninstall/index.ts)_
392
437
  <!-- commandsstop -->
@@ -61,6 +61,7 @@ export default class Add extends Command {
61
61
  package: args.package,
62
62
  parameters,
63
63
  project: config.project,
64
+ skipDeploy: true,
64
65
  workspace: config.workspace,
65
66
  });
66
67
  if (!provisionOutput.success) {
@@ -77,6 +78,7 @@ export default class Add extends Command {
77
78
  workspace: config.workspace,
78
79
  });
79
80
  await configManager.addPackage({
81
+ deploy: metadata.deploy,
80
82
  package: args.package,
81
83
  projectRootDir,
82
84
  });
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Deploy extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ chdir: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
+ workspace: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,108 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import path from 'node:path';
3
+ import { getBackend } from '../../backend/index.js';
4
+ import { destroyPackage, provisionPackage } from '../../infrastructure/index.js';
5
+ import { getConfigManager } from '../../lib/config/index.js';
6
+ import { getEnvManager } from '../../lib/env/index.js';
7
+ import { getParameterManager } from '../../lib/parameter/index.js';
8
+ import Up from '../up/index.js';
9
+ export default class Deploy extends Command {
10
+ static description = 'Deploy a hereya project using the project deployment package';
11
+ static examples = [
12
+ '<%= config.bin %> <%= command.id %>',
13
+ ];
14
+ static flags = {
15
+ chdir: Flags.string({
16
+ description: 'directory to run command in',
17
+ required: false,
18
+ }),
19
+ workspace: Flags.string({
20
+ char: 'w',
21
+ description: 'name of the workspace to deploy the packages for',
22
+ required: false,
23
+ }),
24
+ };
25
+ async run() {
26
+ const { flags } = await this.parse(Deploy);
27
+ const projectRootDir = path.resolve(flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR || process.cwd());
28
+ const configManager = getConfigManager();
29
+ const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
30
+ if (!loadConfigOutput.found) {
31
+ this.warn(`Project not initialized. Run 'hereya init' first.`);
32
+ return;
33
+ }
34
+ const { config } = loadConfigOutput;
35
+ const deployPackages = Object.keys(config.deploy ?? {});
36
+ const backend = await getBackend();
37
+ const savedStateOutput = await backend.getState({
38
+ project: config.project,
39
+ });
40
+ let savedPackages = [];
41
+ if (savedStateOutput.found) {
42
+ savedPackages = Object.keys(savedStateOutput.config.deploy ?? {});
43
+ }
44
+ const removedPackages = savedPackages.filter((packageName) => !deployPackages.includes(packageName));
45
+ const workspace = flags.workspace || config.workspace;
46
+ const getWorkspaceEnvOutput = await backend.getWorkspaceEnv({
47
+ project: config.project,
48
+ workspace,
49
+ });
50
+ if (!getWorkspaceEnvOutput.success) {
51
+ this.error(getWorkspaceEnvOutput.reason);
52
+ }
53
+ const { env: workspaceEnv } = getWorkspaceEnvOutput;
54
+ const parameterManager = getParameterManager();
55
+ const envManager = getEnvManager();
56
+ const { env: projectEnv } = await envManager.getProjectEnv({
57
+ markSecret: true,
58
+ projectRootDir,
59
+ workspace,
60
+ });
61
+ await Promise.all(removedPackages.map(async (packageName) => {
62
+ const { parameters } = await parameterManager.getPackageParameters({
63
+ package: packageName,
64
+ projectRootDir,
65
+ workspace,
66
+ });
67
+ const destroyOutput = await destroyPackage({
68
+ env: workspaceEnv,
69
+ package: packageName,
70
+ parameters,
71
+ project: config.project,
72
+ projectEnv,
73
+ projectRootDir,
74
+ workspace,
75
+ });
76
+ if (!destroyOutput.success) {
77
+ this.error(destroyOutput.reason);
78
+ }
79
+ this.log(`Package ${packageName} un-deployed successfully`);
80
+ }));
81
+ await Up.run(['--chdir', projectRootDir, '--workspace', workspace]);
82
+ const { env: newProjectEnv } = await envManager.getProjectEnv({
83
+ markSecret: true,
84
+ projectRootDir,
85
+ workspace,
86
+ });
87
+ await Promise.all(deployPackages.map(async (packageName) => {
88
+ const { parameters } = await parameterManager.getPackageParameters({
89
+ package: packageName,
90
+ projectRootDir,
91
+ workspace,
92
+ });
93
+ const provisionOutput = await provisionPackage({
94
+ env: workspaceEnv,
95
+ package: packageName,
96
+ parameters,
97
+ project: config.project,
98
+ projectEnv: newProjectEnv,
99
+ projectRootDir,
100
+ workspace,
101
+ });
102
+ if (!provisionOutput.success) {
103
+ this.error(provisionOutput.reason);
104
+ }
105
+ this.log(`Package ${packageName} deployed successfully`);
106
+ }));
107
+ }
108
+ }
@@ -7,6 +7,7 @@ export default class RemoteExec extends Command {
7
7
  static examples: string[];
8
8
  static flags: {
9
9
  output: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
10
+ source: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
10
11
  };
11
12
  run(): Promise<void>;
12
13
  }
@@ -1,4 +1,5 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
+ import path from 'node:path';
2
3
  import { getIac } from '../../../iac/index.js';
3
4
  import { getInfrastructure } from '../../../infrastructure/index.js';
4
5
  import { save } from '../../../lib/yaml-utils.js';
@@ -19,6 +20,11 @@ export default class RemoteExec extends Command {
19
20
  description: 'The path to store the output env in',
20
21
  required: false,
21
22
  }),
23
+ source: Flags.string({
24
+ char: 's',
25
+ description: 'The source of the project to provision or destroy the package for',
26
+ required: false,
27
+ }),
22
28
  };
23
29
  async run() {
24
30
  const { args, flags } = await this.parse(RemoteExec);
@@ -28,6 +34,11 @@ export default class RemoteExec extends Command {
28
34
  const iacType = process.env.HEREYA_IAC_TYPE;
29
35
  const destroy = process.env.HEREYA_DESTROY === 'true';
30
36
  const infraType = process.env.HEREYA_INFRA_TYPE;
37
+ const deploy = process.env.HEREYA_DEPLOY === 'true';
38
+ const source = flags.source ? path.resolve(flags.source) : '';
39
+ if (deploy && !source) {
40
+ return this.error('Deploy packages provisioning requires a source path');
41
+ }
31
42
  if (!id || !iacType || !infraType) {
32
43
  return this.error(`
33
44
  Missing required environment variables:
@@ -39,6 +50,12 @@ export default class RemoteExec extends Command {
39
50
  const input = {
40
51
  env: workspaceEnv, id, parameters, pkgPath: args.pkgPath || process.cwd(),
41
52
  };
53
+ if (deploy) {
54
+ input.parameters = {
55
+ ...input.parameters,
56
+ hereyaProjectRootDir: source,
57
+ };
58
+ }
42
59
  const iac$ = getIac({ type: iacType });
43
60
  if (!iac$.supported) {
44
61
  return this.error(iac$.reason);
@@ -31,7 +31,7 @@ export default class Remove extends Command {
31
31
  return;
32
32
  }
33
33
  const { config } = loadConfigOutput;
34
- if (!(args.package in (config.packages ?? {}))) {
34
+ if (!(args.package in (config.packages ?? {})) && !(args.package in (config.deploy ?? {}))) {
35
35
  this.warn(`Package ${args.package} not found in project.`);
36
36
  return;
37
37
  }
@@ -55,13 +55,16 @@ export default class Remove extends Command {
55
55
  package: args.package,
56
56
  parameters,
57
57
  project: config.project,
58
+ skipDeploy: true,
58
59
  workspace: config.workspace,
59
60
  });
60
61
  if (!destroyOutput.success) {
61
62
  this.error(destroyOutput.reason);
62
63
  }
63
64
  const { env, metadata } = destroyOutput;
64
- this.log(`Infrastructure resources for ${args.package} have been destroyed`);
65
+ if (!metadata.deploy) {
66
+ this.log(`Infrastructure resources for ${args.package} have been destroyed`);
67
+ }
65
68
  this.log('removing package env vars from project');
66
69
  const envManager = getEnvManager();
67
70
  await envManager.removeProjectEnv({
@@ -71,8 +74,9 @@ export default class Remove extends Command {
71
74
  workspace: config.workspace
72
75
  });
73
76
  await configManager.removePackage({
77
+ deploy: metadata.deploy,
74
78
  package: args.package,
75
- projectRootDir
79
+ projectRootDir,
76
80
  });
77
81
  const { config: newConfig } = await configManager.loadConfig({ projectRootDir });
78
82
  await backend.saveState(newConfig);
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Undeploy extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ chdir: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
+ workspace: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,75 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import path from 'node:path';
3
+ import { getBackend } from '../../backend/index.js';
4
+ import { destroyPackage } from '../../infrastructure/index.js';
5
+ import { getConfigManager } from '../../lib/config/index.js';
6
+ import { getEnvManager } from '../../lib/env/index.js';
7
+ import { getParameterManager } from '../../lib/parameter/index.js';
8
+ import Down from '../down/index.js';
9
+ export default class Undeploy extends Command {
10
+ static description = 'Undeploy a hereya project by removing all resources.';
11
+ static examples = [
12
+ '<%= config.bin %> <%= command.id %>',
13
+ ];
14
+ static flags = {
15
+ chdir: Flags.string({
16
+ description: 'directory to run command in',
17
+ required: false,
18
+ }),
19
+ workspace: Flags.string({
20
+ char: 'w',
21
+ description: 'name of the workspace to undeploy the packages for',
22
+ required: false,
23
+ }),
24
+ };
25
+ async run() {
26
+ const { flags } = await this.parse(Undeploy);
27
+ const projectRootDir = path.resolve(flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR || process.cwd());
28
+ const configManager = getConfigManager();
29
+ const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
30
+ if (!loadConfigOutput.found) {
31
+ this.warn(`Project not initialized. Run 'hereya init' first.`);
32
+ return;
33
+ }
34
+ const { config } = loadConfigOutput;
35
+ const deployPackages = Object.keys(config.deploy ?? {});
36
+ const workspace = flags.workspace || config.workspace;
37
+ const backend = await getBackend();
38
+ const getWorkspaceEnvOutput = await backend.getWorkspaceEnv({
39
+ project: config.project,
40
+ workspace,
41
+ });
42
+ if (!getWorkspaceEnvOutput.success) {
43
+ this.error(getWorkspaceEnvOutput.reason);
44
+ }
45
+ const { env: workspaceEnv } = getWorkspaceEnvOutput;
46
+ const parameterManager = getParameterManager();
47
+ const envManager = getEnvManager();
48
+ const { env: projectEnv } = await envManager.getProjectEnv({
49
+ markSecret: true,
50
+ projectRootDir,
51
+ workspace,
52
+ });
53
+ await Promise.all(deployPackages.map(async (packageName) => {
54
+ const { parameters } = await parameterManager.getPackageParameters({
55
+ package: packageName,
56
+ projectRootDir,
57
+ workspace,
58
+ });
59
+ const destroyOutput = await destroyPackage({
60
+ env: workspaceEnv,
61
+ package: packageName,
62
+ parameters,
63
+ project: config.project,
64
+ projectEnv,
65
+ projectRootDir,
66
+ workspace,
67
+ });
68
+ if (!destroyOutput.success) {
69
+ this.error(destroyOutput.reason);
70
+ }
71
+ this.log(`Package ${packageName} un-deployed successfully`);
72
+ }));
73
+ await Down.run(['--chdir', projectRootDir, '--workspace', workspace]);
74
+ }
75
+ }
@@ -91,7 +91,7 @@ export default class Up extends Command {
91
91
  return { env, metadata, packageName };
92
92
  }));
93
93
  const envManager = getEnvManager();
94
- for (const { env, metadata, packageName } of removed) {
94
+ for (const { env, metadata } of removed) {
95
95
  // eslint-disable-next-line no-await-in-loop
96
96
  await Promise.all([
97
97
  envManager.removeProjectEnv({
@@ -100,10 +100,6 @@ export default class Up extends Command {
100
100
  projectRootDir,
101
101
  workspace,
102
102
  }),
103
- configManager.removePackage({
104
- package: packageName,
105
- projectRootDir,
106
- })
107
103
  ]);
108
104
  }
109
105
  for (const { env, metadata } of added) {
@@ -1,11 +1,15 @@
1
- import { BootstrapInput, DestroyInput, DestroyOutput, Infrastructure, ProvisionInput, ProvisionOutput, ResolveEnvInput, ResolveEnvOutput, SaveEnvInput, SaveEnvOutput } from './common.js';
1
+ import { BootstrapInput, DeployInput, DeployOutput, DestroyInput, DestroyOutput, Infrastructure, ProvisionInput, ProvisionOutput, ResolveEnvInput, ResolveEnvOutput, SaveEnvInput, SaveEnvOutput, UndeployInput, UndeployOutput } from './common.js';
2
2
  export declare class AwsInfrastructure implements Infrastructure {
3
3
  bootstrap(_: BootstrapInput): Promise<void>;
4
+ deploy(input: DeployInput): Promise<DeployOutput>;
4
5
  destroy(input: DestroyInput): Promise<DestroyOutput>;
5
6
  provision(input: ProvisionInput): Promise<ProvisionOutput>;
6
7
  resolveEnv(input: ResolveEnvInput): Promise<ResolveEnvOutput>;
7
8
  saveEnv(input: SaveEnvInput): Promise<SaveEnvOutput>;
9
+ undeploy(input: UndeployInput): Promise<UndeployOutput>;
8
10
  private getEnv;
11
+ private getFilesToUpload;
9
12
  private removeEnv;
10
- private runCdkBuild;
13
+ private runCodeBuild;
14
+ private uploadProjectFiles;
11
15
  }
@@ -1,7 +1,14 @@
1
1
  import { BatchGetBuildsCommand, CodeBuildClient, StartBuildCommand } from '@aws-sdk/client-codebuild';
2
+ import { DeleteObjectsCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
2
3
  import { DeleteParameterCommand, GetParameterCommand, PutParameterCommand, SSMClient } from '@aws-sdk/client-ssm';
3
4
  import { GetCallerIdentityCommand, STSClient } from '@aws-sdk/client-sts';
5
+ import { glob } from 'glob';
6
+ import ignore from 'ignore';
7
+ import { randomUUID } from 'node:crypto';
8
+ import fs from 'node:fs/promises';
9
+ import path from 'node:path';
4
10
  import { IacType } from '../iac/common.js';
11
+ import { fileExists, getAnyPath } from '../lib/filesystem.js';
5
12
  import { runShell } from '../lib/shell.js';
6
13
  import { InfrastructureType } from './common.js';
7
14
  import { provisionPackage } from './index.js';
@@ -17,9 +24,42 @@ export class AwsInfrastructure {
17
24
  throw new Error(output.reason);
18
25
  }
19
26
  }
27
+ async deploy(input) {
28
+ let files = [];
29
+ let s3Bucket = '';
30
+ let s3Client = new S3Client({});
31
+ let s3Key = '';
32
+ try {
33
+ ({ files, s3Bucket, s3Client, s3Key } = await this.uploadProjectFiles(input));
34
+ input.parameters = {
35
+ ...input.parameters,
36
+ hereyaProjectEnv: JSON.stringify(input.projectEnv ?? {}),
37
+ };
38
+ const output = await this.runCodeBuild({
39
+ ...input,
40
+ deploy: true,
41
+ sourceS3Key: s3Key
42
+ });
43
+ if (!output.success) {
44
+ return output;
45
+ }
46
+ const env = await this.getEnv(input.id);
47
+ return { env, success: true };
48
+ }
49
+ finally {
50
+ if (s3Key && files.length > 0) {
51
+ await s3Client.send(new DeleteObjectsCommand({
52
+ Bucket: s3Bucket,
53
+ Delete: {
54
+ Objects: files.map(file => ({ Key: `${s3Key}/${file}` }))
55
+ }
56
+ }));
57
+ }
58
+ }
59
+ }
20
60
  async destroy(input) {
21
61
  const env = await this.getEnv(input.id);
22
- const output = await this.runCdkBuild({ ...input, destroy: true });
62
+ const output = await this.runCodeBuild({ ...input, destroy: true });
23
63
  if (!output.success) {
24
64
  return output;
25
65
  }
@@ -27,7 +67,7 @@ export class AwsInfrastructure {
27
67
  return { env, success: true };
28
68
  }
29
69
  async provision(input) {
30
- const output = await this.runCdkBuild(input);
70
+ const output = await this.runCodeBuild(input);
31
71
  if (!output.success) {
32
72
  return output;
33
73
  }
@@ -42,7 +82,10 @@ export class AwsInfrastructure {
42
82
  Name: input.value,
43
83
  WithDecryption: true,
44
84
  }));
45
- return { value: response.Parameter?.Value ?? input.value };
85
+ return {
86
+ isSecret: response.Parameter?.Type === 'SecureString',
87
+ value: response.Parameter?.Value ?? input.value
88
+ };
46
89
  }
47
90
  return { value: input.value };
48
91
  }
@@ -63,6 +106,46 @@ export class AwsInfrastructure {
63
106
  return { reason: error.message, success: false };
64
107
  }
65
108
  }
109
+ async undeploy(input) {
110
+ let files = [];
111
+ let s3Bucket = '';
112
+ let s3Client = new S3Client({});
113
+ let s3Key = '';
114
+ let env = {};
115
+ try {
116
+ env = await this.getEnv(input.id);
117
+ }
118
+ catch (error) {
119
+ console.log(`Could not get env for ${input.id}: ${error.message}. Continuing with undeployment...`);
120
+ }
121
+ try {
122
+ ({ files, s3Bucket, s3Client, s3Key } = await this.uploadProjectFiles(input));
123
+ input.parameters = {
124
+ ...input.parameters,
125
+ hereyaProjectEnv: JSON.stringify(input.projectEnv ?? {}),
126
+ };
127
+ const output = await this.runCodeBuild({
128
+ ...input,
129
+ deploy: true,
130
+ destroy: true,
131
+ sourceS3Key: s3Key
132
+ });
133
+ if (!output.success) {
134
+ return output;
135
+ }
136
+ return { env, success: true };
137
+ }
138
+ finally {
139
+ if (s3Key && files.length > 0) {
140
+ await s3Client.send(new DeleteObjectsCommand({
141
+ Bucket: s3Bucket,
142
+ Delete: {
143
+ Objects: files.map(file => ({ Key: `${s3Key}/${file}` }))
144
+ }
145
+ }));
146
+ }
147
+ }
148
+ }
66
149
  async getEnv(id) {
67
150
  const ssmClient = new SSMClient({});
68
151
  const ssmParameterName = `/hereya/${id}`;
@@ -71,6 +154,16 @@ export class AwsInfrastructure {
71
154
  }));
72
155
  return JSON.parse(ssmParameter.Parameter?.Value ?? '{}');
73
156
  }
157
+ async getFilesToUpload(rootDir) {
158
+ const ig = ignore.default();
159
+ const ignoreFilePath = await getAnyPath(`${rootDir}/.hereyaignore`, `${rootDir}/.gitignore`);
160
+ if (await fileExists(ignoreFilePath)) {
161
+ const ignoreFileContent = await fs.readFile(ignoreFilePath, 'utf8');
162
+ ig.add(ignoreFileContent);
163
+ }
164
+ const files = glob.sync('**/*', { cwd: rootDir, nodir: true });
165
+ return files.filter(file => !ig.ignores(file));
166
+ }
74
167
  async removeEnv(id) {
75
168
  const ssmClient = new SSMClient({});
76
169
  const ssmParameterName = `/hereya/${id}`;
@@ -78,7 +171,7 @@ export class AwsInfrastructure {
78
171
  Name: ssmParameterName,
79
172
  }));
80
173
  }
81
- async runCdkBuild(input) {
174
+ async runCodeBuild(input) {
82
175
  const codebuildClient = new CodeBuildClient({});
83
176
  let codebuildProjectName = '';
84
177
  switch (input.iacType) {
@@ -127,6 +220,16 @@ export class AwsInfrastructure {
127
220
  type: 'PLAINTEXT',
128
221
  value: input.destroy ? 'true' : '',
129
222
  },
223
+ {
224
+ name: 'HEREYA_DEPLOY',
225
+ type: 'PLAINTEXT',
226
+ value: input.deploy ? 'true' : '',
227
+ },
228
+ {
229
+ name: 'HEREYA_PROJECT_S3_KEY',
230
+ type: 'PLAINTEXT',
231
+ value: input.deploy ? input.sourceS3Key : '',
232
+ }
130
233
  ],
131
234
  projectName: codebuildProjectName,
132
235
  }));
@@ -152,4 +255,19 @@ export class AwsInfrastructure {
152
255
  }
153
256
  return { success: true };
154
257
  }
258
+ async uploadProjectFiles(input) {
259
+ const s3Key = `${input.id}/${randomUUID()}`;
260
+ const s3Bucket = 'hereya-projects-source-code';
261
+ const files = await this.getFilesToUpload(input.projectRootDir);
262
+ const s3Client = new S3Client({});
263
+ await Promise.all(files.map(async (file) => {
264
+ console.log(`Uploading ${file} to s3://${s3Bucket}/${s3Key}`);
265
+ await s3Client.send(new PutObjectCommand({
266
+ Body: await fs.readFile(path.join(input.projectRootDir, file)),
267
+ Bucket: s3Bucket,
268
+ Key: `${s3Key}/${file}`,
269
+ }));
270
+ }));
271
+ return { files, s3Bucket, s3Client, s3Key };
272
+ }
155
273
  }
@@ -7,10 +7,12 @@ export declare enum InfrastructureType {
7
7
  }
8
8
  export interface Infrastructure {
9
9
  bootstrap(input: BootstrapInput): Promise<void>;
10
+ deploy(input: DeployInput): Promise<DeployOutput>;
10
11
  destroy(input: DestroyInput): Promise<DestroyOutput>;
11
12
  provision(input: ProvisionInput): Promise<ProvisionOutput>;
12
13
  resolveEnv(input: ResolveEnvInput): Promise<ResolveEnvOutput>;
13
14
  saveEnv(input: SaveEnvInput): Promise<SaveEnvOutput>;
15
+ undeploy(input: UndeployInput): Promise<UndeployOutput>;
14
16
  }
15
17
  export type BootstrapInput = {
16
18
  force?: boolean;
@@ -39,10 +41,20 @@ export type ProvisionOutput = {
39
41
  };
40
42
  export type DestroyInput = ProvisionInput;
41
43
  export type DestroyOutput = ProvisionOutput;
44
+ export type DeployInput = {
45
+ projectEnv: {
46
+ [key: string]: string;
47
+ };
48
+ projectRootDir: string;
49
+ } & ProvisionInput;
50
+ export type DeployOutput = ProvisionOutput;
51
+ export type UndeployInput = DeployInput;
52
+ export type UndeployOutput = DeployOutput;
42
53
  export type ResolveEnvInput = {
43
54
  value: string;
44
55
  };
45
56
  export type ResolveEnvOutput = {
57
+ isSecret?: boolean;
46
58
  value: string;
47
59
  };
48
60
  export type SaveEnvInput = {
@@ -19,6 +19,11 @@ export type ProvisionPackageInput = {
19
19
  [key: string]: string;
20
20
  };
21
21
  project?: string;
22
+ projectEnv?: {
23
+ [key: string]: string;
24
+ };
25
+ projectRootDir?: string;
26
+ skipDeploy?: boolean;
22
27
  workspace?: string;
23
28
  };
24
29
  export type ProvisionPackageOutput = {
@@ -36,8 +36,24 @@ export async function destroyPackage(input) {
36
36
  if (!infrastructure$.supported) {
37
37
  return { reason: infrastructure$.reason, success: false };
38
38
  }
39
+ if (metadata.deploy && input.skipDeploy) {
40
+ console.log(`Skipping un-deployment of ${input.package}...`);
41
+ return { env: {}, metadata, success: true };
42
+ }
39
43
  const { infrastructure } = infrastructure$;
40
- const destroyOutput = await infrastructure.destroy({
44
+ const destroyOutput = metadata.deploy ? await infrastructure.undeploy({
45
+ canonicalName,
46
+ env: input.env,
47
+ iacType: metadata.iac,
48
+ id: ((input.project || input.workspace) ? [input.project, input.workspace, canonicalName] : [canonicalName])
49
+ .filter(Boolean).join('')
50
+ .replaceAll(/[^\dA-Za-z]/g, ''),
51
+ parameters: input.parameters,
52
+ pkgName: input.package,
53
+ pkgUrl: packageUri,
54
+ projectEnv: input.projectEnv ?? {},
55
+ projectRootDir: input.projectRootDir,
56
+ }) : await infrastructure.destroy({
41
57
  canonicalName,
42
58
  env: input.env,
43
59
  iacType: metadata.iac,
@@ -63,8 +79,24 @@ export async function provisionPackage(input) {
63
79
  if (!infrastructure$.supported) {
64
80
  return { reason: infrastructure$.reason, success: false };
65
81
  }
82
+ if (metadata.deploy && input.skipDeploy) {
83
+ console.log(`Skipping deployment of ${input.package}...`);
84
+ return { env: {}, metadata, success: true };
85
+ }
66
86
  const { infrastructure } = infrastructure$;
67
- const provisionOutput = await infrastructure.provision({
87
+ const provisionOutput = metadata.deploy ? await infrastructure.deploy({
88
+ canonicalName,
89
+ env: input.env,
90
+ iacType: metadata.iac,
91
+ id: ((input.project || input.workspace) ? [input.project, input.workspace, canonicalName] : [canonicalName])
92
+ .filter(Boolean).join('')
93
+ .replaceAll(/[^\dA-Za-z]/g, ''),
94
+ parameters: input.parameters,
95
+ pkgName: input.package,
96
+ pkgUrl: packageUri,
97
+ projectEnv: input.projectEnv ?? {},
98
+ projectRootDir: input.projectRootDir,
99
+ }) : await infrastructure.provision({
68
100
  canonicalName,
69
101
  env: input.env,
70
102
  iacType: metadata.iac,
@@ -1,6 +1,7 @@
1
- import { Infrastructure, ProvisionInput, ProvisionOutput, SaveEnvInput, SaveEnvOutput } from './common.js';
1
+ import { DeployInput, DeployOutput, Infrastructure, ProvisionInput, ProvisionOutput, SaveEnvInput, SaveEnvOutput, UndeployInput, UndeployOutput } from './common.js';
2
2
  export declare class LocalInfrastructure implements Infrastructure {
3
3
  bootstrap(): Promise<void>;
4
+ deploy(input: DeployInput): Promise<DeployOutput>;
4
5
  destroy(input: ProvisionInput): Promise<ProvisionOutput>;
5
6
  provision(input: ProvisionInput): Promise<ProvisionOutput>;
6
7
  resolveEnv(input: {
@@ -9,6 +10,7 @@ export declare class LocalInfrastructure implements Infrastructure {
9
10
  value: string;
10
11
  }>;
11
12
  saveEnv(input: SaveEnvInput): Promise<SaveEnvOutput>;
13
+ undeploy(input: UndeployInput): Promise<UndeployOutput>;
12
14
  private download;
13
15
  private isNotEmpty;
14
16
  }
@@ -7,6 +7,14 @@ export class LocalInfrastructure {
7
7
  async bootstrap() {
8
8
  console.log('Bootstrapping local infrastructure');
9
9
  }
10
+ async deploy(input) {
11
+ input.parameters = {
12
+ ...input.parameters,
13
+ hereyaProjectEnv: JSON.stringify(input.projectEnv ?? {}),
14
+ hereyaProjectRootDir: input.projectRootDir
15
+ };
16
+ return this.provision(input);
17
+ }
10
18
  async destroy(input) {
11
19
  // noinspection DuplicatedCode
12
20
  const destPath = path.join(os.homedir(), '.hereya', input.id, input.canonicalName);
@@ -56,6 +64,14 @@ export class LocalInfrastructure {
56
64
  console.log(`Saving env to ${input.id}`);
57
65
  return { success: true };
58
66
  }
67
+ async undeploy(input) {
68
+ input.parameters = {
69
+ ...input.parameters,
70
+ hereyaProjectEnv: JSON.stringify(input.projectEnv ?? {}),
71
+ hereyaProjectRootDir: input.projectRootDir
72
+ };
73
+ return this.destroy(input);
74
+ }
59
75
  async download(pkgUrl, destPath) {
60
76
  if (await this.isNotEmpty(destPath)) {
61
77
  console.log(`Package already downloaded at ${destPath}`);
@@ -15,6 +15,11 @@ export type LoadConfigOutput = {
15
15
  found: true;
16
16
  };
17
17
  export interface Config {
18
+ deploy?: {
19
+ [key: string]: {
20
+ version: string;
21
+ };
22
+ };
18
23
  packages?: {
19
24
  [key: string]: {
20
25
  version: string;
@@ -28,6 +33,7 @@ export interface SaveConfigInput {
28
33
  projectRootDir?: string;
29
34
  }
30
35
  export type AddPackageInput = {
36
+ deploy?: boolean;
31
37
  package: string;
32
38
  projectRootDir?: string;
33
39
  };
@@ -6,12 +6,21 @@ export class SimpleConfigManager {
6
6
  const { config } = await this.loadConfig({ projectRootDir: input.projectRootDir });
7
7
  await yaml.save({
8
8
  ...config,
9
- packages: {
10
- ...config.packages,
11
- [input.package]: {
12
- version: ''
9
+ ...(input.deploy ? {
10
+ deploy: {
11
+ ...config.deploy,
12
+ [input.package]: {
13
+ version: '',
14
+ }
13
15
  }
14
- },
16
+ } : {
17
+ packages: {
18
+ ...config.packages,
19
+ [input.package]: {
20
+ version: '',
21
+ }
22
+ }
23
+ }),
15
24
  }, await this.getConfigPath(input.projectRootDir));
16
25
  }
17
26
  async loadConfig(input) {
@@ -25,9 +34,16 @@ export class SimpleConfigManager {
25
34
  async removePackage(input) {
26
35
  const { config } = await this.loadConfig({ projectRootDir: input.projectRootDir });
27
36
  const newPackages = { ...config.packages };
28
- delete newPackages[input.package];
37
+ const newDeploy = { ...config.deploy };
38
+ if (input.deploy) {
39
+ delete newDeploy[input.package];
40
+ }
41
+ else {
42
+ delete newPackages[input.package];
43
+ }
29
44
  await yaml.save({
30
45
  ...config,
46
+ deploy: newDeploy,
31
47
  packages: newPackages,
32
48
  }, await this.getConfigPath(input.projectRootDir));
33
49
  }
@@ -17,6 +17,7 @@ export type AddEnvInput = {
17
17
  };
18
18
  export type RemoveEnvInput = AddEnvInput;
19
19
  export type GetProjectEnvInput = {
20
+ markSecret?: boolean;
20
21
  projectRootDir?: string;
21
22
  workspace: string;
22
23
  };
@@ -17,7 +17,7 @@ export class EnvManager {
17
17
  if (!found) {
18
18
  return { env: {} };
19
19
  }
20
- const resolvedEnv = await resolveEnvValues(env);
20
+ const resolvedEnv = await resolveEnvValues(env, { markSecret: input.markSecret });
21
21
  return { env: resolvedEnv };
22
22
  }
23
23
  async removeProjectEnv(input) {
@@ -3,6 +3,8 @@ export declare function logEnv(env: {
3
3
  }, logFn?: (_: string) => void): void;
4
4
  export declare function resolveEnvValues(env: {
5
5
  [key: string]: string;
6
+ }, options?: {
7
+ markSecret?: boolean;
6
8
  }): Promise<{
7
9
  [key: string]: string;
8
10
  }>;
@@ -4,17 +4,20 @@ export function logEnv(env, logFn = console.log) {
4
4
  logFn(`${key}=${value}`);
5
5
  }
6
6
  }
7
- export async function resolveEnvValues(env) {
7
+ export async function resolveEnvValues(env, options = {}) {
8
8
  return Object.fromEntries(await Promise.all(Object.entries(env)
9
9
  .map(async ([key, value]) => {
10
10
  const infraType = value.split(':')[0];
11
- const infra$ = await getInfrastructure({ type: infraType });
11
+ const infra$ = getInfrastructure({ type: infraType });
12
12
  if (!infra$.supported) {
13
13
  throw new Error(infra$.reason);
14
14
  }
15
15
  const { infrastructure } = infra$;
16
16
  const valueWithoutInfra = value.split(':').slice(1).join(':');
17
- const { value: resolvedValue } = await infrastructure.resolveEnv({ value: valueWithoutInfra });
18
- return [key, resolvedValue];
17
+ const { isSecret, value: resolvedValue } = await infrastructure.resolveEnv({
18
+ value: valueWithoutInfra
19
+ });
20
+ const finalValue = options.markSecret && isSecret ? `secret://${resolvedValue}` : resolvedValue;
21
+ return [key, finalValue];
19
22
  })));
20
23
  }
@@ -1 +1,2 @@
1
1
  export declare function getAnyPath(...candidates: string[]): Promise<string>;
2
+ export declare function fileExists(filePath: string): Promise<boolean>;
@@ -13,3 +13,12 @@ export async function getAnyPath(...candidates) {
13
13
  };
14
14
  return checkAccess(0);
15
15
  }
16
+ export async function fileExists(filePath) {
17
+ try {
18
+ await access(filePath, constants.F_OK);
19
+ return true;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
@@ -19,12 +19,15 @@ export type ResolvePackageOutput = {
19
19
  reason: string;
20
20
  };
21
21
  export declare const PackageMetadata: z.ZodObject<{
22
+ deploy: z.ZodOptional<z.ZodBoolean>;
22
23
  iac: z.ZodNativeEnum<typeof IacType>;
23
24
  infra: z.ZodNativeEnum<typeof InfrastructureType>;
24
25
  }, "strip", z.ZodTypeAny, {
25
26
  iac: IacType;
26
27
  infra: InfrastructureType;
28
+ deploy?: boolean | undefined;
27
29
  }, {
28
30
  iac: IacType;
29
31
  infra: InfrastructureType;
32
+ deploy?: boolean | undefined;
30
33
  }>;
@@ -40,6 +40,7 @@ export function getPackageCanonicalName(packageName) {
40
40
  return packageName.replace('/', '-');
41
41
  }
42
42
  export const PackageMetadata = z.object({
43
+ deploy: z.boolean().optional(),
43
44
  iac: z.nativeEnum(IacType),
44
45
  infra: z.nativeEnum(InfrastructureType),
45
46
  });
@@ -87,6 +87,48 @@
87
87
  "index.js"
88
88
  ]
89
89
  },
90
+ "deploy": {
91
+ "aliases": [],
92
+ "args": {},
93
+ "description": "Deploy a hereya project using the project deployment package",
94
+ "examples": [
95
+ "<%= config.bin %> <%= command.id %>"
96
+ ],
97
+ "flags": {
98
+ "chdir": {
99
+ "description": "directory to run command in",
100
+ "name": "chdir",
101
+ "required": false,
102
+ "hasDynamicHelp": false,
103
+ "multiple": false,
104
+ "type": "option"
105
+ },
106
+ "workspace": {
107
+ "char": "w",
108
+ "description": "name of the workspace to deploy the packages for",
109
+ "name": "workspace",
110
+ "required": false,
111
+ "hasDynamicHelp": false,
112
+ "multiple": false,
113
+ "type": "option"
114
+ }
115
+ },
116
+ "hasDynamicHelp": false,
117
+ "hiddenAliases": [],
118
+ "id": "deploy",
119
+ "pluginAlias": "hereya-cli",
120
+ "pluginName": "hereya-cli",
121
+ "pluginType": "core",
122
+ "strict": true,
123
+ "enableJsonFlag": false,
124
+ "isESM": true,
125
+ "relativePath": [
126
+ "dist",
127
+ "commands",
128
+ "deploy",
129
+ "index.js"
130
+ ]
131
+ },
90
132
  "down": {
91
133
  "aliases": [],
92
134
  "args": {},
@@ -309,6 +351,48 @@
309
351
  "index.js"
310
352
  ]
311
353
  },
354
+ "undeploy": {
355
+ "aliases": [],
356
+ "args": {},
357
+ "description": "Undeploy a hereya project by removing all resources.",
358
+ "examples": [
359
+ "<%= config.bin %> <%= command.id %>"
360
+ ],
361
+ "flags": {
362
+ "chdir": {
363
+ "description": "directory to run command in",
364
+ "name": "chdir",
365
+ "required": false,
366
+ "hasDynamicHelp": false,
367
+ "multiple": false,
368
+ "type": "option"
369
+ },
370
+ "workspace": {
371
+ "char": "w",
372
+ "description": "name of the workspace to undeploy the packages for",
373
+ "name": "workspace",
374
+ "required": false,
375
+ "hasDynamicHelp": false,
376
+ "multiple": false,
377
+ "type": "option"
378
+ }
379
+ },
380
+ "hasDynamicHelp": false,
381
+ "hiddenAliases": [],
382
+ "id": "undeploy",
383
+ "pluginAlias": "hereya-cli",
384
+ "pluginName": "hereya-cli",
385
+ "pluginType": "core",
386
+ "strict": true,
387
+ "enableJsonFlag": false,
388
+ "isESM": true,
389
+ "relativePath": [
390
+ "dist",
391
+ "commands",
392
+ "undeploy",
393
+ "index.js"
394
+ ]
395
+ },
312
396
  "up": {
313
397
  "aliases": [],
314
398
  "args": {},
@@ -373,6 +457,15 @@
373
457
  "hasDynamicHelp": false,
374
458
  "multiple": false,
375
459
  "type": "option"
460
+ },
461
+ "source": {
462
+ "char": "s",
463
+ "description": "The source of the project to provision or destroy the package for",
464
+ "name": "source",
465
+ "required": false,
466
+ "hasDynamicHelp": false,
467
+ "multiple": false,
468
+ "type": "option"
376
469
  }
377
470
  },
378
471
  "hasDynamicHelp": false,
@@ -606,5 +699,5 @@
606
699
  ]
607
700
  }
608
701
  },
609
- "version": "0.3.4"
702
+ "version": "0.4.0"
610
703
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hereya-cli",
3
3
  "description": "Developer's Package Manager for Seamless Infrastructure Integration.",
4
- "version": "0.3.4",
4
+ "version": "0.4.0",
5
5
  "author": "The Hereya team",
6
6
  "bin": {
7
7
  "hereya": "./bin/run.js"
@@ -10,13 +10,17 @@
10
10
  "dependencies": {
11
11
  "@aws-sdk/client-cloudformation": "^3.577.0",
12
12
  "@aws-sdk/client-codebuild": "^3.583.0",
13
+ "@aws-sdk/client-s3": "^3.583.0",
13
14
  "@aws-sdk/client-ssm": "^3.583.0",
14
15
  "@aws-sdk/client-sts": "^3.582.0",
16
+ "@aws-sdk/lib-storage": "^3.583.0",
15
17
  "@esm2cjs/execa": "^6.1.1-cjs.1",
16
18
  "@oclif/core": "^3",
17
19
  "@oclif/plugin-help": "^6",
18
20
  "@oclif/plugin-plugins": "^5",
19
21
  "@octokit/rest": "^20.1.1",
22
+ "glob": "^10.4.1",
23
+ "ignore": "^5.3.1",
20
24
  "simple-git": "^3.24.0",
21
25
  "yaml": "^2.4.2",
22
26
  "zod": "^3.23.8"
@@ -73,7 +77,7 @@
73
77
  },
74
78
  "repository": "hereya/hereya-cli",
75
79
  "scripts": {
76
- "generate": "oclif generate command $COMMAND && shx mkdir src/commands/$COMMAND && shx mv src/commands/$COMMAND.ts src/commands/$COMMAND/index.ts && shx mv test/commands/$COMMAND.test.ts src/commands/$COMMAND/index.test.ts && shx rm -rf test",
80
+ "generate": "npx oclif generate command $COMMAND && shx mkdir src/commands/$COMMAND && shx mv src/commands/$COMMAND.ts src/commands/$COMMAND/index.ts && shx mv test/commands/$COMMAND.test.ts src/commands/$COMMAND/index.test.ts && shx rm -rf test",
77
81
  "dev": "./bin/dev.js",
78
82
  "build": "shx rm -rf dist && tsc -b",
79
83
  "lint": "eslint .",