hereya-cli 0.13.0 → 0.14.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.
@@ -1,11 +1,11 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
+ import { Listr, ListrLogLevels, ListrLogger } from 'listr2';
2
3
  import { getBackend } from '../../backend/index.js';
3
4
  import { destroyPackage } from '../../infrastructure/index.js';
4
5
  import { getConfigManager } from '../../lib/config/index.js';
5
6
  import { getEnvManager } from '../../lib/env/index.js';
6
- import { getLogger } from '../../lib/log.js';
7
7
  import { getParameterManager } from '../../lib/parameter/index.js';
8
- import { setDebug } from '../../lib/shell.js';
8
+ import { delay, setDebug } from '../../lib/shell.js';
9
9
  export default class Remove extends Command {
10
10
  static args = {
11
11
  package: Args.string({
@@ -28,67 +28,120 @@ export default class Remove extends Command {
28
28
  async run() {
29
29
  const { args, flags } = await this.parse(Remove);
30
30
  setDebug(flags.debug);
31
- const logger = getLogger();
32
31
  const projectRootDir = flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR;
33
- const configManager = getConfigManager();
34
- const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
35
- if (!loadConfigOutput.found) {
36
- this.warn(`Project not initialized. Run 'hereya init' first.`);
37
- return;
32
+ const myLogger = new ListrLogger({ useIcons: false });
33
+ const task = new Listr([
34
+ {
35
+ async task(ctx, task) {
36
+ return task.newListr([
37
+ {
38
+ async task(ctx) {
39
+ const configManager = getConfigManager();
40
+ const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
41
+ if (!loadConfigOutput.found) {
42
+ throw new Error("Project not initialized. Run 'hereya init' first.");
43
+ }
44
+ ctx.configOutput = loadConfigOutput;
45
+ const { config } = loadConfigOutput;
46
+ if (!(args.package in (config.packages ?? {})) && !(args.package in (config.deploy ?? {}))) {
47
+ throw new Error(`Package ${args.package} not found in project.`);
48
+ }
49
+ await delay(500);
50
+ },
51
+ title: 'Loading project config',
52
+ },
53
+ {
54
+ async task(ctx) {
55
+ const backend = await getBackend();
56
+ const getWorkspaceEnvOutput = await backend.getWorkspaceEnv({
57
+ project: ctx.configOutput.config.project,
58
+ workspace: ctx.configOutput.config.workspace,
59
+ });
60
+ if (!getWorkspaceEnvOutput.success) {
61
+ throw new Error(getWorkspaceEnvOutput.reason);
62
+ }
63
+ ctx.workspaceEnvOutput = getWorkspaceEnvOutput;
64
+ await delay(500);
65
+ },
66
+ title: 'Loading workspace environment variables',
67
+ },
68
+ {
69
+ async task(ctx) {
70
+ const parameterManager = getParameterManager();
71
+ const parametersOutput = await parameterManager.getPackageParameters({
72
+ package: args.package,
73
+ projectRootDir,
74
+ workspace: ctx.configOutput.config.workspace,
75
+ });
76
+ ctx.parametersOutput = parametersOutput;
77
+ await delay(500);
78
+ },
79
+ title: 'Resolving package parameters',
80
+ },
81
+ {
82
+ async task(ctx) {
83
+ const destroyOutput = await destroyPackage({
84
+ env: ctx.workspaceEnvOutput.env,
85
+ package: args.package,
86
+ parameters: ctx.parametersOutput.parameters,
87
+ project: ctx.configOutput.config.project,
88
+ skipDeploy: true,
89
+ workspace: ctx.configOutput.config.workspace,
90
+ });
91
+ if (!destroyOutput.success) {
92
+ throw new Error(destroyOutput.reason);
93
+ }
94
+ ctx.destroyOutput = destroyOutput;
95
+ },
96
+ title: 'Destroying package',
97
+ },
98
+ {
99
+ async task(ctx) {
100
+ const envManager = getEnvManager();
101
+ await envManager.removeProjectEnv({
102
+ env: ctx.destroyOutput.env,
103
+ infra: ctx.destroyOutput.metadata.infra,
104
+ projectRootDir,
105
+ workspace: ctx.configOutput.config.workspace,
106
+ });
107
+ await delay(500);
108
+ },
109
+ title: 'Removing package env vars from project',
110
+ },
111
+ {
112
+ async task(ctx) {
113
+ const configManager = getConfigManager();
114
+ await configManager.removePackage({
115
+ metadata: ctx.destroyOutput.metadata,
116
+ package: args.package,
117
+ projectRootDir,
118
+ });
119
+ await delay(500);
120
+ },
121
+ title: 'Removing package from hereya manifest',
122
+ },
123
+ {
124
+ async task() {
125
+ const backend = await getBackend();
126
+ const configManager = getConfigManager();
127
+ const { config: newConfig } = await configManager.loadConfig({ projectRootDir });
128
+ await backend.saveState(newConfig);
129
+ await delay(500);
130
+ },
131
+ title: 'Saving state',
132
+ },
133
+ ]);
134
+ },
135
+ title: `Removing ${args.package}`,
136
+ },
137
+ ]);
138
+ try {
139
+ await task.run();
140
+ myLogger.log(ListrLogLevels.COMPLETED, 'Package removed successfully');
38
141
  }
39
- const { config } = loadConfigOutput;
40
- if (!(args.package in (config.packages ?? {})) && !(args.package in (config.deploy ?? {}))) {
41
- this.warn(`Package ${args.package} not found in project.`);
42
- return;
142
+ catch (error) {
143
+ myLogger.log(ListrLogLevels.FAILED, error);
144
+ this.error(error.message);
43
145
  }
44
- const backend = await getBackend();
45
- const getWorkspaceEnvOutput = await backend.getWorkspaceEnv({
46
- project: config.project,
47
- workspace: config.workspace,
48
- });
49
- if (!getWorkspaceEnvOutput.success) {
50
- this.error(getWorkspaceEnvOutput.reason);
51
- }
52
- const { env: workspaceEnv } = getWorkspaceEnvOutput;
53
- const parameterManager = getParameterManager();
54
- const { parameters } = await parameterManager.getPackageParameters({
55
- package: args.package,
56
- projectRootDir,
57
- workspace: config.workspace,
58
- });
59
- logger.log(`Destroying package ${args.package}`);
60
- const destroyOutput = await destroyPackage({
61
- env: workspaceEnv,
62
- package: args.package,
63
- parameters,
64
- project: config.project,
65
- skipDeploy: true,
66
- workspace: config.workspace,
67
- });
68
- if (!destroyOutput.success) {
69
- this.error(destroyOutput.reason);
70
- }
71
- const { env, metadata } = destroyOutput;
72
- if (!metadata.deploy) {
73
- logger.done(`Destroyed infrastructure resources for ${args.package}`);
74
- }
75
- logger.log('removing package env vars from project');
76
- const envManager = getEnvManager();
77
- await envManager.removeProjectEnv({
78
- env,
79
- infra: metadata.infra,
80
- projectRootDir,
81
- workspace: config.workspace,
82
- });
83
- logger.done('removed package env vars from project');
84
- logger.log('removing package from hereya manifest');
85
- await configManager.removePackage({
86
- metadata,
87
- package: args.package,
88
- projectRootDir,
89
- });
90
- logger.done('removed package from hereya manifest');
91
- const { config: newConfig } = await configManager.loadConfig({ projectRootDir });
92
- await backend.saveState(newConfig);
93
146
  }
94
147
  }
@@ -1,13 +1,12 @@
1
1
  import { Command, Flags } from '@oclif/core';
2
+ import { Listr, ListrLogLevels, ListrLogger } from 'listr2';
2
3
  import path from 'node:path';
3
4
  import { getBackend } from '../../backend/index.js';
4
5
  import { destroyPackage } from '../../infrastructure/index.js';
5
6
  import { getConfigManager } from '../../lib/config/index.js';
6
7
  import { getEnvManager } from '../../lib/env/index.js';
7
- import { getLogger } from '../../lib/log.js';
8
8
  import { getParameterManager } from '../../lib/parameter/index.js';
9
- import { setDebug } from '../../lib/shell.js';
10
- import Down from '../down/index.js';
9
+ import { delay, setDebug } from '../../lib/shell.js';
11
10
  export default class Undeploy extends Command {
12
11
  static description = 'Undeploy a hereya project by removing all resources.';
13
12
  static examples = ['<%= config.bin %> <%= command.id %>'];
@@ -29,56 +28,185 @@ export default class Undeploy extends Command {
29
28
  async run() {
30
29
  const { flags } = await this.parse(Undeploy);
31
30
  setDebug(flags.debug);
32
- const logger = getLogger();
33
31
  const projectRootDir = path.resolve(flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR || process.cwd());
34
- const configManager = getConfigManager();
35
- const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
36
- if (!loadConfigOutput.found) {
37
- this.warn(`Project not initialized. Run 'hereya init' first.`);
38
- return;
32
+ const myLogger = new ListrLogger({ useIcons: false });
33
+ const task = new Listr([
34
+ {
35
+ async task(ctx, task) {
36
+ return task.newListr([
37
+ {
38
+ async task(ctx) {
39
+ const configManager = getConfigManager();
40
+ const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
41
+ if (!loadConfigOutput.found) {
42
+ throw new Error("Project not initialized. Run 'hereya init' first.");
43
+ }
44
+ ctx.configOutput = loadConfigOutput;
45
+ await delay(500);
46
+ },
47
+ title: 'Loading project config',
48
+ },
49
+ {
50
+ async task(ctx) {
51
+ const backend = await getBackend();
52
+ const { workspace } = flags;
53
+ const getWorkspaceEnvOutput = await backend.getWorkspaceEnv({
54
+ project: ctx.configOutput.config.project,
55
+ workspace,
56
+ });
57
+ if (!getWorkspaceEnvOutput.success) {
58
+ throw new Error(getWorkspaceEnvOutput.reason);
59
+ }
60
+ ctx.workspaceEnv = getWorkspaceEnvOutput.env;
61
+ ctx.workspace = workspace;
62
+ await delay(500);
63
+ },
64
+ title: 'Loading workspace environment variables',
65
+ },
66
+ {
67
+ async task(ctx) {
68
+ const envManager = getEnvManager();
69
+ const { env: projectEnv } = await envManager.getProjectEnv({
70
+ markSecret: true,
71
+ projectRootDir,
72
+ workspace: ctx.workspace,
73
+ });
74
+ ctx.projectEnv = projectEnv;
75
+ await delay(500);
76
+ },
77
+ title: 'Loading project environment variables',
78
+ },
79
+ {
80
+ async task(ctx) {
81
+ const backend = await getBackend();
82
+ const savedStateOutput = await backend.getState({
83
+ project: ctx.configOutput.config.project,
84
+ });
85
+ if (savedStateOutput.found) {
86
+ ctx.savedStateOutput = savedStateOutput;
87
+ }
88
+ await delay(500);
89
+ },
90
+ title: 'Loading project current state',
91
+ },
92
+ {
93
+ async task(ctx) {
94
+ const deployPackages = Object.keys(ctx.configOutput.config.deploy ?? {});
95
+ const savedDeployPackages = Object.keys(ctx.savedStateOutput?.config.deploy ?? {});
96
+ const removedDeployPackages = savedDeployPackages.filter((packageName) => !deployPackages.includes(packageName));
97
+ ctx.deployPackages = [...removedDeployPackages, ...deployPackages];
98
+ const packages = Object.keys(ctx.configOutput.config.packages ?? {});
99
+ const savedPackages = Object.keys(ctx.savedStateOutput?.config.packages ?? {});
100
+ const removedPackages = savedPackages.filter((packageName) => !packages.includes(packageName));
101
+ ctx.packages = [...removedPackages, ...packages];
102
+ await delay(500);
103
+ },
104
+ title: 'Identifying removed packages',
105
+ },
106
+ {
107
+ skip: (ctx) => ctx.deployPackages.length === 0,
108
+ async task(ctx, task) {
109
+ return task.newListr(ctx.deployPackages.map((packageName) => ({
110
+ async task() {
111
+ const parameterManager = getParameterManager();
112
+ const { parameters } = await parameterManager.getPackageParameters({
113
+ package: packageName,
114
+ projectRootDir,
115
+ workspace: ctx.workspace,
116
+ });
117
+ const destroyOutput = await destroyPackage({
118
+ env: ctx.workspaceEnv,
119
+ isDeploying: true,
120
+ package: packageName,
121
+ parameters,
122
+ project: ctx.configOutput.config.project,
123
+ projectEnv: ctx.projectEnv,
124
+ projectRootDir,
125
+ workspace: ctx.workspace,
126
+ });
127
+ if (!destroyOutput.success) {
128
+ throw new Error(destroyOutput.reason);
129
+ }
130
+ },
131
+ title: `Destroying package ${packageName}`,
132
+ })), { concurrent: false });
133
+ },
134
+ title: 'Destroying deployment packages',
135
+ },
136
+ {
137
+ skip: (ctx) => !ctx.packages || ctx.packages.length === 0,
138
+ async task(ctx, task) {
139
+ return task.newListr(ctx.packages.map((packageName) => ({
140
+ async task() {
141
+ const parameterManager = getParameterManager();
142
+ const { parameters } = await parameterManager.getPackageParameters({
143
+ package: packageName,
144
+ projectRootDir,
145
+ workspace: ctx.workspace,
146
+ });
147
+ const destroyOutput = await destroyPackage({
148
+ env: ctx.workspaceEnv,
149
+ isDeploying: true,
150
+ package: packageName,
151
+ parameters,
152
+ project: ctx.configOutput.config.project,
153
+ workspace: ctx.workspace,
154
+ });
155
+ if (!destroyOutput.success) {
156
+ throw new Error(destroyOutput.reason);
157
+ }
158
+ const { env, metadata } = destroyOutput;
159
+ const output = ctx.destroyed || [];
160
+ output.push({ env, metadata, packageName });
161
+ ctx.destroyed = output;
162
+ },
163
+ title: `Destroying ${packageName}`,
164
+ })), { concurrent: true });
165
+ },
166
+ title: `Destroying packages`,
167
+ },
168
+ {
169
+ skip: (ctx) => !ctx.destroyed || ctx.destroyed.length === 0,
170
+ async task(ctx) {
171
+ const { destroyed, workspace } = ctx;
172
+ if (!destroyed || destroyed.length === 0) {
173
+ return;
174
+ }
175
+ const envManager = getEnvManager();
176
+ for (const { env, metadata } of destroyed) {
177
+ // eslint-disable-next-line no-await-in-loop
178
+ await envManager.removeProjectEnv({
179
+ env,
180
+ infra: metadata.originalInfra ?? metadata.infra,
181
+ projectRootDir,
182
+ workspace,
183
+ });
184
+ }
185
+ await delay(500);
186
+ },
187
+ title: 'Removing env vars from destroyed packages',
188
+ },
189
+ {
190
+ async task() {
191
+ const backend = await getBackend();
192
+ const configManager = getConfigManager();
193
+ const { config: newConfig } = await configManager.loadConfig({ projectRootDir });
194
+ await backend.saveState(newConfig);
195
+ await delay(500);
196
+ },
197
+ title: 'Saving state',
198
+ },
199
+ ], { concurrent: false });
200
+ },
201
+ },
202
+ ]);
203
+ try {
204
+ await task.run();
205
+ myLogger.log(ListrLogLevels.COMPLETED, 'Project undeployed successfully');
39
206
  }
40
- const { config } = loadConfigOutput;
41
- const deployPackages = Object.keys(config.deploy ?? {});
42
- const workspace = flags.workspace || config.workspace;
43
- const backend = await getBackend();
44
- const getWorkspaceEnvOutput = await backend.getWorkspaceEnv({
45
- project: config.project,
46
- workspace,
47
- });
48
- if (!getWorkspaceEnvOutput.success) {
49
- this.error(getWorkspaceEnvOutput.reason);
207
+ catch (error) {
208
+ myLogger.log(ListrLogLevels.FAILED, error);
209
+ this.error(error.message);
50
210
  }
51
- const { env: workspaceEnv } = getWorkspaceEnvOutput;
52
- const parameterManager = getParameterManager();
53
- const envManager = getEnvManager();
54
- const { env: projectEnv } = await envManager.getProjectEnv({
55
- markSecret: true,
56
- projectRootDir,
57
- workspace,
58
- });
59
- logger.log(`Destroying ${deployPackages.length} deployment packages`);
60
- await Promise.all(deployPackages.map(async (packageName) => {
61
- const { parameters } = await parameterManager.getPackageParameters({
62
- package: packageName,
63
- projectRootDir,
64
- workspace,
65
- });
66
- const destroyOutput = await destroyPackage({
67
- env: workspaceEnv,
68
- isDeploying: true,
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
- logger.done(`Destroyed ${deployPackages.length} deployment packages`);
82
- await Down.run(['--chdir', projectRootDir, '--workspace', workspace, '--deploy']);
83
211
  }
84
212
  }