hereya-cli 0.64.2 → 0.65.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 +133 -43
- package/dist/backend/cloud/cloud-backend.d.ts +71 -0
- package/dist/backend/cloud/cloud-backend.js +96 -0
- package/dist/backend/common.d.ts +4 -0
- package/dist/backend/common.js +1 -0
- package/dist/backend/index.d.ts +5 -1
- package/dist/backend/index.js +18 -2
- package/dist/commands/add/index.js +109 -2
- package/dist/commands/deploy/index.js +8 -2
- package/dist/commands/docker/run/index.js +1 -0
- package/dist/commands/down/index.js +111 -3
- package/dist/commands/env/index.js +1 -0
- package/dist/commands/executor/start/index.d.ts +11 -0
- package/dist/commands/executor/start/index.js +176 -0
- package/dist/commands/remove/index.js +138 -4
- package/dist/commands/run/index.js +1 -0
- package/dist/commands/undeploy/index.js +4 -1
- package/dist/commands/up/index.js +102 -5
- package/dist/commands/workspace/executor/install/index.d.ts +9 -0
- package/dist/commands/workspace/executor/install/index.js +110 -0
- package/dist/commands/workspace/executor/token/index.d.ts +8 -0
- package/dist/commands/workspace/executor/token/index.js +41 -0
- package/dist/commands/workspace/executor/uninstall/index.d.ts +9 -0
- package/dist/commands/workspace/executor/uninstall/index.js +102 -0
- package/dist/executor/context.d.ts +2 -0
- package/dist/executor/context.js +39 -0
- package/dist/executor/delegating.d.ts +15 -0
- package/dist/executor/delegating.js +50 -0
- package/dist/executor/index.d.ts +12 -3
- package/dist/executor/index.js +13 -2
- package/dist/executor/remote.d.ts +16 -0
- package/dist/executor/remote.js +168 -0
- package/dist/infrastructure/index.js +55 -22
- package/dist/lib/config/common.d.ts +5 -0
- package/dist/lib/config/simple.js +43 -24
- package/dist/lib/env/index.d.ts +9 -0
- package/dist/lib/env/index.js +101 -15
- package/dist/lib/package/index.d.ts +12 -0
- package/dist/lib/package/index.js +4 -0
- package/oclif.manifest.json +159 -1
- package/package.json +1 -1
|
@@ -126,6 +126,37 @@ export class CloudBackend {
|
|
|
126
126
|
success: true,
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
|
+
async generateExecutorToken(input) {
|
|
130
|
+
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/executor-token`, {
|
|
131
|
+
headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
|
|
132
|
+
method: 'POST',
|
|
133
|
+
});
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
const error = await response.json();
|
|
136
|
+
return { reason: error.error || 'Failed to generate executor token', success: false };
|
|
137
|
+
}
|
|
138
|
+
const result = await response.json();
|
|
139
|
+
return { expiresAt: result.expiresAt, success: true, token: result.token };
|
|
140
|
+
}
|
|
141
|
+
async getExecutorJobStatus(input) {
|
|
142
|
+
const url = new URL(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/jobs/${encodeURIComponent(input.jobId)}`);
|
|
143
|
+
if (input.poll) {
|
|
144
|
+
url.searchParams.set('poll', 'true');
|
|
145
|
+
}
|
|
146
|
+
if (input.lastStatus) {
|
|
147
|
+
url.searchParams.set('lastStatus', input.lastStatus);
|
|
148
|
+
}
|
|
149
|
+
const response = await fetch(url.toString(), {
|
|
150
|
+
headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
|
|
151
|
+
method: 'GET',
|
|
152
|
+
});
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
const error = await response.json();
|
|
155
|
+
return { reason: error.error || 'Failed to get job status', success: false };
|
|
156
|
+
}
|
|
157
|
+
const result = await response.json();
|
|
158
|
+
return { job: result.job, success: true };
|
|
159
|
+
}
|
|
129
160
|
async getPackageByVersion(name, version) {
|
|
130
161
|
const response = await fetch(`${this.config.url}/api/registry/packages/${encodeURIComponent(name)}/${encodeURIComponent(version)}`, {
|
|
131
162
|
headers: {
|
|
@@ -411,6 +442,18 @@ export class CloudBackend {
|
|
|
411
442
|
const result = await response.json();
|
|
412
443
|
return result.workspaces.map((workspace) => workspace.name);
|
|
413
444
|
}
|
|
445
|
+
async pollExecutorJobs(input) {
|
|
446
|
+
const response = await fetch(`${this.config.url}/api/executor/jobs?workspace=${encodeURIComponent(input.workspace)}`, {
|
|
447
|
+
headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
|
|
448
|
+
method: 'GET',
|
|
449
|
+
});
|
|
450
|
+
if (!response.ok) {
|
|
451
|
+
const error = await response.json();
|
|
452
|
+
return { reason: error.error || 'Failed to poll for jobs', success: false };
|
|
453
|
+
}
|
|
454
|
+
const result = await response.json();
|
|
455
|
+
return { job: result.job, success: true };
|
|
456
|
+
}
|
|
414
457
|
async publishPackage(input) {
|
|
415
458
|
const formData = new FormData();
|
|
416
459
|
formData.append('name', input.name);
|
|
@@ -533,6 +576,17 @@ export class CloudBackend {
|
|
|
533
576
|
workspace: this.convertWorkspace(result.workspace),
|
|
534
577
|
};
|
|
535
578
|
}
|
|
579
|
+
async revokeExecutorToken(input) {
|
|
580
|
+
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/executor-token`, {
|
|
581
|
+
headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
|
|
582
|
+
method: 'DELETE',
|
|
583
|
+
});
|
|
584
|
+
if (!response.ok) {
|
|
585
|
+
const error = await response.json();
|
|
586
|
+
return { reason: error.error || 'Failed to revoke executor token', success: false };
|
|
587
|
+
}
|
|
588
|
+
return { success: true };
|
|
589
|
+
}
|
|
536
590
|
async saveState(config, workspace) {
|
|
537
591
|
const formData = new FormData();
|
|
538
592
|
if (workspace) {
|
|
@@ -622,6 +676,22 @@ export class CloudBackend {
|
|
|
622
676
|
success: true,
|
|
623
677
|
};
|
|
624
678
|
}
|
|
679
|
+
async submitExecutorJob(input) {
|
|
680
|
+
const formData = new FormData();
|
|
681
|
+
formData.append('type', input.type);
|
|
682
|
+
formData.append('payload', JSON.stringify(input.payload));
|
|
683
|
+
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/jobs`, {
|
|
684
|
+
body: formData,
|
|
685
|
+
headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
|
|
686
|
+
method: 'POST',
|
|
687
|
+
});
|
|
688
|
+
if (!response.ok) {
|
|
689
|
+
const error = await response.json();
|
|
690
|
+
return { reason: error.error || 'Failed to submit executor job', success: false };
|
|
691
|
+
}
|
|
692
|
+
const result = await response.json();
|
|
693
|
+
return { jobId: result.jobId, success: true };
|
|
694
|
+
}
|
|
625
695
|
async unsetEnvVar(input) {
|
|
626
696
|
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/env/${encodeURIComponent(input.name)}`, {
|
|
627
697
|
headers: {
|
|
@@ -639,11 +709,36 @@ export class CloudBackend {
|
|
|
639
709
|
success: true,
|
|
640
710
|
};
|
|
641
711
|
}
|
|
712
|
+
async updateExecutorJob(input) {
|
|
713
|
+
const formData = new FormData();
|
|
714
|
+
if (input.logs) {
|
|
715
|
+
formData.append('logs', input.logs);
|
|
716
|
+
}
|
|
717
|
+
if (input.status) {
|
|
718
|
+
formData.append('status', input.status);
|
|
719
|
+
}
|
|
720
|
+
if (input.result) {
|
|
721
|
+
formData.append('result', JSON.stringify(input.result));
|
|
722
|
+
}
|
|
723
|
+
const response = await fetch(`${this.config.url}/api/executor/jobs/${encodeURIComponent(input.jobId)}`, {
|
|
724
|
+
body: formData,
|
|
725
|
+
headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
|
|
726
|
+
method: 'PATCH',
|
|
727
|
+
});
|
|
728
|
+
if (!response.ok) {
|
|
729
|
+
const error = await response.json();
|
|
730
|
+
return { reason: error.error || 'Failed to update job', success: false };
|
|
731
|
+
}
|
|
732
|
+
return { success: true };
|
|
733
|
+
}
|
|
642
734
|
async updateWorkspace(input) {
|
|
643
735
|
const formData = new FormData();
|
|
644
736
|
if (input.profile !== undefined) {
|
|
645
737
|
formData.append('profile', input.profile === null ? '' : input.profile);
|
|
646
738
|
}
|
|
739
|
+
if (input.hasExecutor !== undefined) {
|
|
740
|
+
formData.append('hasExecutor', input.hasExecutor === null ? '' : String(input.hasExecutor));
|
|
741
|
+
}
|
|
647
742
|
if (input.isDeploy !== undefined) {
|
|
648
743
|
formData.append('isDeploy', input.isDeploy === null ? '' : String(input.isDeploy));
|
|
649
744
|
}
|
|
@@ -693,6 +788,7 @@ export class CloudBackend {
|
|
|
693
788
|
}
|
|
694
789
|
return {
|
|
695
790
|
env,
|
|
791
|
+
hasExecutor: workspace.hasExecutor ?? undefined,
|
|
696
792
|
id: workspace.id,
|
|
697
793
|
isDeploy: workspace.isDeploy,
|
|
698
794
|
mirrorOf: workspace.mirrorOf?.name,
|
package/dist/backend/common.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export interface Backend {
|
|
|
27
27
|
}
|
|
28
28
|
export declare const WorkspaceSchema: z.ZodObject<{
|
|
29
29
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
30
|
+
hasExecutor: z.ZodOptional<z.ZodBoolean>;
|
|
30
31
|
id: z.ZodString;
|
|
31
32
|
isDeploy: z.ZodOptional<z.ZodBoolean>;
|
|
32
33
|
mirrorOf: z.ZodOptional<z.ZodString>;
|
|
@@ -51,6 +52,7 @@ export declare const WorkspaceSchema: z.ZodObject<{
|
|
|
51
52
|
parameters?: Record<string, any> | undefined;
|
|
52
53
|
}> | undefined;
|
|
53
54
|
profile?: string | undefined;
|
|
55
|
+
hasExecutor?: boolean | undefined;
|
|
54
56
|
isDeploy?: boolean | undefined;
|
|
55
57
|
mirrorOf?: string | undefined;
|
|
56
58
|
}, {
|
|
@@ -62,6 +64,7 @@ export declare const WorkspaceSchema: z.ZodObject<{
|
|
|
62
64
|
parameters?: Record<string, any> | undefined;
|
|
63
65
|
}> | undefined;
|
|
64
66
|
profile?: string | undefined;
|
|
67
|
+
hasExecutor?: boolean | undefined;
|
|
65
68
|
isDeploy?: boolean | undefined;
|
|
66
69
|
mirrorOf?: string | undefined;
|
|
67
70
|
}>;
|
|
@@ -222,6 +225,7 @@ export type UnsetEnvVarInput = {
|
|
|
222
225
|
};
|
|
223
226
|
export type UnsetEnvVarOutput = SetEnvVarOutput;
|
|
224
227
|
export type UpdateWorkspaceInput = {
|
|
228
|
+
hasExecutor?: boolean | null;
|
|
225
229
|
isDeploy?: boolean | null;
|
|
226
230
|
name: string;
|
|
227
231
|
profile?: null | string;
|
package/dist/backend/common.js
CHANGED
package/dist/backend/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Backend } from './common.js';
|
|
2
|
-
export
|
|
2
|
+
export interface GetBackendOptions {
|
|
3
|
+
token?: string;
|
|
4
|
+
url?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function getBackend(typeOrOptions?: BackendType | GetBackendOptions): Promise<Backend>;
|
|
3
7
|
export declare function clearBackend(): void;
|
|
4
8
|
export declare function setBackendType(type: BackendType): void;
|
|
5
9
|
export declare enum BackendType {
|
package/dist/backend/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getAwsConfig } from '../infrastructure/aws-config.js';
|
|
2
2
|
import { CloudBackend } from './cloud/cloud-backend.js';
|
|
3
|
-
import { refreshToken } from './cloud/login.js';
|
|
3
|
+
import { loginWithToken, refreshToken } from './cloud/login.js';
|
|
4
4
|
import { getCloudCredentials, loadBackendConfig, saveCloudCredentials } from './config.js';
|
|
5
5
|
import { LocalFileBackend } from './local.js';
|
|
6
6
|
import { S3FileBackend } from './s3.js';
|
|
@@ -62,10 +62,26 @@ function isTokenExpired(token) {
|
|
|
62
62
|
return true;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
export async function getBackend(
|
|
65
|
+
export async function getBackend(typeOrOptions) {
|
|
66
66
|
if (backend) {
|
|
67
67
|
return backend;
|
|
68
68
|
}
|
|
69
|
+
// Handle token-based auth
|
|
70
|
+
if (typeOrOptions && typeof typeOrOptions === 'object' && typeOrOptions.token) {
|
|
71
|
+
const url = typeOrOptions.url || 'https://cloud.hereya.dev';
|
|
72
|
+
const result = await loginWithToken(url, typeOrOptions.token);
|
|
73
|
+
if (!result.success) {
|
|
74
|
+
throw new Error(`Failed to authenticate with token: ${result.error}`);
|
|
75
|
+
}
|
|
76
|
+
backend = new CloudBackend({
|
|
77
|
+
accessToken: result.accessToken,
|
|
78
|
+
clientId: result.clientId,
|
|
79
|
+
refreshToken: result.refreshToken,
|
|
80
|
+
url,
|
|
81
|
+
});
|
|
82
|
+
return backend;
|
|
83
|
+
}
|
|
84
|
+
const type = typeof typeOrOptions === 'string' ? typeOrOptions : undefined;
|
|
69
85
|
const backendConfig = await loadBackendConfig();
|
|
70
86
|
const backendType = type ?? currentBackendType ?? backendConfig.current;
|
|
71
87
|
switch (backendType) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import { Listr, ListrLogger, ListrLogLevels } from 'listr2';
|
|
3
3
|
import { getBackend } from '../../backend/index.js';
|
|
4
|
-
import {
|
|
4
|
+
import { getExecutorForWorkspace } from '../../executor/context.js';
|
|
5
5
|
import { getConfigManager } from '../../lib/config/index.js';
|
|
6
6
|
import { logEnv } from '../../lib/env-utils.js';
|
|
7
7
|
import { getEnvManager } from '../../lib/env/index.js';
|
|
@@ -107,7 +107,7 @@ export default class Add extends Command {
|
|
|
107
107
|
persistentOutput: isDebug(),
|
|
108
108
|
},
|
|
109
109
|
async task(ctx, task) {
|
|
110
|
-
const executor$ =
|
|
110
|
+
const executor$ = await getExecutorForWorkspace(ctx.workspace, ctx.configOutput.config.project);
|
|
111
111
|
if (!executor$.success) {
|
|
112
112
|
throw new Error(executor$.reason);
|
|
113
113
|
}
|
|
@@ -135,7 +135,9 @@ export default class Add extends Command {
|
|
|
135
135
|
await envManager.addProjectEnv({
|
|
136
136
|
env,
|
|
137
137
|
infra: metadata.originalInfra ?? metadata.infra,
|
|
138
|
+
pkg: ctx.provisionOutput.pkgName,
|
|
138
139
|
projectRootDir,
|
|
140
|
+
snakeCase: metadata.snakeCase,
|
|
139
141
|
workspace: ctx.workspace,
|
|
140
142
|
});
|
|
141
143
|
await delay(500);
|
|
@@ -176,6 +178,111 @@ export default class Add extends Command {
|
|
|
176
178
|
},
|
|
177
179
|
title: 'Saving state',
|
|
178
180
|
},
|
|
181
|
+
{
|
|
182
|
+
async task(ctx) {
|
|
183
|
+
const configManager = getConfigManager();
|
|
184
|
+
const { config } = await configManager.loadConfig({ projectRootDir });
|
|
185
|
+
const devDeploy = config.devDeploy ?? {};
|
|
186
|
+
if (Object.keys(devDeploy).length === 0) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const backend = await getBackend();
|
|
190
|
+
const profile = await getProfileFromWorkspace(backend, ctx.workspace, ctx.configOutput.config.project);
|
|
191
|
+
const envManager = getEnvManager();
|
|
192
|
+
const getProjectEnvOutput = await envManager.getProjectEnv({
|
|
193
|
+
excludeDevDeploy: true,
|
|
194
|
+
markSecret: false,
|
|
195
|
+
profile,
|
|
196
|
+
project: ctx.configOutput.config.project,
|
|
197
|
+
projectRootDir,
|
|
198
|
+
workspace: ctx.workspace,
|
|
199
|
+
});
|
|
200
|
+
if (!getProjectEnvOutput.success) {
|
|
201
|
+
throw new Error(getProjectEnvOutput.reason);
|
|
202
|
+
}
|
|
203
|
+
ctx.projectEnv = getProjectEnvOutput.env;
|
|
204
|
+
// Update configOutput with fresh config
|
|
205
|
+
ctx.configOutput = { config, found: true };
|
|
206
|
+
await delay(500);
|
|
207
|
+
},
|
|
208
|
+
title: 'Loading project environment',
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
skip(ctx) {
|
|
212
|
+
const devDeploy = ctx.configOutput.config.devDeploy ?? {};
|
|
213
|
+
return Object.keys(devDeploy).length === 0;
|
|
214
|
+
},
|
|
215
|
+
async task(ctx, task) {
|
|
216
|
+
const configManager = getConfigManager();
|
|
217
|
+
const { config } = await configManager.loadConfig({ projectRootDir });
|
|
218
|
+
const devDeployPackages = config.devDeploy ?? {};
|
|
219
|
+
const devDeployEntries = Object.entries(devDeployPackages).map(([name, info]) => ({
|
|
220
|
+
name,
|
|
221
|
+
packageSpec: info.version ? `${name}@${info.version}` : name,
|
|
222
|
+
version: info.version || '',
|
|
223
|
+
}));
|
|
224
|
+
return task.newListr(devDeployEntries.map((pkg) => ({
|
|
225
|
+
rendererOptions: {
|
|
226
|
+
persistentOutput: isDebug(),
|
|
227
|
+
},
|
|
228
|
+
async task(_, task) {
|
|
229
|
+
const parameterManager = getParameterManager();
|
|
230
|
+
const backend = await getBackend();
|
|
231
|
+
const profile = await getProfileFromWorkspace(backend, ctx.workspace, ctx.configOutput.config.project);
|
|
232
|
+
const { parameters } = await parameterManager.getPackageParameters({
|
|
233
|
+
package: pkg.name,
|
|
234
|
+
profile,
|
|
235
|
+
projectRootDir,
|
|
236
|
+
});
|
|
237
|
+
const executor$ = await getExecutorForWorkspace(ctx.workspace, ctx.configOutput.config.project);
|
|
238
|
+
if (!executor$.success) {
|
|
239
|
+
throw new Error(executor$.reason);
|
|
240
|
+
}
|
|
241
|
+
const { executor } = executor$;
|
|
242
|
+
const provisionOutput = await executor.provision({
|
|
243
|
+
logger: getLogger(task),
|
|
244
|
+
package: pkg.packageSpec,
|
|
245
|
+
parameters,
|
|
246
|
+
project: ctx.configOutput.config.project,
|
|
247
|
+
projectEnv: ctx.projectEnv ?? {},
|
|
248
|
+
workspace: ctx.workspace,
|
|
249
|
+
});
|
|
250
|
+
if (!provisionOutput.success) {
|
|
251
|
+
throw new Error(provisionOutput.reason);
|
|
252
|
+
}
|
|
253
|
+
const { env, metadata } = provisionOutput;
|
|
254
|
+
const output = ctx.devDeployAdded || [];
|
|
255
|
+
output.push({ env, metadata, packageName: pkg.name });
|
|
256
|
+
ctx.devDeployAdded = output;
|
|
257
|
+
},
|
|
258
|
+
title: `Provisioning ${pkg.name}`,
|
|
259
|
+
})), { concurrent: true, rendererOptions: { collapseSubtasks: !isDebug() } });
|
|
260
|
+
},
|
|
261
|
+
title: 'Provisioning devDeploy packages',
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
skip: (ctx) => !ctx.devDeployAdded || ctx.devDeployAdded.length === 0,
|
|
265
|
+
async task(ctx) {
|
|
266
|
+
if (!ctx.devDeployAdded || ctx.devDeployAdded.length === 0) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const envManager = getEnvManager();
|
|
270
|
+
for (const { env, metadata, packageName } of ctx.devDeployAdded) {
|
|
271
|
+
// eslint-disable-next-line no-await-in-loop
|
|
272
|
+
await envManager.addProjectEnv({
|
|
273
|
+
env,
|
|
274
|
+
infra: metadata.originalInfra ?? metadata.infra,
|
|
275
|
+
isDevDeploy: true,
|
|
276
|
+
pkg: packageName,
|
|
277
|
+
projectRootDir,
|
|
278
|
+
snakeCase: metadata.snakeCase,
|
|
279
|
+
workspace: ctx.workspace,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
await delay(500);
|
|
283
|
+
},
|
|
284
|
+
title: 'Adding env vars from devDeploy packages',
|
|
285
|
+
},
|
|
179
286
|
], { concurrent: false, rendererOptions: { collapseSubtasks: !isDebug() } });
|
|
180
287
|
},
|
|
181
288
|
title: `Adding ${args.package}`,
|
|
@@ -81,6 +81,7 @@ export default class Deploy extends Command {
|
|
|
81
81
|
const getProjectEnvOutput = await envManager.getProjectEnv({
|
|
82
82
|
markSecret: true,
|
|
83
83
|
profile,
|
|
84
|
+
project: ctx.configOutput.config.project,
|
|
84
85
|
projectRootDir,
|
|
85
86
|
workspace: ctx.workspace,
|
|
86
87
|
});
|
|
@@ -267,12 +268,14 @@ export default class Deploy extends Command {
|
|
|
267
268
|
return;
|
|
268
269
|
}
|
|
269
270
|
const envManager = getEnvManager();
|
|
270
|
-
for (const { env, metadata } of ctx.removed) {
|
|
271
|
+
for (const { env, metadata, packageName } of ctx.removed) {
|
|
271
272
|
// eslint-disable-next-line no-await-in-loop
|
|
272
273
|
await envManager.removeProjectEnv({
|
|
273
274
|
env,
|
|
274
275
|
infra: metadata.originalInfra ?? metadata.infra,
|
|
276
|
+
pkg: packageName,
|
|
275
277
|
projectRootDir,
|
|
278
|
+
snakeCase: metadata.snakeCase,
|
|
276
279
|
workspace: ctx.workspace,
|
|
277
280
|
});
|
|
278
281
|
}
|
|
@@ -287,12 +290,14 @@ export default class Deploy extends Command {
|
|
|
287
290
|
return;
|
|
288
291
|
}
|
|
289
292
|
const envManager = getEnvManager();
|
|
290
|
-
for (const { env, metadata } of ctx.added) {
|
|
293
|
+
for (const { env, metadata, packageName } of ctx.added) {
|
|
291
294
|
// eslint-disable-next-line no-await-in-loop
|
|
292
295
|
await envManager.addProjectEnv({
|
|
293
296
|
env,
|
|
294
297
|
infra: metadata.originalInfra ?? metadata.infra,
|
|
298
|
+
pkg: packageName,
|
|
295
299
|
projectRootDir,
|
|
300
|
+
snakeCase: metadata.snakeCase,
|
|
296
301
|
workspace: ctx.workspace,
|
|
297
302
|
});
|
|
298
303
|
}
|
|
@@ -319,6 +324,7 @@ export default class Deploy extends Command {
|
|
|
319
324
|
const getProjectEnvOutput = await envManager.getProjectEnv({
|
|
320
325
|
markSecret: true,
|
|
321
326
|
profile,
|
|
327
|
+
project: ctx.configOutput.config.project,
|
|
322
328
|
projectRootDir,
|
|
323
329
|
workspace: ctx.workspace,
|
|
324
330
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { Listr, ListrLogger, ListrLogLevels } from 'listr2';
|
|
3
3
|
import { getBackend } from '../../backend/index.js';
|
|
4
|
-
import {
|
|
4
|
+
import { getExecutorForWorkspace } from '../../executor/context.js';
|
|
5
5
|
import { getConfigManager } from '../../lib/config/index.js';
|
|
6
6
|
import { getEnvManager } from '../../lib/env/index.js';
|
|
7
7
|
import { getLogger, getLogPath, isDebug, setDebug } from '../../lib/log.js';
|
|
@@ -115,10 +115,116 @@ export default class Down extends Command {
|
|
|
115
115
|
packagesWithVersions = selectedPackages;
|
|
116
116
|
}
|
|
117
117
|
ctx.packages = [...packagesWithVersions, ...removedPackagesWithVersions];
|
|
118
|
+
// Collect devDeploy packages from config and saved state
|
|
119
|
+
const configDevDeploy = ctx.configOutput.config.devDeploy ?? {};
|
|
120
|
+
const devDeployFromConfig = Object.entries(configDevDeploy).map(([name, info]) => ({
|
|
121
|
+
name,
|
|
122
|
+
packageSpec: info.version ? `${name}@${info.version}` : name,
|
|
123
|
+
version: info.version || '',
|
|
124
|
+
}));
|
|
125
|
+
let devDeployFromState = [];
|
|
126
|
+
if (savedStateOutput.found) {
|
|
127
|
+
const savedDevDeploy = savedStateOutput.config.devDeploy ?? {};
|
|
128
|
+
devDeployFromState = Object.entries(savedDevDeploy)
|
|
129
|
+
.filter(([name]) => !configDevDeploy[name])
|
|
130
|
+
.map(([name, info]) => ({
|
|
131
|
+
name,
|
|
132
|
+
packageSpec: info.version ? `${name}@${info.version}` : name,
|
|
133
|
+
version: info.version || '',
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
ctx.devDeployPackages = [...devDeployFromConfig, ...devDeployFromState];
|
|
118
137
|
await delay(500);
|
|
119
138
|
},
|
|
120
139
|
title: 'Identifying packages to destroy',
|
|
121
140
|
},
|
|
141
|
+
{
|
|
142
|
+
skip: (ctx) => !ctx.devDeployPackages || ctx.devDeployPackages.length === 0,
|
|
143
|
+
async task(ctx) {
|
|
144
|
+
// Load project env for devDeploy destroy
|
|
145
|
+
const backend = await getBackend();
|
|
146
|
+
const profile = await getProfileFromWorkspace(backend, ctx.workspace, ctx.configOutput.config.project);
|
|
147
|
+
const envManager = getEnvManager();
|
|
148
|
+
const getProjectEnvOutput = await envManager.getProjectEnv({
|
|
149
|
+
excludeDevDeploy: true,
|
|
150
|
+
markSecret: false,
|
|
151
|
+
profile,
|
|
152
|
+
project: ctx.configOutput.config.project,
|
|
153
|
+
projectRootDir,
|
|
154
|
+
workspace: ctx.workspace,
|
|
155
|
+
});
|
|
156
|
+
if (!getProjectEnvOutput.success) {
|
|
157
|
+
throw new Error(getProjectEnvOutput.reason);
|
|
158
|
+
}
|
|
159
|
+
ctx.projectEnv = getProjectEnvOutput.env;
|
|
160
|
+
await delay(500);
|
|
161
|
+
},
|
|
162
|
+
title: 'Loading project environment for devDeploy',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
skip: (ctx) => !ctx.devDeployPackages || ctx.devDeployPackages.length === 0,
|
|
166
|
+
async task(ctx) {
|
|
167
|
+
return task.newListr(ctx.devDeployPackages.map((pkg) => ({
|
|
168
|
+
rendererOptions: {
|
|
169
|
+
persistentOutput: isDebug(),
|
|
170
|
+
},
|
|
171
|
+
async task(_, task) {
|
|
172
|
+
const parameterManager = getParameterManager();
|
|
173
|
+
const backend = await getBackend();
|
|
174
|
+
const profile = await getProfileFromWorkspace(backend, ctx.workspace, ctx.configOutput.config.project);
|
|
175
|
+
const { parameters } = await parameterManager.getPackageParameters({
|
|
176
|
+
package: pkg.name,
|
|
177
|
+
profile,
|
|
178
|
+
projectRootDir,
|
|
179
|
+
});
|
|
180
|
+
const executor$ = await getExecutorForWorkspace(ctx.workspace, ctx.configOutput.config.project);
|
|
181
|
+
if (!executor$.success) {
|
|
182
|
+
throw new Error(executor$.reason);
|
|
183
|
+
}
|
|
184
|
+
const { executor } = executor$;
|
|
185
|
+
const destroyOutput = await executor.destroy({
|
|
186
|
+
logger: getLogger(task),
|
|
187
|
+
package: pkg.packageSpec,
|
|
188
|
+
parameters,
|
|
189
|
+
project: ctx.configOutput.config.project,
|
|
190
|
+
projectEnv: ctx.projectEnv,
|
|
191
|
+
workspace: ctx.workspace,
|
|
192
|
+
});
|
|
193
|
+
if (!destroyOutput.success) {
|
|
194
|
+
throw new Error(destroyOutput.reason);
|
|
195
|
+
}
|
|
196
|
+
const { env, metadata } = destroyOutput;
|
|
197
|
+
const output = ctx.devDeployDestroyed || [];
|
|
198
|
+
output.push({ env, metadata, packageName: pkg.name });
|
|
199
|
+
ctx.devDeployDestroyed = output;
|
|
200
|
+
},
|
|
201
|
+
title: `Destroying ${pkg.name}`,
|
|
202
|
+
})), { concurrent: true, rendererOptions: { collapseSubtasks: !isDebug() } });
|
|
203
|
+
},
|
|
204
|
+
title: 'Destroying devDeploy packages',
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
skip: (ctx) => !ctx.devDeployDestroyed || ctx.devDeployDestroyed.length === 0,
|
|
208
|
+
async task(ctx) {
|
|
209
|
+
if (!ctx.devDeployDestroyed || ctx.devDeployDestroyed.length === 0) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const envManager = getEnvManager();
|
|
213
|
+
for (const { env, metadata, packageName } of ctx.devDeployDestroyed) {
|
|
214
|
+
// eslint-disable-next-line no-await-in-loop
|
|
215
|
+
await envManager.removeProjectEnv({
|
|
216
|
+
env,
|
|
217
|
+
infra: metadata.originalInfra ?? metadata.infra,
|
|
218
|
+
pkg: packageName,
|
|
219
|
+
projectRootDir,
|
|
220
|
+
snakeCase: metadata.snakeCase,
|
|
221
|
+
workspace: ctx.workspace,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
await delay(500);
|
|
225
|
+
},
|
|
226
|
+
title: 'Removing env vars from devDeploy packages',
|
|
227
|
+
},
|
|
122
228
|
{
|
|
123
229
|
skip: (ctx) => !ctx.packages || ctx.packages.length === 0,
|
|
124
230
|
async task(ctx) {
|
|
@@ -138,7 +244,7 @@ export default class Down extends Command {
|
|
|
138
244
|
profile,
|
|
139
245
|
projectRootDir,
|
|
140
246
|
});
|
|
141
|
-
const executor$ =
|
|
247
|
+
const executor$ = await getExecutorForWorkspace(ctx.workspace, ctx.configOutput.config.project);
|
|
142
248
|
if (!executor$.success) {
|
|
143
249
|
throw new Error(executor$.reason);
|
|
144
250
|
}
|
|
@@ -173,12 +279,14 @@ export default class Down extends Command {
|
|
|
173
279
|
return;
|
|
174
280
|
}
|
|
175
281
|
const envManager = getEnvManager();
|
|
176
|
-
for (const { env, metadata } of destroyed) {
|
|
282
|
+
for (const { env, metadata, packageName } of destroyed) {
|
|
177
283
|
// eslint-disable-next-line no-await-in-loop
|
|
178
284
|
await envManager.removeProjectEnv({
|
|
179
285
|
env,
|
|
180
286
|
infra: metadata.originalInfra ?? metadata.infra,
|
|
287
|
+
pkg: packageName,
|
|
181
288
|
projectRootDir,
|
|
289
|
+
snakeCase: metadata.snakeCase,
|
|
182
290
|
workspace,
|
|
183
291
|
});
|
|
184
292
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ExecutorStart extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
concurrency: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
private executeJob;
|
|
11
|
+
}
|