hereya-cli 0.2.1

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.
Files changed (85) hide show
  1. package/README.md +392 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +6 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +5 -0
  6. package/dist/backend/common.d.ts +126 -0
  7. package/dist/backend/common.js +1 -0
  8. package/dist/backend/index.d.ts +4 -0
  9. package/dist/backend/index.js +5 -0
  10. package/dist/backend/local.d.ts +16 -0
  11. package/dist/backend/local.js +231 -0
  12. package/dist/commands/add/index.d.ts +13 -0
  13. package/dist/commands/add/index.js +96 -0
  14. package/dist/commands/bootstrap/index.d.ts +12 -0
  15. package/dist/commands/bootstrap/index.js +28 -0
  16. package/dist/commands/down/index.d.ts +10 -0
  17. package/dist/commands/down/index.js +78 -0
  18. package/dist/commands/env/index.d.ts +10 -0
  19. package/dist/commands/env/index.js +46 -0
  20. package/dist/commands/init/index.d.ts +13 -0
  21. package/dist/commands/init/index.js +46 -0
  22. package/dist/commands/remote/exec/index.d.ts +12 -0
  23. package/dist/commands/remote/exec/index.js +65 -0
  24. package/dist/commands/remove/index.d.ts +12 -0
  25. package/dist/commands/remove/index.js +80 -0
  26. package/dist/commands/run/index.d.ts +14 -0
  27. package/dist/commands/run/index.js +60 -0
  28. package/dist/commands/up/index.d.ts +10 -0
  29. package/dist/commands/up/index.js +121 -0
  30. package/dist/commands/workspace/create/index.d.ts +9 -0
  31. package/dist/commands/workspace/create/index.js +25 -0
  32. package/dist/commands/workspace/delete/index.d.ts +9 -0
  33. package/dist/commands/workspace/delete/index.js +24 -0
  34. package/dist/commands/workspace/env/index.d.ts +9 -0
  35. package/dist/commands/workspace/env/index.js +28 -0
  36. package/dist/commands/workspace/install/index.d.ts +14 -0
  37. package/dist/commands/workspace/install/index.js +74 -0
  38. package/dist/commands/workspace/uninstall/index.d.ts +14 -0
  39. package/dist/commands/workspace/uninstall/index.js +85 -0
  40. package/dist/iac/cdk.d.ts +8 -0
  41. package/dist/iac/cdk.js +83 -0
  42. package/dist/iac/common.d.ts +29 -0
  43. package/dist/iac/common.js +5 -0
  44. package/dist/iac/index.d.ts +16 -0
  45. package/dist/iac/index.js +18 -0
  46. package/dist/iac/terraform.d.ts +6 -0
  47. package/dist/iac/terraform.js +67 -0
  48. package/dist/index.d.ts +1 -0
  49. package/dist/index.js +1 -0
  50. package/dist/infrastructure/aws.d.ts +8 -0
  51. package/dist/infrastructure/aws.js +28 -0
  52. package/dist/infrastructure/common.d.ts +59 -0
  53. package/dist/infrastructure/common.js +7 -0
  54. package/dist/infrastructure/index.d.ts +43 -0
  55. package/dist/infrastructure/index.js +82 -0
  56. package/dist/infrastructure/local.d.ts +14 -0
  57. package/dist/infrastructure/local.js +81 -0
  58. package/dist/lib/config/common.d.ts +34 -0
  59. package/dist/lib/config/common.js +1 -0
  60. package/dist/lib/config/index.d.ts +3 -0
  61. package/dist/lib/config/index.js +5 -0
  62. package/dist/lib/config/simple.d.ts +8 -0
  63. package/dist/lib/config/simple.js +41 -0
  64. package/dist/lib/env/index.d.ts +27 -0
  65. package/dist/lib/env/index.js +42 -0
  66. package/dist/lib/env-utils.d.ts +8 -0
  67. package/dist/lib/env-utils.js +20 -0
  68. package/dist/lib/filesystem.d.ts +1 -0
  69. package/dist/lib/filesystem.js +15 -0
  70. package/dist/lib/object-utils.d.ts +4 -0
  71. package/dist/lib/object-utils.js +9 -0
  72. package/dist/lib/package/common.d.ts +15 -0
  73. package/dist/lib/package/common.js +1 -0
  74. package/dist/lib/package/github.d.ts +4 -0
  75. package/dist/lib/package/github.js +32 -0
  76. package/dist/lib/package/index.d.ts +30 -0
  77. package/dist/lib/package/index.js +45 -0
  78. package/dist/lib/parameter/index.d.ts +34 -0
  79. package/dist/lib/parameter/index.js +47 -0
  80. package/dist/lib/shell.d.ts +9 -0
  81. package/dist/lib/shell.js +16 -0
  82. package/dist/lib/yaml-utils.d.ts +5 -0
  83. package/dist/lib/yaml-utils.js +27 -0
  84. package/oclif.manifest.json +610 -0
  85. package/package.json +86 -0
