hereya-cli 0.23.0 → 0.25.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.23.0 linux-x64 node-v22.13.1
23
+ hereya-cli/0.25.0 linux-x64 node-v22.14.0
24
24
  $ hereya --help [COMMAND]
25
25
  USAGE
26
26
  $ hereya COMMAND
@@ -48,6 +48,7 @@ USAGE
48
48
  * [`hereya workspace env set`](#hereya-workspace-env-set)
49
49
  * [`hereya workspace env unset`](#hereya-workspace-env-unset)
50
50
  * [`hereya workspace install PACKAGE`](#hereya-workspace-install-package)
51
+ * [`hereya workspace list`](#hereya-workspace-list)
51
52
  * [`hereya workspace uninstall PACKAGE`](#hereya-workspace-uninstall-package)
52
53
 
53
54
  ## `hereya add PACKAGE`
@@ -81,7 +82,7 @@ EXAMPLES
81
82
  $ hereya add cloudy/docker_postgres
82
83
  ```
83
84
 
84
- _See code: [src/commands/add/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/add/index.ts)_
85
+ _See code: [src/commands/add/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/add/index.ts)_
85
86
 
86
87
  ## `hereya bootstrap INFRASTRUCTURETYPE`
87
88
 
@@ -106,7 +107,7 @@ EXAMPLES
106
107
  $ hereya bootstrap local
107
108
  ```
108
109
 
109
- _See code: [src/commands/bootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/bootstrap/index.ts)_
110
+ _See code: [src/commands/bootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/bootstrap/index.ts)_
110
111
 
111
112
  ## `hereya deploy`
112
113
 
@@ -131,7 +132,7 @@ EXAMPLES
131
132
  $ hereya deploy
132
133
  ```
133
134
 
134
- _See code: [src/commands/deploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/deploy/index.ts)_
135
+ _See code: [src/commands/deploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/deploy/index.ts)_
135
136
 
136
137
  ## `hereya down`
137
138
 
@@ -157,7 +158,7 @@ EXAMPLES
157
158
  $ hereya down
158
159
  ```
159
160
 
160
- _See code: [src/commands/down/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/down/index.ts)_
161
+ _See code: [src/commands/down/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/down/index.ts)_
161
162
 
162
163
  ## `hereya env [NAME]`
163
164
 
@@ -188,7 +189,7 @@ EXAMPLES
188
189
  $ hereya env -w dev -l
189
190
  ```
190
191
 
191
- _See code: [src/commands/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/env/index.ts)_
192
+ _See code: [src/commands/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/env/index.ts)_
192
193
 
193
194
  ## `hereya env set [NAME]`
194
195
 
@@ -215,7 +216,7 @@ EXAMPLES
215
216
  $ hereya env set FOO -v bar -w dev
216
217
  ```
217
218
 
218
- _See code: [src/commands/env/set/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/env/set/index.ts)_
219
+ _See code: [src/commands/env/set/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/env/set/index.ts)_
219
220
 
220
221
  ## `hereya help [COMMAND]`
221
222
 
@@ -261,7 +262,7 @@ EXAMPLES
261
262
  $ hereya init myProject -w=defaultWorkspace --chdir=./myProject
262
263
  ```
263
264
 
264
- _See code: [src/commands/init/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/init/index.ts)_
265
+ _See code: [src/commands/init/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/init/index.ts)_
265
266
 
266
267
  ## `hereya remove PACKAGE`
267
268
 
@@ -288,7 +289,7 @@ EXAMPLES
288
289
  $ hereya remove cloudy/docker_postgres
289
290
  ```
290
291
 
291
- _See code: [src/commands/remove/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/remove/index.ts)_
292
+ _See code: [src/commands/remove/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/remove/index.ts)_
292
293
 
293
294
  ## `hereya run CMD`
294
295
 
@@ -314,7 +315,7 @@ EXAMPLES
314
315
  $ hereya run -w uat -- node index.js
315
316
  ```
316
317
 
317
- _See code: [src/commands/run/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/run/index.ts)_
318
+ _See code: [src/commands/run/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/run/index.ts)_
318
319
 
319
320
  ## `hereya unbootstrap INFRASTRUCTURETYPE`
320
321
 
@@ -339,7 +340,7 @@ EXAMPLES
339
340
  $ hereya unbootstrap local
340
341
  ```
341
342
 
342
- _See code: [src/commands/unbootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/unbootstrap/index.ts)_
343
+ _See code: [src/commands/unbootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/unbootstrap/index.ts)_
343
344
 
344
345
  ## `hereya undeploy`
345
346
 
@@ -364,7 +365,7 @@ EXAMPLES
364
365
  $ hereya undeploy
365
366
  ```
366
367
 
367
- _See code: [src/commands/undeploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/undeploy/index.ts)_
368
+ _See code: [src/commands/undeploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/undeploy/index.ts)_
368
369
 
369
370
  ## `hereya up`
370
371
 
@@ -390,7 +391,7 @@ EXAMPLES
390
391
  $ hereya up
391
392
  ```
392
393
 
393
- _See code: [src/commands/up/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/up/index.ts)_
394
+ _See code: [src/commands/up/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/up/index.ts)_
394
395
 
395
396
  ## `hereya workspace create NAME`
396
397
 
@@ -398,11 +399,14 @@ Create a new workspace if it does not exist.
398
399
 
399
400
  ```
400
401
  USAGE
401
- $ hereya workspace create NAME
402
+ $ hereya workspace create NAME [--mirror <value>]
402
403
 
403
404
  ARGUMENTS
404
405
  NAME name of the workspace to create
405
406
 
407
+ FLAGS
408
+ --mirror=<value> workspace to mirror
409
+
406
410
  DESCRIPTION
407
411
  Create a new workspace if it does not exist.
408
412
 
@@ -410,7 +414,7 @@ EXAMPLES
410
414
  $ hereya workspace create dev
411
415
  ```
412
416
 
413
- _See code: [src/commands/workspace/create/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/workspace/create/index.ts)_
417
+ _See code: [src/commands/workspace/create/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/workspace/create/index.ts)_
414
418
 
415
419
  ## `hereya workspace delete NAME`
416
420
 
@@ -430,7 +434,7 @@ EXAMPLES
430
434
  $ hereya workspace delete dev
431
435
  ```
432
436
 
433
- _See code: [src/commands/workspace/delete/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/workspace/delete/index.ts)_
437
+ _See code: [src/commands/workspace/delete/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/workspace/delete/index.ts)_
434
438
 
435
439
  ## `hereya workspace env [NAME]`
436
440
 
@@ -456,7 +460,7 @@ EXAMPLES
456
460
  $ hereya workspace env myEnv -w dev
457
461
  ```
458
462
 
459
- _See code: [src/commands/workspace/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/workspace/env/index.ts)_
463
+ _See code: [src/commands/workspace/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/workspace/env/index.ts)_
460
464
 
461
465
  ## `hereya workspace env set`
462
466
 
@@ -480,7 +484,7 @@ EXAMPLES
480
484
  $ hereya workspace env set -w my-workspace -n myVar -v my-value -i aws -s
481
485
  ```
482
486
 
483
- _See code: [src/commands/workspace/env/set/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/workspace/env/set/index.ts)_
487
+ _See code: [src/commands/workspace/env/set/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/workspace/env/set/index.ts)_
484
488
 
485
489
  ## `hereya workspace env unset`
486
490
 
@@ -501,7 +505,7 @@ EXAMPLES
501
505
  $ hereya workspace env unset -w my-workspace -n myVar
502
506
  ```
503
507
 
504
- _See code: [src/commands/workspace/env/unset/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/workspace/env/unset/index.ts)_
508
+ _See code: [src/commands/workspace/env/unset/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/workspace/env/unset/index.ts)_
505
509
 
506
510
  ## `hereya workspace install PACKAGE`
507
511
 
@@ -528,7 +532,24 @@ EXAMPLES
528
532
  $ hereya workspace install hereya/aws-cognito
529
533
  ```
530
534
 
531
- _See code: [src/commands/workspace/install/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/workspace/install/index.ts)_
535
+ _See code: [src/commands/workspace/install/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/workspace/install/index.ts)_
536
+
537
+ ## `hereya workspace list`
538
+
539
+ List workspaces.
540
+
541
+ ```
542
+ USAGE
543
+ $ hereya workspace list
544
+
545
+ DESCRIPTION
546
+ List workspaces.
547
+
548
+ EXAMPLES
549
+ $ hereya workspace list
550
+ ```
551
+
552
+ _See code: [src/commands/workspace/list/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/workspace/list/index.ts)_
532
553
 
533
554
  ## `hereya workspace uninstall PACKAGE`
534
555
 
@@ -555,5 +576,5 @@ EXAMPLES
555
576
  $ hereya workspace uninstall hereya/aws-cognito
556
577
  ```
557
578
 
558
- _See code: [src/commands/workspace/uninstall/index.ts](https://github.com/hereya/hereya-cli/blob/v0.23.0/src/commands/workspace/uninstall/index.ts)_
579
+ _See code: [src/commands/workspace/uninstall/index.ts](https://github.com/hereya/hereya-cli/blob/v0.25.0/src/commands/workspace/uninstall/index.ts)_
559
580
  <!-- commandsstop -->
@@ -1,3 +1,4 @@
1
+ import { z } from 'zod';
1
2
  import { InfrastructureType } from '../infrastructure/common.js';
2
3
  import { Config } from '../lib/config/common.js';
3
4
  export interface Backend {
@@ -9,11 +10,47 @@ export interface Backend {
9
10
  getWorkspace(workspace: string): Promise<GetWorkspaceOutput>;
10
11
  getWorkspaceEnv(input: GetWorkspaceEnvInput): Promise<GetWorkspaceEnvOutput>;
11
12
  init(options: InitProjectInput): Promise<InitProjectOutput>;
13
+ listWorkspaces(): Promise<string[]>;
12
14
  removePackageFromWorkspace(input: RemovePackageFromWorkspaceInput): Promise<RemovePackageFromWorkspaceOutput>;
13
15
  saveState(config: Config, workspace?: string): Promise<void>;
14
16
  setEnvVar(input: SetEnvVarInput): Promise<SetEnvVarOutput>;
15
17
  unsetEnvVar(input: UnsetEnvVarInput): Promise<UnsetEnvVarOutput>;
16
18
  }
19
+ export declare const WorkspaceSchema: z.ZodObject<{
20
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
21
+ id: z.ZodString;
22
+ mirrorOf: z.ZodOptional<z.ZodString>;
23
+ name: z.ZodString;
24
+ packages: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
25
+ parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
26
+ version: z.ZodString;
27
+ }, "strip", z.ZodTypeAny, {
28
+ version: string;
29
+ parameters?: Record<string, any> | undefined;
30
+ }, {
31
+ version: string;
32
+ parameters?: Record<string, any> | undefined;
33
+ }>>>;
34
+ }, "strip", z.ZodTypeAny, {
35
+ name: string;
36
+ id: string;
37
+ env?: Record<string, string> | undefined;
38
+ mirrorOf?: string | undefined;
39
+ packages?: Record<string, {
40
+ version: string;
41
+ parameters?: Record<string, any> | undefined;
42
+ }> | undefined;
43
+ }, {
44
+ name: string;
45
+ id: string;
46
+ env?: Record<string, string> | undefined;
47
+ mirrorOf?: string | undefined;
48
+ packages?: Record<string, {
49
+ version: string;
50
+ parameters?: Record<string, any> | undefined;
51
+ }> | undefined;
52
+ }>;
53
+ export type Workspace = z.infer<typeof WorkspaceSchema>;
17
54
  export type AddPackageToWorkspaceInput = {
18
55
  env: {
19
56
  [key: string]: string;
@@ -30,15 +67,7 @@ export type AddPackageToWorkspaceOutput = {
30
67
  success: false;
31
68
  } | {
32
69
  success: true;
33
- workspace: {
34
- id: string;
35
- name: string;
36
- packages?: {
37
- [key: string]: {
38
- version: string;
39
- };
40
- };
41
- };
70
+ workspace: Workspace;
42
71
  };
43
72
  export type RemovePackageFromWorkspaceInput = AddPackageToWorkspaceInput;
44
73
  export type RemovePackageFromWorkspaceOutput = AddPackageToWorkspaceOutput;
@@ -57,6 +86,7 @@ export interface InitProjectOutput {
57
86
  };
58
87
  }
59
88
  export interface CreateWorkspaceInput {
89
+ mirrorOf?: string;
60
90
  name: string;
61
91
  }
62
92
  export type CreateWorkspaceOutput = {
@@ -92,21 +122,7 @@ export type GetWorkspaceOutput = {
92
122
  } | {
93
123
  found: true;
94
124
  hasError: false;
95
- workspace: {
96
- env?: {
97
- [key: string]: string;
98
- };
99
- id: string;
100
- name: string;
101
- packages?: {
102
- [key: string]: {
103
- parameters?: {
104
- [key: string]: string;
105
- };
106
- version: string;
107
- };
108
- };
109
- };
125
+ workspace: Workspace;
110
126
  });
111
127
  export type GetStateInput = {
112
128
  project: string;
@@ -141,9 +157,7 @@ export type GetProvisioningIdOutput = {
141
157
  success: false;
142
158
  };
143
159
  export type SetEnvVarInput = {
144
- infra: InfrastructureType;
145
160
  name: string;
146
- sensitive?: boolean;
147
161
  value: string;
148
162
  workspace: string;
149
163
  };
@@ -1 +1,13 @@
1
- export {};
1
+ import { z } from 'zod';
2
+ export const WorkspaceSchema = z.object({
3
+ env: z.record(z.string()).optional(),
4
+ id: z.string().min(2),
5
+ mirrorOf: z.string().optional(),
6
+ name: z.string().min(2),
7
+ packages: z
8
+ .record(z.object({
9
+ parameters: z.record(z.any()).optional(),
10
+ version: z.string(),
11
+ }))
12
+ .optional(),
13
+ });
@@ -9,6 +9,7 @@ export declare class LocalBackend implements Backend {
9
9
  getWorkspace(workspace: string): Promise<GetWorkspaceOutput>;
10
10
  getWorkspaceEnv(input: GetWorkspaceEnvInput): Promise<GetWorkspaceEnvOutput>;
11
11
  init(options: InitProjectInput): Promise<InitProjectOutput>;
12
+ listWorkspaces(): Promise<string[]>;
12
13
  removePackageFromWorkspace(input: RemovePackageFromWorkspaceInput): Promise<RemovePackageFromWorkspaceOutput>;
13
14
  saveState(config: Config, workspace?: string): Promise<void>;
14
15
  setEnvVar(input: SetEnvVarInput): Promise<SetEnvVarOutput>;
@@ -1,22 +1,9 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
- import { z } from 'zod';
5
- import { getExecutor } from '../executor/index.js';
6
- import { getInfrastructure } from '../infrastructure/index.js';
7
4
  import { getAnyPath } from '../lib/filesystem.js';
8
5
  import { load, save } from '../lib/yaml-utils.js';
9
- const WorkspaceSchema = z.object({
10
- env: z.record(z.string()).optional(),
11
- id: z.string().min(2),
12
- name: z.string().min(2),
13
- packages: z
14
- .record(z.object({
15
- parameters: z.record(z.any()).optional(),
16
- version: z.string(),
17
- }))
18
- .optional(),
19
- });
6
+ import { WorkspaceSchema, } from './common.js';
20
7
  export class LocalBackend {
21
8
  async addPackageToWorkspace(input) {
22
9
  const workspace$ = await this.getWorkspace(input.workspace);
@@ -33,6 +20,12 @@ export class LocalBackend {
33
20
  };
34
21
  }
35
22
  const { workspace } = workspace$;
23
+ if (workspace.mirrorOf) {
24
+ return {
25
+ reason: `Cannot add package to mirrored workspace ${input.workspace}`,
26
+ success: false,
27
+ };
28
+ }
36
29
  workspace.packages = {
37
30
  ...workspace.packages,
38
31
  [input.package]: {
@@ -73,8 +66,24 @@ export class LocalBackend {
73
66
  workspace: workspace$.workspace,
74
67
  };
75
68
  }
69
+ if (input.mirrorOf) {
70
+ const mirroredWorkspace$ = await this.getWorkspace(input.mirrorOf);
71
+ if (!mirroredWorkspace$.found) {
72
+ return {
73
+ reason: `Mirrored workspace ${input.mirrorOf} not found`,
74
+ success: false,
75
+ };
76
+ }
77
+ if (mirroredWorkspace$.hasError) {
78
+ return {
79
+ reason: mirroredWorkspace$.error,
80
+ success: false,
81
+ };
82
+ }
83
+ }
76
84
  const workspace = {
77
85
  id: input.name,
86
+ mirrorOf: input.mirrorOf,
78
87
  name: input.name,
79
88
  };
80
89
  try {
@@ -107,7 +116,24 @@ export class LocalBackend {
107
116
  };
108
117
  }
109
118
  const { workspace } = workspace$;
110
- if (Object.keys(workspace.packages ?? {}).length > 0) {
119
+ const workspaceNames = await this.listWorkspaces();
120
+ const allWorkspaces = await Promise.all(workspaceNames.map(async (workspaceName) => {
121
+ const w$ = await this.getWorkspace(workspaceName);
122
+ if (!w$.found || w$.hasError) {
123
+ throw new Error(`Workspace ${workspaceName} not found or has an error`);
124
+ }
125
+ return w$.workspace;
126
+ }));
127
+ if (allWorkspaces.some((w) => w.mirrorOf === input.name)) {
128
+ return {
129
+ reason: `Cannot delete workspace ${input.name} because it is mirrored by ${allWorkspaces
130
+ .filter((w) => w.mirrorOf === input.name)
131
+ .map((w) => w.name)
132
+ .join(', ')}`,
133
+ success: false,
134
+ };
135
+ }
136
+ if (!workspace.mirrorOf && Object.keys(workspace.packages ?? {}).length > 0) {
111
137
  return {
112
138
  reason: `Cannot delete workspace ${input.name} because it has packages`,
113
139
  success: false,
@@ -147,24 +173,66 @@ export class LocalBackend {
147
173
  }
148
174
  async getWorkspace(workspace) {
149
175
  const workspacePath = await getAnyPath(path.join(os.homedir(), '.hereya', 'state', 'workspaces', `${workspace}.yaml`), path.join(os.homedir(), '.hereya', 'state', 'workspaces', `${workspace}.yml`));
150
- const { data, found } = await load(workspacePath);
151
- if (found) {
152
- const workspace$ = WorkspaceSchema.safeParse(data);
153
- if (!workspace$.success) {
176
+ const { data, error, found } = await load(workspacePath);
177
+ if (error) {
178
+ return {
179
+ error,
180
+ found: true,
181
+ hasError: true,
182
+ };
183
+ }
184
+ if (!found) {
185
+ return {
186
+ found: false,
187
+ };
188
+ }
189
+ const workspace$ = WorkspaceSchema.safeParse(data);
190
+ if (!workspace$.success) {
191
+ return {
192
+ error: workspace$.error.message,
193
+ found: true,
194
+ hasError: true,
195
+ };
196
+ }
197
+ let mirroredWorkspace;
198
+ if (workspace$.data.mirrorOf) {
199
+ const mirroredWorkspace$ = await this.getWorkspace(workspace$.data.mirrorOf);
200
+ if (!mirroredWorkspace$.found) {
154
201
  return {
155
- error: workspace$.error.message,
202
+ error: `Mirrored workspace ${workspace$.data.mirrorOf} not found`,
156
203
  found: true,
157
204
  hasError: true,
158
205
  };
159
206
  }
160
- return {
161
- found: true,
162
- hasError: false,
163
- workspace: workspace$.data,
164
- };
207
+ if (mirroredWorkspace$.hasError) {
208
+ return {
209
+ error: mirroredWorkspace$.error,
210
+ found: true,
211
+ hasError: true,
212
+ };
213
+ }
214
+ mirroredWorkspace = mirroredWorkspace$.workspace;
165
215
  }
166
216
  return {
167
- found: false,
217
+ found: true,
218
+ hasError: false,
219
+ workspace: mirroredWorkspace
220
+ ? {
221
+ ...workspace$.data,
222
+ env: {
223
+ ...mirroredWorkspace.env,
224
+ ...workspace$.data.env,
225
+ },
226
+ packages: {
227
+ ...mirroredWorkspace.packages,
228
+ },
229
+ }
230
+ : {
231
+ ...workspace$.data,
232
+ packages: {
233
+ ...workspace$.data.packages,
234
+ },
235
+ },
168
236
  };
169
237
  }
170
238
  async getWorkspaceEnv(input) {
@@ -181,16 +249,8 @@ export class LocalBackend {
181
249
  success: false,
182
250
  };
183
251
  }
184
- const executor$ = getExecutor();
185
- if (!executor$.success) {
186
- return {
187
- reason: executor$.reason,
188
- success: false,
189
- };
190
- }
191
- const { executor } = executor$;
192
252
  return {
193
- env: await executor.resolveEnvValues({ env: workspace$.workspace.env ?? {} }),
253
+ env: workspace$.workspace.env ?? {},
194
254
  success: true,
195
255
  };
196
256
  }
@@ -206,6 +266,11 @@ export class LocalBackend {
206
266
  },
207
267
  };
208
268
  }
269
+ async listWorkspaces() {
270
+ const workspacesPath = path.join(os.homedir(), '.hereya', 'state', 'workspaces');
271
+ const workspaces = await fs.readdir(workspacesPath);
272
+ return workspaces.map((workspace) => workspace.replace(/\.yaml|\.yml$/, '')).sort();
273
+ }
209
274
  async removePackageFromWorkspace(input) {
210
275
  const workspace$ = await this.getWorkspace(input.workspace);
211
276
  if (!workspace$.found) {
@@ -221,6 +286,12 @@ export class LocalBackend {
221
286
  };
222
287
  }
223
288
  const { workspace } = workspace$;
289
+ if (workspace.mirrorOf) {
290
+ return {
291
+ reason: `Cannot remove package from mirrored workspace ${input.workspace}`,
292
+ success: false,
293
+ };
294
+ }
224
295
  workspace.packages = Object.fromEntries(Object.entries(workspace.packages ?? {}).filter(([key]) => key !== input.package));
225
296
  workspace.env = Object.fromEntries(Object.entries(workspace.env ?? {}).filter(([key]) => !(key in input.env)));
226
297
  try {
@@ -263,29 +334,9 @@ export class LocalBackend {
263
334
  };
264
335
  }
265
336
  const { workspace } = workspace$;
266
- const infrastructure$ = getInfrastructure({ type: input.infra });
267
- if (!infrastructure$.supported) {
268
- return {
269
- reason: `Infrastructure ${input.infra} not found`,
270
- success: false,
271
- };
272
- }
273
- const { infrastructure } = infrastructure$;
274
- const setEnvVarOutput = await infrastructure.storeEnv({
275
- name: input.name,
276
- oldValue: workspace.env?.[input.name]?.split(':').slice(1).join(':'),
277
- sensitive: input.sensitive,
278
- value: input.value,
279
- });
280
- if (!setEnvVarOutput.success) {
281
- return {
282
- reason: setEnvVarOutput.reason,
283
- success: false,
284
- };
285
- }
286
337
  workspace.env = {
287
338
  ...workspace.env,
288
- [input.name]: `${input.infra}:${setEnvVarOutput.value}`,
339
+ [input.name]: input.value,
289
340
  };
290
341
  await this.saveWorkspace(workspace, input.workspace);
291
342
  return {
@@ -313,24 +364,6 @@ export class LocalBackend {
313
364
  success: true,
314
365
  };
315
366
  }
316
- const infra = value.split(':')[0];
317
- const infrastructure$ = getInfrastructure({ type: infra });
318
- if (!infrastructure$.supported) {
319
- return {
320
- reason: `Infrastructure ${infra} not found`,
321
- success: false,
322
- };
323
- }
324
- const { infrastructure } = infrastructure$;
325
- const unsetEnvVarOutput = await infrastructure.unstoreEnv({
326
- value: value.split(':').slice(1).join(':'),
327
- });
328
- if (!unsetEnvVarOutput.success) {
329
- return {
330
- reason: unsetEnvVarOutput.reason,
331
- success: false,
332
- };
333
- }
334
367
  workspace.env = Object.fromEntries(Object.entries(workspace.env ?? {}).filter(([key]) => key !== input.name));
335
368
  await this.saveWorkspace(workspace, input.workspace);
336
369
  return {
@@ -1,6 +1,7 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
2
  import path from 'node:path';
3
3
  import { getConfigManager } from '../../../lib/config/index.js';
4
+ import { getEnvManager } from '../../../lib/env/index.js';
4
5
  import { getAnyPath } from '../../../lib/filesystem.js';
5
6
  import { load, save } from '../../../lib/yaml-utils.js';
6
7
  export default class EnvSet extends Command {
@@ -40,13 +41,11 @@ export default class EnvSet extends Command {
40
41
  this.warn(`Project not initialized. Run 'hereya init' first.`);
41
42
  return;
42
43
  }
43
- const rootDir = projectRootDir ?? process.cwd();
44
+ const envManager = getEnvManager();
45
+ const envDir = await envManager.getStaticEnvDir(projectRootDir);
44
46
  const candidates = flags.workspace
45
- ? [
46
- path.join(rootDir, 'hereyastaticenv', `env.${flags.workspace}.yaml`),
47
- path.join(rootDir, 'hereyastaticenv', `env.${flags.workspace}.yml`),
48
- ]
49
- : [path.join(rootDir, 'hereyastaticenv', `env.yaml`), path.join(rootDir, 'hereyastaticenv', `env.yml`)];
47
+ ? [path.join(envDir, `env.${flags.workspace}.yaml`), path.join(envDir, `env.${flags.workspace}.yml`)]
48
+ : [path.join(envDir, `env.yaml`), path.join(envDir, `env.yml`)];
50
49
  const envFile = await getAnyPath(...candidates);
51
50
  const { data: env } = await load(envFile);
52
51
  env[args.name] = flags.value;
@@ -5,5 +5,8 @@ export default class WorkspaceCreate extends Command {
5
5
  };
6
6
  static description: string;
7
7
  static examples: string[];
8
+ static flags: {
9
+ mirror: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ };
8
11
  run(): Promise<void>;
9
12
  }
@@ -1,17 +1,21 @@
1
- import { Args, Command } from '@oclif/core';
1
+ import { Args, Command, Flags } from '@oclif/core';
2
2
  import { getBackend } from '../../../backend/index.js';
3
3
  export default class WorkspaceCreate extends Command {
4
4
  static args = {
5
5
  name: Args.string({ description: 'name of the workspace to create', required: true }),
6
6
  };
7
7
  static description = 'Create a new workspace if it does not exist.';
8
- static examples = [
9
- '<%= config.bin %> <%= command.id %> dev',
10
- ];
8
+ static examples = ['<%= config.bin %> <%= command.id %> dev'];
9
+ static flags = {
10
+ mirror: Flags.string({ description: 'workspace to mirror', required: false }),
11
+ };
11
12
  async run() {
12
- const { args } = await this.parse(WorkspaceCreate);
13
+ const { args, flags } = await this.parse(WorkspaceCreate);
13
14
  const backend = await getBackend();
14
- const createWorkspaceOutput = await backend.createWorkspace({ name: args.name });
15
+ const createWorkspaceOutput = await backend.createWorkspace({
16
+ mirrorOf: flags.mirror,
17
+ name: args.name,
18
+ });
15
19
  if (!createWorkspaceOutput.success) {
16
20
  this.error(`Failed to create workspace: ${createWorkspaceOutput.reason}`);
17
21
  }
@@ -1,5 +1,6 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
2
  import { getBackend } from '../../../backend/index.js';
3
+ import { getExecutor } from '../../../executor/index.js';
3
4
  import { logEnv } from '../../../lib/env-utils.js';
4
5
  export default class WorkspaceEnv extends Command {
5
6
  static args = {
@@ -43,6 +44,12 @@ export default class WorkspaceEnv extends Command {
43
44
  this.log(Object.keys(env).join('\n'));
44
45
  return;
45
46
  }
46
- logEnv(env);
47
+ const executor$ = getExecutor();
48
+ if (!executor$.success) {
49
+ this.error(executor$.reason);
50
+ }
51
+ const { executor } = executor$;
52
+ const resolvedEnv = await executor.resolveEnvValues({ env });
53
+ logEnv(resolvedEnv);
47
54
  }
48
55
  }
@@ -1,5 +1,5 @@
1
1
  import { Command, Flags } from '@oclif/core';
2
- import { getBackend } from '../../../../backend/index.js';
2
+ import { getExecutor } from '../../../../executor/index.js';
3
3
  export default class WorkspaceEnvSet extends Command {
4
4
  static description = 'set an env var for a workspace';
5
5
  static examples = ['<%= config.bin %> <%= command.id %> -w my-workspace -n myVar -v my-value -i aws -s'];
@@ -16,15 +16,12 @@ export default class WorkspaceEnvSet extends Command {
16
16
  };
17
17
  async run() {
18
18
  const { flags } = await this.parse(WorkspaceEnvSet);
19
- const backend = await getBackend();
20
- const getWorkspaceOutput = await backend.getWorkspace(flags.workspace);
21
- if (!getWorkspaceOutput.found) {
22
- this.error(`Workspace ${flags.workspace} not found`);
19
+ const executor$ = getExecutor();
20
+ if (!executor$.success) {
21
+ this.error(executor$.reason);
23
22
  }
24
- if (getWorkspaceOutput.hasError) {
25
- this.error(getWorkspaceOutput.error);
26
- }
27
- const setEnvVarOutput = await backend.setEnvVar({
23
+ const { executor } = executor$;
24
+ const setEnvVarOutput = await executor.setEnvVar({
28
25
  infra: flags.infra,
29
26
  name: flags.name,
30
27
  sensitive: flags.sensitive,
@@ -1,5 +1,5 @@
1
1
  import { Command, Flags } from '@oclif/core';
2
- import { getBackend } from '../../../../backend/index.js';
2
+ import { getExecutor } from '../../../../executor/index.js';
3
3
  export default class WorkspaceEnvUnset extends Command {
4
4
  static description = 'unset an env var for a workspace';
5
5
  static examples = ['<%= config.bin %> <%= command.id %> -w my-workspace -n myVar'];
@@ -13,15 +13,12 @@ export default class WorkspaceEnvUnset extends Command {
13
13
  };
14
14
  async run() {
15
15
  const { flags } = await this.parse(WorkspaceEnvUnset);
16
- const backend = await getBackend();
17
- const getWorkspaceOutput = await backend.getWorkspace(flags.workspace);
18
- if (!getWorkspaceOutput.found) {
19
- this.error(`Workspace ${flags.workspace} not found`);
16
+ const executor$ = getExecutor();
17
+ if (!executor$.success) {
18
+ this.error(executor$.reason);
20
19
  }
21
- if (getWorkspaceOutput.hasError) {
22
- this.error(getWorkspaceOutput.error);
23
- }
24
- const unsetEnvVarOutput = await backend.unsetEnvVar({
20
+ const { executor } = executor$;
21
+ const unsetEnvVarOutput = await executor.unsetEnvVar({
25
22
  name: flags.name,
26
23
  workspace: flags.workspace,
27
24
  });
@@ -51,6 +51,9 @@ export default class WorkspaceInstall extends Command {
51
51
  if (!loadWorkspaceOutput.found || loadWorkspaceOutput.hasError) {
52
52
  throw new Error(`Workspace ${flags.workspace} not found`);
53
53
  }
54
+ if (loadWorkspaceOutput.workspace.mirrorOf) {
55
+ throw new Error(`Workspace ${flags.workspace} is a mirror of ${loadWorkspaceOutput.workspace.mirrorOf}`);
56
+ }
54
57
  ctx.workspace = loadWorkspaceOutput;
55
58
  await delay(500);
56
59
  },
@@ -0,0 +1,6 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class WorkspaceList extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ import { getBackend } from '../../../backend/index.js';
3
+ export default class WorkspaceList extends Command {
4
+ static description = 'List workspaces.';
5
+ static examples = ['<%= config.bin %> <%= command.id %>'];
6
+ async run() {
7
+ await this.parse(WorkspaceList);
8
+ const backend = await getBackend();
9
+ const output = await backend.listWorkspaces();
10
+ this.log(output.join('\n'));
11
+ }
12
+ }
@@ -51,6 +51,9 @@ export default class WorkspaceUninstall extends Command {
51
51
  if (!loadWorkspaceOutput.found || loadWorkspaceOutput.hasError) {
52
52
  throw new Error(`Workspace ${flags.workspace} not found`);
53
53
  }
54
+ if (loadWorkspaceOutput.workspace.mirrorOf) {
55
+ throw new Error(`Workspace ${flags.workspace} is a mirror of ${loadWorkspaceOutput.workspace.mirrorOf}`);
56
+ }
54
57
  if (!(args.package in (loadWorkspaceOutput.workspace.packages ?? {}))) {
55
58
  throw new Error(`Package ${args.package} not found in workspace ${flags.workspace}`);
56
59
  }
@@ -1,3 +1,4 @@
1
+ import { InfrastructureType } from '../infrastructure/common.js';
1
2
  import { Logger } from '../lib/log.js';
2
3
  import { IPackageMetadata } from '../lib/package/index.js';
3
4
  export type ExecutorProvisionInput = {
@@ -36,8 +37,33 @@ export type ExecutorResolveEnvValuesInput = {
36
37
  export type ExecutorResolveEnvValuesOutput = {
37
38
  [key: string]: string;
38
39
  };
40
+ export type ExecutorSetEnvVarInput = {
41
+ infra: InfrastructureType;
42
+ name: string;
43
+ sensitive?: boolean;
44
+ value: string;
45
+ workspace: string;
46
+ };
47
+ export type ExecutorSetEnvVarOutput = {
48
+ reason: string;
49
+ success: false;
50
+ } | {
51
+ success: true;
52
+ };
53
+ export type ExecutorUnsetEnvVarOutput = {
54
+ reason: string;
55
+ success: false;
56
+ } | {
57
+ success: true;
58
+ };
59
+ export type ExecutorUnsetEnvVarInput = {
60
+ name: string;
61
+ workspace: string;
62
+ };
39
63
  export interface Executor {
40
64
  destroy(input: ExecutorDestroyInput): Promise<ExecutorDestroyOutput>;
41
65
  provision(input: ExecutorProvisionInput): Promise<ExecutorProvisionOutput>;
42
66
  resolveEnvValues(input: ExecutorResolveEnvValuesInput): Promise<ExecutorResolveEnvValuesOutput>;
67
+ setEnvVar(input: ExecutorSetEnvVarInput): Promise<ExecutorSetEnvVarOutput>;
68
+ unsetEnvVar(input: ExecutorUnsetEnvVarInput): Promise<ExecutorUnsetEnvVarOutput>;
43
69
  }
@@ -1,7 +1,9 @@
1
- import { Executor, ExecutorDestroyInput, ExecutorDestroyOutput, ExecutorProvisionInput, ExecutorProvisionOutput, ExecutorResolveEnvValuesInput, ExecutorResolveEnvValuesOutput } from './interface.js';
1
+ import { Executor, ExecutorDestroyInput, ExecutorDestroyOutput, ExecutorProvisionInput, ExecutorProvisionOutput, ExecutorResolveEnvValuesInput, ExecutorResolveEnvValuesOutput, ExecutorSetEnvVarInput, ExecutorSetEnvVarOutput, ExecutorUnsetEnvVarInput, ExecutorUnsetEnvVarOutput } from './interface.js';
2
2
  export declare class LocalExecutor implements Executor {
3
3
  destroy(input: ExecutorDestroyInput): Promise<ExecutorDestroyOutput>;
4
4
  provision(input: ExecutorProvisionInput): Promise<ExecutorProvisionOutput>;
5
5
  resolveEnvValues(input: ExecutorResolveEnvValuesInput): Promise<ExecutorResolveEnvValuesOutput>;
6
+ setEnvVar(input: ExecutorSetEnvVarInput): Promise<ExecutorSetEnvVarOutput>;
7
+ unsetEnvVar(input: ExecutorUnsetEnvVarInput): Promise<ExecutorUnsetEnvVarOutput>;
6
8
  private getWorkspaceEnv;
7
9
  }
@@ -45,14 +45,96 @@ export class LocalExecutor {
45
45
  return [key, finalValue];
46
46
  })));
47
47
  }
48
+ async setEnvVar(input) {
49
+ const backend = await getBackend();
50
+ const workspace$ = await backend.getWorkspace(input.workspace);
51
+ if (!workspace$.found) {
52
+ return {
53
+ reason: `Workspace ${input.workspace} not found`,
54
+ success: false,
55
+ };
56
+ }
57
+ if (workspace$.hasError) {
58
+ return {
59
+ reason: workspace$.error,
60
+ success: false,
61
+ };
62
+ }
63
+ const { workspace } = workspace$;
64
+ const infrastructure$ = getInfrastructure({ type: input.infra });
65
+ if (!infrastructure$.supported) {
66
+ return { reason: `Infrastructure ${input.infra} not found`, success: false };
67
+ }
68
+ const { infrastructure } = infrastructure$;
69
+ const setEnvVarOutput = await infrastructure.storeEnv({
70
+ name: input.name,
71
+ oldValue: workspace.env?.[input.name]?.split(':').slice(1).join(':'),
72
+ sensitive: input.sensitive,
73
+ value: input.value,
74
+ });
75
+ if (!setEnvVarOutput.success) {
76
+ return { reason: setEnvVarOutput.reason, success: false };
77
+ }
78
+ return backend.setEnvVar({
79
+ name: input.name,
80
+ value: `${input.infra}:${setEnvVarOutput.value}`,
81
+ workspace: input.workspace,
82
+ });
83
+ }
84
+ async unsetEnvVar(input) {
85
+ const backend = await getBackend();
86
+ const workspace$ = await backend.getWorkspace(input.workspace);
87
+ if (!workspace$.found) {
88
+ return { reason: `Workspace ${input.workspace} not found`, success: false };
89
+ }
90
+ if (workspace$.hasError) {
91
+ return { reason: workspace$.error, success: false };
92
+ }
93
+ const { workspace } = workspace$;
94
+ const value = workspace.env?.[input.name];
95
+ if (!value) {
96
+ return {
97
+ success: true,
98
+ };
99
+ }
100
+ const infra = value.split(':')[0];
101
+ const infrastructure$ = getInfrastructure({ type: infra });
102
+ if (!infrastructure$.supported) {
103
+ return {
104
+ reason: `Infrastructure ${infra} not found`,
105
+ success: false,
106
+ };
107
+ }
108
+ const { infrastructure } = infrastructure$;
109
+ const unsetEnvVarOutput = await infrastructure.unstoreEnv({
110
+ value: value.split(':').slice(1).join(':'),
111
+ });
112
+ if (!unsetEnvVarOutput.success) {
113
+ return {
114
+ reason: unsetEnvVarOutput.reason,
115
+ success: false,
116
+ };
117
+ }
118
+ return backend.unsetEnvVar({
119
+ name: input.name,
120
+ workspace: input.workspace,
121
+ });
122
+ }
48
123
  async getWorkspaceEnv({ project, workspace, }) {
49
124
  if (!workspace || !project) {
50
125
  return { env: {}, success: true };
51
126
  }
52
127
  const backend = await getBackend();
53
- return backend.getWorkspaceEnv({
128
+ const result = await backend.getWorkspaceEnv({
54
129
  project,
55
130
  workspace,
56
131
  });
132
+ if (!result.success) {
133
+ return { reason: result.reason, success: false };
134
+ }
135
+ return {
136
+ env: await this.resolveEnvValues({ env: result.env }),
137
+ success: true,
138
+ };
57
139
  }
58
140
  }
@@ -2,6 +2,7 @@ import { InfrastructureType } from '../../infrastructure/common.js';
2
2
  export declare class EnvManager {
3
3
  addProjectEnv(input: AddEnvInput): Promise<void>;
4
4
  getProjectEnv(input: GetProjectEnvInput): Promise<GetProjectEnvOutput>;
5
+ getStaticEnvDir(projectRootDir?: string): Promise<string>;
5
6
  removeProjectEnv(input: RemoveEnvInput): Promise<void>;
6
7
  private getEnvPath;
7
8
  private getUserEnvPaths;
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { getExecutor } from '../../executor/index.js';
3
- import { getAnyPath } from '../filesystem.js';
3
+ import { getAnyPath, migrateFiles } from '../filesystem.js';
4
4
  import { load, save } from '../yaml-utils.js';
5
5
  export class EnvManager {
6
6
  async addProjectEnv(input) {
@@ -33,6 +33,12 @@ export class EnvManager {
33
33
  const finalEnv = { ...resolvedEnv, ...userMergedEnv };
34
34
  return { env: finalEnv, success: true };
35
35
  }
36
+ async getStaticEnvDir(projectRootDir) {
37
+ const sourceDir = path.join(projectRootDir ?? process.cwd(), 'hereyastaticenv');
38
+ const targetDir = path.join(projectRootDir ?? process.cwd(), 'hereyaconfig', 'hereyastaticenv');
39
+ await migrateFiles(sourceDir, targetDir);
40
+ return targetDir;
41
+ }
36
42
  async removeProjectEnv(input) {
37
43
  const envPath = await this.getEnvPath(input);
38
44
  const { data: existingEnv, found } = await load(envPath);
@@ -48,8 +54,8 @@ export class EnvManager {
48
54
  }
49
55
  async getUserEnvPaths(input) {
50
56
  const paths = await Promise.all([
51
- getAnyPath(path.join(input.projectRootDir ?? process.cwd(), 'hereyastaticenv', `env.yaml`), path.join(input.projectRootDir ?? process.cwd(), 'hereyastaticenv', `env.yml`)),
52
- getAnyPath(path.join(input.projectRootDir ?? process.cwd(), 'hereyastaticenv', `env.${input.workspace}.yaml`), path.join(input.projectRootDir ?? process.cwd(), 'hereyastaticenv', `env.${input.workspace}.yml`)),
57
+ getAnyPath(path.join(await this.getStaticEnvDir(input.projectRootDir), `env.yaml`), path.join(await this.getStaticEnvDir(input.projectRootDir), `env.yml`)),
58
+ getAnyPath(path.join(await this.getStaticEnvDir(input.projectRootDir), `env.${input.workspace}.yaml`), path.join(await this.getStaticEnvDir(input.projectRootDir), `env.${input.workspace}.yml`)),
53
59
  ]);
54
60
  return paths;
55
61
  }
@@ -1,3 +1,4 @@
1
1
  export declare function getAnyPath(...candidates: string[]): Promise<string>;
2
2
  export declare function fileExists(filePath: string): Promise<boolean>;
3
3
  export declare function isNotEmpty(directoryPath: string): Promise<boolean>;
4
+ export declare function migrateFiles(sourceDir: string, targetDir: string): Promise<void>;
@@ -1,4 +1,5 @@
1
- import { access, constants, readdir } from 'node:fs/promises';
1
+ import fs, { access, constants, readdir } from 'node:fs/promises';
2
+ import path from 'node:path';
2
3
  export async function getAnyPath(...candidates) {
3
4
  const checkAccess = async (index) => {
4
5
  if (index >= candidates.length)
@@ -31,3 +32,27 @@ export async function isNotEmpty(directoryPath) {
31
32
  return false;
32
33
  }
33
34
  }
35
+ export async function migrateFiles(sourceDir, targetDir) {
36
+ const sourceDirExists = await fs
37
+ .access(sourceDir)
38
+ .then(() => true)
39
+ .catch(() => false);
40
+ if (!sourceDirExists) {
41
+ return;
42
+ }
43
+ const targetDirExists = await fs
44
+ .access(targetDir)
45
+ .then(() => true)
46
+ .catch(() => false);
47
+ if (targetDirExists) {
48
+ return;
49
+ }
50
+ await fs.mkdir(targetDir, { recursive: true });
51
+ const files = await fs.readdir(sourceDir);
52
+ await Promise.all(files.map(async (file) => {
53
+ const sourcePath = path.join(sourceDir, file);
54
+ const targetPath = path.join(targetDir, file);
55
+ await fs.rename(sourcePath, targetPath);
56
+ }));
57
+ await fs.rmdir(sourceDir);
58
+ }
@@ -0,0 +1 @@
1
+ export declare function generateRandomGuid(): string;
@@ -0,0 +1,6 @@
1
+ import crypto from 'node:crypto';
2
+ export function generateRandomGuid() {
3
+ const uuid = crypto.randomUUID();
4
+ // Remove all dashes from the UUID and add "hereya" as a prefix
5
+ return `hereya${uuid.replaceAll('-', '')}`;
6
+ }
@@ -1,6 +1,7 @@
1
1
  export declare class ParameterManager {
2
2
  getPackageParameters(input: GetPackageParametersInput): Promise<GetPackageParametersOutput>;
3
3
  savePackageParameters(input: SavePackageParametersInput): Promise<SavePackageParametersOutput>;
4
+ private getParametersFolder;
4
5
  }
5
6
  export declare const parameterManager: ParameterManager;
6
7
  export declare function getParameterManager(): ParameterManager;
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- import { getAnyPath } from '../filesystem.js';
2
+ import { getAnyPath, migrateFiles } from '../filesystem.js';
3
3
  import { getPackageCanonicalName } from '../package/index.js';
4
4
  import { load, save } from '../yaml-utils.js';
5
5
  export class ParameterManager {
@@ -9,7 +9,7 @@ export class ParameterManager {
9
9
  [`${pkgName}.yaml`, `${pkgName}.yml`],
10
10
  [`${pkgName}.${input.workspace}.yaml`, `${pkgName}.${input.workspace}.yml`],
11
11
  ].map(async ([filename, altFilename]) => {
12
- const filePath = await getAnyPath(path.join(input.projectRootDir ?? process.cwd(), 'hereyavars', filename), path.join(input.projectRootDir ?? process.cwd(), 'hereyavars', altFilename));
12
+ const filePath = await getAnyPath(path.join(await this.getParametersFolder(input.projectRootDir), filename), path.join(await this.getParametersFolder(input.projectRootDir), altFilename));
13
13
  const { data: parameters } = await load(filePath);
14
14
  return parameters;
15
15
  }));
@@ -29,7 +29,7 @@ export class ParameterManager {
29
29
  [`${pkgName}.yaml`, `${pkgName}.yml`],
30
30
  [`${pkgName}.${input.workspace}.yaml`, `${pkgName}.${input.workspace}.yml`],
31
31
  ].map(async ([filename, altFilename]) => {
32
- const filePath = await getAnyPath(path.join(input.projectRootDir ?? process.cwd(), 'hereyavars', filename), path.join(input.projectRootDir ?? process.cwd(), 'hereyavars', altFilename));
32
+ const filePath = await getAnyPath(path.join(await this.getParametersFolder(input.projectRootDir), filename), path.join(await this.getParametersFolder(input.projectRootDir), altFilename));
33
33
  const { found } = await load(filePath);
34
34
  return found;
35
35
  }));
@@ -39,13 +39,19 @@ export class ParameterManager {
39
39
  saved: false,
40
40
  };
41
41
  }
42
- const filePath = path.join(input.projectRootDir ?? process.cwd(), 'hereyavars', `${pkgName}.yaml`);
42
+ const filePath = path.join(await this.getParametersFolder(input.projectRootDir), `${pkgName}.yaml`);
43
43
  await save(input.parameters, filePath);
44
44
  return {
45
45
  filePath,
46
46
  saved: true,
47
47
  };
48
48
  }
49
+ async getParametersFolder(projectRootDir) {
50
+ const sourceDir = path.join(projectRootDir ?? process.cwd(), 'hereyavars');
51
+ const targetDir = path.join(projectRootDir ?? process.cwd(), 'hereyaconfig', 'hereyavars');
52
+ await migrateFiles(sourceDir, targetDir);
53
+ return targetDir;
54
+ }
49
55
  }
50
56
  export const parameterManager = new ParameterManager();
51
57
  export function getParameterManager() {
@@ -1,5 +1,6 @@
1
1
  export declare function save<T extends object>(content: T, file: string): Promise<void>;
2
2
  export declare function load<T extends object>(file: string): Promise<{
3
3
  data: T;
4
+ error?: string;
4
5
  found: boolean;
5
6
  }>;
@@ -20,7 +20,7 @@ export async function load(file) {
20
20
  }
21
21
  catch (error) {
22
22
  if (error.code !== 'ENOENT') {
23
- throw new Error(`could not load file ${file}: ${error}`);
23
+ return { data: {}, error: `could not load file ${file}: ${error}`, found: true };
24
24
  }
25
25
  }
26
26
  return { data: data || {}, found };
@@ -611,7 +611,16 @@
611
611
  "examples": [
612
612
  "<%= config.bin %> <%= command.id %> dev"
613
613
  ],
614
- "flags": {},
614
+ "flags": {
615
+ "mirror": {
616
+ "description": "workspace to mirror",
617
+ "name": "mirror",
618
+ "required": false,
619
+ "hasDynamicHelp": false,
620
+ "multiple": false,
621
+ "type": "option"
622
+ }
623
+ },
615
624
  "hasDynamicHelp": false,
616
625
  "hiddenAliases": [],
617
626
  "id": "workspace:create",
@@ -774,6 +783,31 @@
774
783
  "index.js"
775
784
  ]
776
785
  },
786
+ "workspace:list": {
787
+ "aliases": [],
788
+ "args": {},
789
+ "description": "List workspaces.",
790
+ "examples": [
791
+ "<%= config.bin %> <%= command.id %>"
792
+ ],
793
+ "flags": {},
794
+ "hasDynamicHelp": false,
795
+ "hiddenAliases": [],
796
+ "id": "workspace:list",
797
+ "pluginAlias": "hereya-cli",
798
+ "pluginName": "hereya-cli",
799
+ "pluginType": "core",
800
+ "strict": true,
801
+ "enableJsonFlag": false,
802
+ "isESM": true,
803
+ "relativePath": [
804
+ "dist",
805
+ "commands",
806
+ "workspace",
807
+ "list",
808
+ "index.js"
809
+ ]
810
+ },
777
811
  "workspace:uninstall": {
778
812
  "aliases": [],
779
813
  "args": {
@@ -954,5 +988,5 @@
954
988
  ]
955
989
  }
956
990
  },
957
- "version": "0.23.0"
991
+ "version": "0.25.0"
958
992
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hereya-cli",
3
3
  "description": "Infrastructure as Package",
4
- "version": "0.23.0",
4
+ "version": "0.25.0",
5
5
  "author": "Hereya Developers",
6
6
  "bin": {
7
7
  "hereya": "./bin/run.js"
@@ -90,6 +90,7 @@
90
90
  "posttest": "yarn lint",
91
91
  "prepack": "oclif manifest && oclif readme",
92
92
  "test": "mocha --forbid-only \"src/**/*.test.ts\"",
93
+ "t": "mocha --forbid-only",
93
94
  "version": "oclif readme && git add README.md",
94
95
  "doc": "yarn build && yarn run version && shx rm -rf dist"
95
96
  },