hereya-cli 0.12.0 → 0.13.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.
@@ -3,17 +3,21 @@ import { getBackend } from '../../backend/index.js';
3
3
  import { destroyPackage, provisionPackage } from '../../infrastructure/index.js';
4
4
  import { getConfigManager } from '../../lib/config/index.js';
5
5
  import { getEnvManager } from '../../lib/env/index.js';
6
+ import { getLogger } from '../../lib/log.js';
6
7
  import { getParameterManager } from '../../lib/parameter/index.js';
8
+ import { setDebug } from '../../lib/shell.js';
7
9
  export default class Up extends Command {
8
10
  static description = 'Provision all packages in the project.';
9
- static examples = [
10
- '<%= config.bin %> <%= command.id %>',
11
- ];
11
+ static examples = ['<%= config.bin %> <%= command.id %>'];
12
12
  static flags = {
13
13
  chdir: Flags.string({
14
14
  description: 'directory to run command in',
15
15
  required: false,
16
16
  }),
17
+ debug: Flags.boolean({
18
+ default: false,
19
+ description: 'enable debug mode',
20
+ }),
17
21
  deploy: Flags.boolean({
18
22
  description: 'provision deployment companion packages',
19
23
  required: false,
@@ -26,6 +30,8 @@ export default class Up extends Command {
26
30
  };
27
31
  async run() {
28
32
  const { flags } = await this.parse(Up);
33
+ setDebug(flags.debug);
34
+ const logger = getLogger();
29
35
  const projectRootDir = flags.chdir || process.env.HEREYA_PROJECT_ROOT_DIR;
30
36
  const configManager = getConfigManager();
31
37
  const loadConfigOutput = await configManager.loadConfig({ projectRootDir });
@@ -54,6 +60,9 @@ export default class Up extends Command {
54
60
  }
55
61
  const { env: workspaceEnv } = getWorkspaceEnvOutput;
56
62
  const parameterManager = getParameterManager();
63
+ if (removedPackages.length > 0) {
64
+ logger.log(`Destroying ${removedPackages.length} removed packages`);
65
+ }
57
66
  const removed = await Promise.all(removedPackages.map(async (packageName) => {
58
67
  const { parameters } = await parameterManager.getPackageParameters({
59
68
  package: packageName,
@@ -71,10 +80,13 @@ export default class Up extends Command {
71
80
  if (!destroyOutput.success) {
72
81
  this.error(destroyOutput.reason);
73
82
  }
74
- this.log(`Package ${packageName} destroyed successfully`);
75
83
  const { env, metadata } = destroyOutput;
76
84
  return { env, metadata, packageName };
77
85
  }));
86
+ if (removedPackages.length > 0) {
87
+ logger.done(`Destroyed ${removedPackages.length} removed packages`);
88
+ }
89
+ logger.log(`Provisioning ${packages.length} packages`);
78
90
  const added = await Promise.all(packages.map(async (packageName) => {
79
91
  const { parameters } = await parameterManager.getPackageParameters({
80
92
  package: packageName,
@@ -93,9 +105,9 @@ export default class Up extends Command {
93
105
  this.error(provisionOutput.reason);
94
106
  }
95
107
  const { env, metadata } = provisionOutput;
96
- this.log(`Package ${packageName} provisioned successfully`);
97
108
  return { env, metadata, packageName };
98
109
  }));
110
+ logger.done(`Provisioned ${packages.length} packages`);
99
111
  const envManager = getEnvManager();
100
112
  for (const { env, metadata } of removed) {
101
113
  // eslint-disable-next-line no-await-in-loop
@@ -108,6 +120,9 @@ export default class Up extends Command {
108
120
  }),
109
121
  ]);
110
122
  }
123
+ if (removedPackages.length > 0) {
124
+ logger.done(`Removed env vars from ${removedPackages.length} removed packages`);
125
+ }
111
126
  for (const { env, metadata } of added) {
112
127
  // eslint-disable-next-line no-await-in-loop
113
128
  await envManager.addProjectEnv({
@@ -117,6 +132,7 @@ export default class Up extends Command {
117
132
  workspace,
118
133
  });
119
134
  }
135
+ logger.done('Saved exported environment variables');
120
136
  const { config: newConfig } = await configManager.loadConfig({ projectRootDir });
121
137
  await backend.saveState(newConfig);
122
138
  }
@@ -10,19 +10,19 @@ export function getInfrastructure(input) {
10
10
  case InfrastructureType.local: {
11
11
  return {
12
12
  infrastructure: localInfrastructure,
13
- supported: true
13
+ supported: true,
14
14
  };
15
15
  }
16
16
  case InfrastructureType.aws: {
17
17
  return {
18
18
  infrastructure: awsInfrastructure,
19
- supported: true
19
+ supported: true,
20
20
  };
21
21
  }
22
22
  default: {
23
23
  return {
24
24
  reason: `Infrastructure type ${input.type} is not supported yet!`,
25
- supported: false
25
+ supported: false,
26
26
  };
27
27
  }
28
28
  }
@@ -38,7 +38,6 @@ export async function destroyPackage(input) {
38
38
  return { reason: infrastructure$.reason, success: false };
39
39
  }
40
40
  if (metadata.deploy && input.skipDeploy) {
41
- console.log(`Skipping un-deployment of ${input.package}...`);
42
41
  return { env: {}, metadata, success: true };
43
42
  }
44
43
  const { infrastructure } = infrastructure$;
@@ -46,31 +45,33 @@ export async function destroyPackage(input) {
46
45
  const id$ = await backend.getProvisioningId({
47
46
  packageCanonicalName: canonicalName,
48
47
  project: input.project,
49
- workspace: input.workspace
48
+ workspace: input.workspace,
50
49
  });
51
50
  if (!id$.success) {
52
51
  return { reason: id$.reason, success: false };
53
52
  }
54
53
  const { id } = id$;
55
- const destroyOutput = metadata.deploy ? await infrastructure.undeploy({
56
- canonicalName,
57
- env: input.env,
58
- iacType: metadata.iac,
59
- id,
60
- parameters: input.parameters,
61
- pkgName,
62
- pkgUrl: packageUri,
63
- projectEnv: input.projectEnv ?? {},
64
- projectRootDir: input.projectRootDir,
65
- }) : await infrastructure.destroy({
66
- canonicalName,
67
- env: input.env,
68
- iacType: metadata.iac,
69
- id,
70
- parameters: input.parameters,
71
- pkgName,
72
- pkgUrl: packageUri,
73
- });
54
+ const destroyOutput = metadata.deploy
55
+ ? await infrastructure.undeploy({
56
+ canonicalName,
57
+ env: input.env,
58
+ iacType: metadata.iac,
59
+ id,
60
+ parameters: input.parameters,
61
+ pkgName,
62
+ pkgUrl: packageUri,
63
+ projectEnv: input.projectEnv ?? {},
64
+ projectRootDir: input.projectRootDir,
65
+ })
66
+ : await infrastructure.destroy({
67
+ canonicalName,
68
+ env: input.env,
69
+ iacType: metadata.iac,
70
+ id,
71
+ parameters: input.parameters,
72
+ pkgName,
73
+ pkgUrl: packageUri,
74
+ });
74
75
  if (!destroyOutput.success) {
75
76
  return { reason: destroyOutput.reason, success: false };
76
77
  }
@@ -79,10 +80,12 @@ export async function destroyPackage(input) {
79
80
  ...input,
80
81
  package: depName,
81
82
  })));
82
- if (!depsOutput.every(output => output.success)) {
83
+ if (!depsOutput.every((output) => output.success)) {
83
84
  return {
84
- reason: `Failed to destroy all dependencies: ${depsOutput.filter(o => !o.success).map(o => !o.success && o.reason)}`,
85
- success: false
85
+ reason: `Failed to destroy all dependencies: ${depsOutput
86
+ .filter((o) => !o.success)
87
+ .map((o) => !o.success && o.reason)}`,
88
+ success: false,
86
89
  };
87
90
  }
88
91
  return { env: destroyOutput.env, metadata, success: true };
@@ -98,7 +101,6 @@ export async function provisionPackage(input) {
98
101
  return { reason: infrastructure$.reason, success: false };
99
102
  }
100
103
  if (metadata.deploy && input.skipDeploy) {
101
- console.log(`Skipping deployment of ${input.package}...`);
102
104
  return { env: {}, metadata, success: true };
103
105
  }
104
106
  const dependencies = metadata.dependencies ?? {};
@@ -106,10 +108,12 @@ export async function provisionPackage(input) {
106
108
  ...input,
107
109
  package: depName,
108
110
  })));
109
- if (!depsOutput.every(output => output.success)) {
111
+ if (!depsOutput.every((output) => output.success)) {
110
112
  return {
111
- reason: `Failed to provision all dependencies: ${depsOutput.filter(o => !o.success).map(o => !o.success && o.reason)}`,
112
- success: false
113
+ reason: `Failed to provision all dependencies: ${depsOutput
114
+ .filter((o) => !o.success)
115
+ .map((o) => !o.success && o.reason)}`,
116
+ success: false,
113
117
  };
114
118
  }
115
119
  let depsEnv = {};
@@ -126,31 +130,33 @@ export async function provisionPackage(input) {
126
130
  const id$ = await backend.getProvisioningId({
127
131
  packageCanonicalName: canonicalName,
128
132
  project: input.project,
129
- workspace: input.workspace
133
+ workspace: input.workspace,
130
134
  });
131
135
  if (!id$.success) {
132
136
  return { reason: id$.reason, success: false };
133
137
  }
134
138
  const { id } = id$;
135
- const provisionOutput = metadata.deploy ? await infrastructure.deploy({
136
- canonicalName,
137
- env: { ...input.env, ...depsEnv },
138
- iacType: metadata.iac,
139
- id,
140
- parameters: input.parameters,
141
- pkgName,
142
- pkgUrl: packageUri,
143
- projectEnv: input.projectEnv ?? {},
144
- projectRootDir: input.projectRootDir,
145
- }) : await infrastructure.provision({
146
- canonicalName,
147
- env: input.env,
148
- iacType: metadata.iac,
149
- id,
150
- parameters: input.parameters,
151
- pkgName,
152
- pkgUrl: packageUri,
153
- });
139
+ const provisionOutput = metadata.deploy
140
+ ? await infrastructure.deploy({
141
+ canonicalName,
142
+ env: { ...input.env, ...depsEnv },
143
+ iacType: metadata.iac,
144
+ id,
145
+ parameters: input.parameters,
146
+ pkgName,
147
+ pkgUrl: packageUri,
148
+ projectEnv: input.projectEnv ?? {},
149
+ projectRootDir: input.projectRootDir,
150
+ })
151
+ : await infrastructure.provision({
152
+ canonicalName,
153
+ env: input.env,
154
+ iacType: metadata.iac,
155
+ id,
156
+ parameters: input.parameters,
157
+ pkgName,
158
+ pkgUrl: packageUri,
159
+ });
154
160
  if (!provisionOutput.success) {
155
161
  return { reason: provisionOutput.reason, success: false };
156
162
  }
@@ -0,0 +1,4 @@
1
+ export declare function getLogger(): {
2
+ done(message: string): void;
3
+ log(message: string): void;
4
+ };
@@ -0,0 +1,29 @@
1
+ import cliSpinners from 'cli-spinners';
2
+ import ora from 'ora';
3
+ let spinner = null;
4
+ const logger = {
5
+ done(message) {
6
+ if (!spinner) {
7
+ spinner = ora({
8
+ spinner: cliSpinners.aesthetic,
9
+ text: message,
10
+ });
11
+ }
12
+ spinner.succeed(message);
13
+ spinner = null;
14
+ },
15
+ log(message) {
16
+ if (spinner) {
17
+ spinner.text = message;
18
+ return;
19
+ }
20
+ spinner = ora({
21
+ spinner: cliSpinners.aesthetic,
22
+ text: message,
23
+ });
24
+ spinner.start();
25
+ },
26
+ };
27
+ export function getLogger() {
28
+ return logger;
29
+ }
@@ -1,4 +1,4 @@
1
1
  import type { GetRepoContentInput, GetRepoContentOutput, PackageManager } from './common.js';
2
2
  export declare class GitHubPackageManager implements PackageManager {
3
- getRepoContent({ owner, path, repo }: GetRepoContentInput): Promise<GetRepoContentOutput>;
3
+ getRepoContent({ owner, path: filePath, repo }: GetRepoContentInput): Promise<GetRepoContentOutput>;
4
4
  }
@@ -1,31 +1,31 @@
1
- import { Octokit } from '@octokit/rest';
1
+ import fs from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { downloadPackage } from './index.js';
2
5
  export class GitHubPackageManager {
3
- async getRepoContent({ owner, path, repo }) {
4
- const octokit = new Octokit();
6
+ async getRepoContent({ owner, path: filePath, repo }) {
7
+ const pkgUrl = `https://github.com/${owner}/${repo}`;
8
+ const tmpFolder = path.join(os.tmpdir(), 'hereya', 'github', owner, repo);
5
9
  try {
6
- const response = await octokit.rest.repos.getContent({
7
- headers: {
8
- 'Accept': 'application/vnd.github.raw+json'
9
- },
10
- owner,
11
- path,
12
- repo
13
- });
14
- if (response.status !== 200) {
10
+ const destPath = await downloadPackage(pkgUrl, tmpFolder);
11
+ if (await fs.stat(path.join(destPath, filePath))) {
12
+ const content = await fs.readFile(path.join(destPath, filePath), 'utf8');
13
+ // remove the tmp folder
14
+ await fs.rm(destPath, { recursive: true });
15
15
  return {
16
- found: false,
17
- reason: `Failed to fetch content: ${response.status}`
16
+ content,
17
+ found: true,
18
18
  };
19
19
  }
20
20
  return {
21
- content: response.data,
22
- found: true
21
+ found: false,
22
+ reason: `File ${filePath} not found in ${pkgUrl}`,
23
23
  };
24
24
  }
25
25
  catch (error) {
26
26
  return {
27
27
  found: false,
28
- reason: error.message
28
+ reason: error.message,
29
29
  };
30
30
  }
31
31
  }
@@ -55,11 +55,9 @@ export function getPackageCanonicalName(packageName) {
55
55
  }
56
56
  export async function downloadPackage(pkgUrl, destPath) {
57
57
  if (await isNotEmpty(destPath)) {
58
- console.log(`Package already downloaded at ${destPath}`);
59
58
  return destPath;
60
59
  }
61
60
  await fs.mkdir(destPath, { recursive: true });
62
- console.log(`Downloading package from ${pkgUrl}`);
63
61
  // Initialize simple-git
64
62
  const git = simpleGit();
65
63
  // Clone repository into temp directory
@@ -1,6 +1,8 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  /// <reference types="node" resolution-mode="require"/>
3
3
  import { StdioOptions, spawnSync } from 'node:child_process';
4
+ export declare function setDebug(value: boolean): void;
5
+ export declare function isDebug(): boolean;
4
6
  export type RunShellOptions = {
5
7
  directory?: string;
6
8
  env?: NodeJS.ProcessEnv;
package/dist/lib/shell.js CHANGED
@@ -1,4 +1,11 @@
1
1
  import { spawnSync } from 'node:child_process';
2
+ let debug = false;
3
+ export function setDebug(value) {
4
+ debug = value;
5
+ }
6
+ export function isDebug() {
7
+ return debug;
8
+ }
2
9
  export function runShell(cmd, args, options = {}) {
3
10
  // Run the command
4
11
  const result = spawnSync(cmd, args, {
@@ -6,7 +13,7 @@ export function runShell(cmd, args, options = {}) {
6
13
  encoding: 'utf8',
7
14
  env: { ...process.env, ...options.env },
8
15
  shell: true,
9
- stdio: options.stdio ?? 'inherit',
16
+ stdio: options.stdio ?? (isDebug() ? 'inherit' : 'ignore'),
10
17
  });
11
18
  // Throw an error if the command failed
12
19
  if (result.status !== 0) {