@@ -0,0 +1,231 @@
1
+ import fs from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { z } from 'zod';
5
+ import { resolveEnvValues } from '../lib/env-utils.js';
6
+ import { getAnyPath } from '../lib/filesystem.js';
7
+ import { load, save } from '../lib/yaml-utils.js';
8
+ const WorkspaceSchema = z.object({
9
+ env: z.record(z.string()).optional(),
10
+ id: z.string().min(2),
11
+ name: z.string().min(2),
12
+ packages: z.record(z.object({
13
+ parameters: z.record(z.any()).optional(),
14
+ version: z.string(),
15
+ })).optional(),
16
+ });
17
+ export class LocalBackend {
18
+ async addPackageToWorkspace(input) {
19
+ const workspace$ = await this.getWorkspace(input.workspace);
20
+ if (!workspace$.found) {
21
+ return {
22
+ reason: `Workspace ${input.workspace} not found`,
23
+ success: false,
24
+ };
25
+ }
26
+ if (workspace$.hasError) {
27
+ return {
28
+ reason: workspace$.error,
29
+ success: false,
30
+ };
31
+ }
32
+ const { workspace } = workspace$;
33
+ workspace.packages = {
34
+ ...workspace.packages,
35
+ [input.package]: {
36
+ parameters: input.parameters,
37
+ version: '',
38
+ },
39
+ };
40
+ const newEnv = Object.fromEntries(Object.entries(input.env)
41
+ .map(([key, value]) => [key, `${input.infra}:${value}`]));
42
+ workspace.env = {
43
+ ...workspace.env,
44
+ ...newEnv,
45
+ };
46
+ try {
47
+ await this.saveWorkspace(workspace, input.workspace);
48
+ return {
49
+ success: true,
50
+ workspace,
51
+ };
52
+ }
53
+ catch (error) {
54
+ return {
55
+ reason: error.message,
56
+ success: false,
57
+ };
58
+ }
59
+ }
60
+ async createWorkspace(input) {
61
+ const workspace$ = await this.getWorkspace(input.name);
62
+ if (workspace$.found) {
63
+ return workspace$.hasError ? {
64
+ reason: workspace$.error,
65
+ success: false,
66
+ } : {
67
+ isNew: false,
68
+ success: true,
69
+ workspace: workspace$.workspace,
70
+ };
71
+ }
72
+ const workspace = {
73
+ id: input.name,
74
+ name: input.name,
75
+ };
76
+ try {
77
+ await this.saveWorkspace(workspace, input.name);
78
+ return {
79
+ isNew: true,
80
+ success: true,
81
+ workspace,
82
+ };
83
+ }
84
+ catch (error) {
85
+ return {
86
+ reason: error.message,
87
+ success: false,
88
+ };
89
+ }
90
+ }
91
+ async deleteWorkspace(input) {
92
+ const workspace$ = await this.getWorkspace(input.name);
93
+ if (!workspace$.found) {
94
+ return {
95
+ message: `Workspace ${input.name} does not exist`,
96
+ success: true,
97
+ };
98
+ }
99
+ if (workspace$.hasError) {
100
+ return {
101
+ reason: workspace$.error,
102
+ success: false,
103
+ };
104
+ }
105
+ const { workspace } = workspace$;
106
+ if (Object.keys(workspace.packages ?? {}).length > 0) {
107
+ return {
108
+ reason: `Cannot delete workspace ${input.name} because it has packages`,
109
+ success: false,
110
+ };
111
+ }
112
+ const workspacePath = await this.getWorkspacePath(input.name);
113
+ await fs.rm(workspacePath);
114
+ return {
115
+ success: true,
116
+ };
117
+ }
118
+ async getState(input) {
119
+ const projectStatePath = await this.getProjectStatePath(input.project);
120
+ const { data, found } = await load(projectStatePath);
121
+ if (found) {
122
+ return {
123
+ config: data,
124
+ found: true,
125
+ };
126
+ }
127
+ return {
128
+ found: false,
129
+ };
130
+ }
131
+ async getWorkspace(workspace) {
132
+ const workspacePath = await getAnyPath(path.join(os.homedir(), '.hereya', 'state', 'workspaces', `${workspace}.yaml`), path.join(os.homedir(), '.hereya', 'state', 'workspaces', `${workspace}.yml`));
133
+ const { data, found } = await load(workspacePath);
134
+ if (found) {
135
+ const workspace$ = WorkspaceSchema.safeParse(data);
136
+ if (!workspace$.success) {
137
+ return {
138
+ error: workspace$.error.message,
139
+ found: true,
140
+ hasError: true,
141
+ };
142
+ }
143
+ return {
144
+ found: true,
145
+ hasError: false,
146
+ workspace: workspace$.data,
147
+ };
148
+ }
149
+ return {
150
+ found: false,
151
+ };
152
+ }
153
+ async getWorkspaceEnv(input) {
154
+ const workspace$ = await this.getWorkspace(input.workspace);
155
+ if (!workspace$.found) {
156
+ return {
157
+ reason: `Workspace ${input.workspace} not found`,
158
+ success: false,
159
+ };
160
+ }
161
+ if (workspace$.hasError) {
162
+ return {
163
+ reason: workspace$.error,
164
+ success: false,
165
+ };
166
+ }
167
+ return {
168
+ env: await resolveEnvValues(workspace$.workspace.env ?? {}),
169
+ success: true,
170
+ };
171
+ }
172
+ async init(options) {
173
+ return {
174
+ project: {
175
+ id: options.project,
176
+ name: options.project,
177
+ },
178
+ workspace: {
179
+ id: options.workspace,
180
+ name: options.workspace,
181
+ },
182
+ };
183
+ }
184
+ async removePackageFromWorkspace(input) {
185
+ const workspace$ = await this.getWorkspace(input.workspace);
186
+ if (!workspace$.found) {
187
+ return {
188
+ reason: `Workspace ${input.workspace} not found`,
189
+ success: false,
190
+ };
191
+ }
192
+ if (workspace$.hasError) {
193
+ return {
194
+ reason: workspace$.error,
195
+ success: false,
196
+ };
197
+ }
198
+ const { workspace } = workspace$;
199
+ workspace.packages = Object.fromEntries(Object.entries(workspace.packages ?? {})
200
+ .filter(([key]) => key !== input.package));
201
+ workspace.env = Object.fromEntries(Object.entries(workspace.env ?? {})
202
+ .filter(([key]) => !(key in input.env)));
203
+ try {
204
+ await this.saveWorkspace(workspace, input.workspace);
205
+ return {
206
+ success: true,
207
+ workspace,
208
+ };
209
+ }
210
+ catch (error) {
211
+ return {
212
+ reason: error.message,
213
+ success: false,
214
+ };
215
+ }
216
+ }
217
+ async saveState(config) {
218
+ const projectStatePath = await this.getProjectStatePath(config.project);
219
+ await save(config, projectStatePath);
220
+ }
221
+ async getProjectStatePath(project) {
222
+ return getAnyPath(path.join(os.homedir(), '.hereya', 'state', 'projects', `${project}.yaml`), path.join(os.homedir(), '.hereya', 'state', 'projects', `${project}.yml`));
223
+ }
224
+ async getWorkspacePath(name) {
225
+ return getAnyPath(path.join(os.homedir(), '.hereya', 'state', 'workspaces', `${name}.yaml`), path.join(os.homedir(), '.hereya', 'state', 'workspaces', `${name}.yml`));
226
+ }
227
+ async saveWorkspace(data, name) {
228
+ const workspacePath = await this.getWorkspacePath(name);
229
+ await save(data, workspacePath);
230
+ }
231
+ }
@@ -0,0 +1,13 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Add extends Command {
3
+ static args: {
4
+ package: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ chdir: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
10
+ parameter: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[], import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,96 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { getBackend } from '../../backend/index.js';
3
+ import { provisionPackage } from '../../infrastructure/index.js';
4
+ import { getConfigManager } from '../../lib/config/index.js';
5
+ import { getEnvManager } from '../../lib/env/index.js';
6
+ import { logEnv } from '../../lib/env-utils.js';
7
+ import { arrayOfStringToObject } from '../../lib/object-utils.js';
8
+ import { getParameterManager } from '../../lib/parameter/index.js';
9
+ export default class Add extends Command {
10
+ static args = {
11
+ package: Args.string({
12
+ description: 'The package to add. Packages are gitHub repositories. Use the format owner/repository',
13
+ required: true
14
+ }),
15
+ };
16
+ static description = 'Add a package to the project.';
17
+ static examples = [
18
+ '<%= config.bin %> <%= command.id %> cloudy/docker_postgres',
19
+ ];
20
+ static flags = {
21
+ chdir: Flags.string({
22
+ description: 'directory to run command in',
23
+ required: false,
24
+ }),
25
+ parameter: Flags.string({
26
+ char: 'p',
27
+ default: [],
28
+ description: 'parameter for the package, in the form of \'key=value\'. Can be specified multiple times.',
29
+ multiple: true,
30
+ }),
31
+ };
32
+ async run() {
33
+ const { args, flags } = await this.parse(Add);
34
+ const projectRootDir = flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR;
35
+ const configManager = getConfigManager();
36
+ const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
37
+ if (!loadConfigOutput.found) {
38
+ this.warn(`Project not initialized. Run 'hereya init' first.`);
39
+ return;
40
+ }
41
+ const { config } = loadConfigOutput;
42
+ const backend = await getBackend();
43
+ const getWorkspaceEnvOutput = await backend.getWorkspaceEnv({
44
+ project: config.project,
45
+ workspace: config.workspace,
46
+ });
47
+ if (!getWorkspaceEnvOutput.success) {
48
+ this.error(getWorkspaceEnvOutput.reason);
49
+ }
50
+ const { env: workspaceEnv } = getWorkspaceEnvOutput;
51
+ const userSpecifiedParameters = arrayOfStringToObject(flags.parameter);
52
+ const parameterManager = getParameterManager();
53
+ const { parameters } = await parameterManager.getPackageParameters({
54
+ package: args.package,
55
+ projectRootDir,
56
+ userSpecifiedParameters,
57
+ workspace: config.workspace,
58
+ });
59
+ const provisionOutput = await provisionPackage({
60
+ env: workspaceEnv,
61
+ package: args.package,
62
+ parameters,
63
+ project: config.project,
64
+ workspace: config.workspace,
65
+ });
66
+ if (!provisionOutput.success) {
67
+ this.error(provisionOutput.reason);
68
+ }
69
+ const { env, metadata } = provisionOutput;
70
+ this.log(`Package ${args.package} added successfully`);
71
+ this.log(`Saving exported environment variables`);
72
+ const envManager = getEnvManager();
73
+ await envManager.addProjectEnv({
74
+ env,
75
+ infra: metadata.infra,
76
+ projectRootDir,
77
+ workspace: config.workspace,
78
+ });
79
+ await configManager.addPackage({
80
+ package: args.package,
81
+ projectRootDir,
82
+ });
83
+ const { config: newConfig } = await configManager.loadConfig({ projectRootDir });
84
+ await backend.saveState(newConfig);
85
+ const { filePath, saved } = await parameterManager.savePackageParameters({
86
+ package: args.package,
87
+ parameters,
88
+ projectRootDir,
89
+ workspace: config.workspace,
90
+ });
91
+ if (saved) {
92
+ this.log(`Saved the following parameters for the package in ${filePath}:`);
93
+ logEnv(parameters, this.log.bind(this));
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Bootstrap extends Command {
3
+ static args: {
4
+ infrastructureType: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ force: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,28 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { getInfrastructure } from '../../infrastructure/index.js';
3
+ export default class Bootstrap extends Command {
4
+ static args = {
5
+ infrastructureType: Args.string({
6
+ description: 'infrastructure to bootstrap. Options are local, aws, azure, gcp',
7
+ required: true
8
+ })
9
+ };
10
+ static description = 'Install necessary resources for hereya operations in an infrastructure.';
11
+ static examples = [
12
+ '<%= config.bin %> <%= command.id %> aws',
13
+ '<%= config.bin %> <%= command.id %> local'
14
+ ];
15
+ static flags = {
16
+ force: Flags.boolean({ char: 'f', description: 'redeploy hereya resources if already deployed' }),
17
+ };
18
+ async run() {
19
+ const { args, flags } = await this.parse(Bootstrap);
20
+ const infrastructure$ = getInfrastructure({ type: args.infrastructureType });
21
+ if (!infrastructure$.supported) {
22
+ this.warn(infrastructure$.reason);
23
+ return;
24
+ }
25
+ const { infrastructure } = infrastructure$;
26
+ await infrastructure.bootstrap({ force: flags.force });
27
+ }
28
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Down 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,78 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getBackend } from '../../backend/index.js';
3
+ import { destroyPackage } from '../../infrastructure/index.js';
4
+ import { getConfigManager } from '../../lib/config/index.js';
5
+ import { getEnvManager } from '../../lib/env/index.js';
6
+ import { getParameterManager } from '../../lib/parameter/index.js';
7
+ export default class Down extends Command {
8
+ static description = 'Destroy all packages in the project.';
9
+ static examples = [
10
+ '<%= config.bin %> <%= command.id %>',
11
+ ];
12
+ static flags = {
13
+ chdir: Flags.string({
14
+ description: 'directory to run command in',
15
+ required: false,
16
+ }),
17
+ workspace: Flags.string({
18
+ char: 'w',
19
+ description: 'name of the workspace to install the packages for',
20
+ required: false,
21
+ }),
22
+ };
23
+ async run() {
24
+ const { flags } = await this.parse(Down);
25
+ const projectRootDir = flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR;
26
+ const configManager = getConfigManager();
27
+ const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
28
+ if (!loadConfigOutput.found) {
29
+ this.warn(`Project not initialized. Run 'hereya init' first.`);
30
+ return;
31
+ }
32
+ const { config } = loadConfigOutput;
33
+ const packages = Object.keys(config.packages ?? {});
34
+ const workspace = flags.workspace || config.workspace;
35
+ const backend = await getBackend();
36
+ const getWorkspaceEnvOutput = await backend.getWorkspaceEnv({
37
+ project: config.project,
38
+ workspace,
39
+ });
40
+ if (!getWorkspaceEnvOutput.success) {
41
+ this.error(getWorkspaceEnvOutput.reason);
42
+ }
43
+ const { env: workspaceEnv } = getWorkspaceEnvOutput;
44
+ const parameterManager = getParameterManager();
45
+ const result = await Promise.all(packages.map(async (packageName) => {
46
+ const { parameters } = await parameterManager.getPackageParameters({
47
+ package: packageName,
48
+ projectRootDir,
49
+ workspace,
50
+ });
51
+ const destroyOutput = await destroyPackage({
52
+ env: workspaceEnv,
53
+ package: packageName,
54
+ parameters,
55
+ project: config.project,
56
+ workspace,
57
+ });
58
+ if (!destroyOutput.success) {
59
+ this.error(destroyOutput.reason);
60
+ }
61
+ this.log(`Package ${packageName} destroyed successfully`);
62
+ const { env, metadata } = destroyOutput;
63
+ return { env, metadata, packageName };
64
+ }));
65
+ const envManager = getEnvManager();
66
+ for (const { env, metadata } of result) {
67
+ // eslint-disable-next-line no-await-in-loop
68
+ await envManager.removeProjectEnv({
69
+ env,
70
+ infra: metadata.infra,
71
+ projectRootDir,
72
+ workspace,
73
+ });
74
+ }
75
+ const { config: newConfig } = await configManager.loadConfig({ projectRootDir });
76
+ await backend.saveState(newConfig);
77
+ }
78
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Env 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,46 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getConfigManager } from '../../lib/config/index.js';
3
+ import { getEnvManager } from '../../lib/env/index.js';
4
+ import { logEnv } from '../../lib/env-utils.js';
5
+ export default class Env extends Command {
6
+ static description = 'Print project environment variables.';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %>',
9
+ '<%= config.bin %> <%= command.id %> -w dev',
10
+ ];
11
+ static flags = {
12
+ chdir: Flags.string({
13
+ description: 'project root directory',
14
+ required: false,
15
+ }),
16
+ workspace: Flags.string({
17
+ char: 'w',
18
+ description: 'name of the workspace to print the env vars for',
19
+ required: false,
20
+ }),
21
+ };
22
+ async run() {
23
+ const { flags } = await this.parse(Env);
24
+ const projectRootDir = flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR;
25
+ const configManager = getConfigManager();
26
+ const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
27
+ if (!loadConfigOutput.found) {
28
+ this.warn(`Project not initialized. Run 'hereya init' first.`);
29
+ return;
30
+ }
31
+ const { config } = loadConfigOutput;
32
+ let { workspace } = flags;
33
+ if (!workspace) {
34
+ workspace = config.workspace;
35
+ }
36
+ if (!workspace) {
37
+ this.error('you must specify a workspace to print the env vars for');
38
+ }
39
+ const envManager = getEnvManager();
40
+ const { env } = await envManager.getProjectEnv({
41
+ projectRootDir,
42
+ workspace,
43
+ });
44
+ logEnv(env);
45
+ }
46
+ }
@@ -0,0 +1,13 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Init extends Command {
3
+ static args: {
4
+ project: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ chdir: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
10
+ workspace: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,46 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { getBackend } from '../../backend/index.js';
3
+ import { getConfigManager } from '../../lib/config/index.js';
4
+ export default class Init extends Command {
5
+ static args = {
6
+ project: Args.string({ description: 'project name', required: true }),
7
+ };
8
+ static description = 'Initialize hereya in a project directory.';
9
+ static examples = [
10
+ '<%= config.bin %> <%= command.id %> myProject -w=defaultWorkspace',
11
+ '<%= config.bin %> <%= command.id %> myProject -w=defaultWorkspace --chdir=./myProject',
12
+ ];
13
+ static flags = {
14
+ chdir: Flags.string({
15
+ description: 'directory to run command in',
16
+ required: false,
17
+ }),
18
+ workspace: Flags.string({
19
+ char: 'w',
20
+ description: 'workspace to set as default',
21
+ required: true,
22
+ }),
23
+ };
24
+ async run() {
25
+ const { args, flags } = await this.parse(Init);
26
+ const projectRootDir = flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR;
27
+ const configManager = getConfigManager();
28
+ const config$ = await configManager.loadConfig({ projectRootDir });
29
+ if (config$.found) {
30
+ this.warn(`Project already initialized.`);
31
+ return;
32
+ }
33
+ const backend = await getBackend();
34
+ const initProjectOutput = await backend.init({
35
+ project: args.project,
36
+ workspace: flags.workspace,
37
+ });
38
+ const content = {
39
+ project: initProjectOutput.project.id,
40
+ workspace: initProjectOutput.workspace.name,
41
+ };
42
+ await configManager.saveConfig({ config: content, projectRootDir });
43
+ this.log(`Initialized project ${initProjectOutput.project.name}.`);
44
+ this.log(`Current workspace set to ${initProjectOutput.workspace.name}.`);
45
+ }
46
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class RemoteExec extends Command {
3
+ static args: {
4
+ pkgPath: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ output: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,65 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { getIac } from '../../../iac/index.js';
3
+ import { getInfrastructure } from '../../../infrastructure/index.js';
4
+ import { save } from '../../../lib/yaml-utils.js';
5
+ export default class RemoteExec extends Command {
6
+ static args = {
7
+ pkgPath: Args.string({
8
+ description: 'The path to the package to provision or destroy',
9
+ required: false,
10
+ }),
11
+ };
12
+ static description = 'remotely provision or destroy a package';
13
+ static examples = [
14
+ '<%= config.bin %> <%= command.id %>',
15
+ ];
16
+ static flags = {
17
+ output: Flags.string({
18
+ char: 'o',
19
+ description: 'The path to store the output env in',
20
+ required: false,
21
+ }),
22
+ };
23
+ async run() {
24
+ const { args, flags } = await this.parse(RemoteExec);
25
+ const workspaceEnv = Object.fromEntries((process.env.HEREYA_WORKSPACE_ENV?.split(',') ?? []).map(param => param.split('=')));
26
+ const parameters = Object.fromEntries((process.env.HEREYA_PARAMETERS?.split(',') ?? []).map(param => param.split('=')));
27
+ const id = process.env.HEREYA_ID;
28
+ const iacType = process.env.HEREYA_IAC_TYPE;
29
+ const destroy = process.env.HEREYA_DESTROY === 'true';
30
+ const infraType = process.env.HEREYA_INFRA_TYPE;
31
+ if (!id || !iacType || !infraType) {
32
+ return this.error(`
33
+ Missing required environment variables:
34
+ HEREYA_ID: ${id}
35
+ HEREYA_IAC_TYPE: ${iacType}
36
+ HEREYA_INFRA_TYPE: ${infraType}
37
+ `);
38
+ }
39
+ const input = {
40
+ env: workspaceEnv, id, parameters, pkgPath: args.pkgPath || process.cwd(),
41
+ };
42
+ const iac$ = getIac({ type: iacType });
43
+ if (!iac$.supported) {
44
+ return this.error(iac$.reason);
45
+ }
46
+ const { iac } = iac$;
47
+ const output = await (destroy ? iac.destroy(input) : iac.apply(input));
48
+ if (!output.success) {
49
+ return this.error(output.reason);
50
+ }
51
+ if (flags.output) {
52
+ await save(output.env, flags.output);
53
+ this.log(`Output env saved to ${flags.output}`);
54
+ }
55
+ const infra$ = getInfrastructure({ type: infraType });
56
+ if (!infra$.supported) {
57
+ return this.error(infra$.reason);
58
+ }
59
+ const { infrastructure } = infra$;
60
+ const saveOutput = await infrastructure.saveEnv({ env: output.env, id });
61
+ if (!saveOutput.success) {
62
+ return this.error(saveOutput.reason);
63
+ }
64
+ }
65
+ }