@pagopa/dx-cli 0.20.1 → 0.21.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.
Files changed (36) hide show
  1. package/README.md +12 -1
  2. package/bin/index.js +0 -20
  3. package/dist/adapters/azure/__tests__/cloud-account-service.test.js +132 -1
  4. package/dist/adapters/azure/cloud-account-service.d.ts +3 -2
  5. package/dist/adapters/azure/cloud-account-service.js +127 -39
  6. package/dist/adapters/commander/__tests__/error-reporting.test.d.ts +1 -0
  7. package/dist/adapters/commander/__tests__/error-reporting.test.js +63 -0
  8. package/dist/adapters/commander/__tests__/exit-with-error.test.d.ts +1 -0
  9. package/dist/adapters/commander/__tests__/exit-with-error.test.js +92 -0
  10. package/dist/adapters/commander/commands/add.d.ts +2 -0
  11. package/dist/adapters/commander/commands/add.js +8 -5
  12. package/dist/adapters/commander/commands/codemod.js +3 -2
  13. package/dist/adapters/commander/commands/init.js +2 -2
  14. package/dist/adapters/commander/commands/savemoney.js +6 -3
  15. package/dist/adapters/commander/error-reporting.d.ts +10 -0
  16. package/dist/adapters/commander/error-reporting.js +68 -0
  17. package/dist/adapters/commander/index.d.ts +17 -1
  18. package/dist/adapters/commander/index.js +23 -2
  19. package/dist/adapters/octokit/index.d.ts +2 -1
  20. package/dist/adapters/octokit/index.js +33 -0
  21. package/dist/adapters/plop/__tests__/run-actions.test.d.ts +1 -0
  22. package/dist/adapters/plop/__tests__/run-actions.test.js +68 -0
  23. package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.js +24 -7
  24. package/dist/adapters/plop/actions/init-cloud-accounts.d.ts +3 -2
  25. package/dist/adapters/plop/actions/init-cloud-accounts.js +4 -4
  26. package/dist/adapters/plop/generators/environment/__tests__/actions.test.js +6 -1
  27. package/dist/adapters/plop/generators/environment/actions.js +12 -0
  28. package/dist/adapters/plop/generators/environment/index.d.ts +2 -1
  29. package/dist/adapters/plop/generators/environment/index.js +2 -2
  30. package/dist/adapters/plop/index.d.ts +5 -3
  31. package/dist/adapters/plop/index.js +20 -12
  32. package/dist/domain/cloud-account.d.ts +3 -2
  33. package/dist/domain/github.d.ts +13 -0
  34. package/dist/index.js +36 -0
  35. package/package.json +4 -2
  36. package/templates/environment/workflow/_release-terraform-apply-bootstrapper-{{env.name}}.yaml.hbs +19 -0
@@ -26,19 +26,27 @@ const validatePayload = async (payload, github) => {
26
26
  }
27
27
  };
28
28
  export const getPlopInstance = async () => nodePlop();
29
- const runActions = async (generator, payload) => {
29
+ export const runActions = async (generator, payload) => {
30
30
  const logger = getLogger(["dx-cli", "init"]);
31
31
  const result = await generator.runActions(payload);
32
32
  if (result.failures.length > 0) {
33
- for (const failure of result.failures) {
34
- if (failure.error === "Aborted due to previous action failure") {
35
- continue;
36
- }
37
- logger.error(`Error on {type} step. ${failure.message}`, {
38
- type: failure.type,
33
+ // Collect every failure to report rich context. node-plop's failure
34
+ // objects have shape `{ type, path, error }` (the `error` property holds
35
+ // the original error's message — see node-plop's generator-runner.js).
36
+ const relevant = result.failures.filter((failure) => failure.error !== "Aborted due to previous action failure");
37
+ if (relevant.length === 0) {
38
+ return;
39
+ }
40
+ const summary = relevant
41
+ .map((failure) => `${failure.type || "action"}: ${failure.error ?? "unknown error"}`)
42
+ .join("; ");
43
+ for (const failure of relevant) {
44
+ logger.error("Error on {type} step: {error}", {
45
+ error: failure.error ?? "unknown error",
46
+ type: failure.type || "action",
39
47
  });
40
- throw new Error("One or more actions failed during generation.");
41
48
  }
49
+ throw new Error(`One or more actions failed during generation (${summary}).`);
42
50
  }
43
51
  };
44
52
  export const runMonorepoGenerator = async (plop, githubService) => {
@@ -62,8 +70,8 @@ export const runMonorepoGenerator = async (plop, githubService) => {
62
70
  * uses the explicitly passed repository. When omitted (by add command),
63
71
  * the generator infers it from the local git context.
64
72
  */
65
- export const runDeploymentEnvironmentGenerator = async (plop, github) => {
66
- setDeploymentEnvironmentGenerator(plop, github);
73
+ export const runDeploymentEnvironmentGenerator = async (plop, gitHubService, github) => {
74
+ setDeploymentEnvironmentGenerator(plop, gitHubService, github);
67
75
  const generator = plop.getGenerator(PLOP_ENVIRONMENT_GENERATOR_NAME);
68
76
  const answers = await generator.runPrompts();
69
77
  const payload = environmentPayloadSchema.parse(answers);
@@ -82,10 +90,10 @@ export const runDeploymentEnvironmentGenerator = async (plop, github) => {
82
90
  * uses the explicitly passed repository. When omitted (by add command),
83
91
  * the generator infers it from the local git context.
84
92
  */
85
- export const setDeploymentEnvironmentGenerator = (plop, github) => {
93
+ export const setDeploymentEnvironmentGenerator = (plop, gitHubService, github) => {
86
94
  const credential = new AzureCliCredential();
87
95
  const cloudAccountRepository = new AzureSubscriptionRepository(credential);
88
96
  const cloudAccountService = new AzureCloudAccountService(credential);
89
97
  const templatesPath = path.join(import.meta.dirname, "../../../templates/environment");
90
- createDeploymentEnvironmentGenerator(plop, templatesPath, cloudAccountRepository, cloudAccountService, github);
98
+ createDeploymentEnvironmentGenerator(plop, templatesPath, cloudAccountRepository, cloudAccountService, gitHubService, github);
91
99
  };
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod/v4";
2
2
  import { type EnvironmentId } from "./environment.js";
3
- import { type GitHubAppCredentials } from "./github.js";
3
+ import { type GitHubRepo } from "./github-repo.js";
4
+ import { type GitHubAppCredentials, type GitHubService } from "./github.js";
4
5
  import { TerraformBackend } from "./remote-backend.js";
5
6
  export declare const cloudAccountSchema: z.ZodObject<{
6
7
  csp: z.ZodDefault<z.ZodEnum<{
@@ -17,7 +18,7 @@ export type CloudAccountRepository = {
17
18
  export type CloudAccountService = {
18
19
  getTerraformBackend(cloudAccountId: CloudAccount["id"], environment: EnvironmentId): Promise<TerraformBackend | undefined>;
19
20
  hasUserPermissionToInitialize(cloudAccountId: CloudAccount["id"]): Promise<boolean>;
20
- initialize(cloudAccount: CloudAccount, environment: EnvironmentId, runnerAppCredentials: GitHubAppCredentials, tags?: Record<string, string>): Promise<void>;
21
+ initialize(cloudAccount: CloudAccount, environment: EnvironmentId, runnerAppCredentials: GitHubAppCredentials, github: GitHubRepo, gitHubService: GitHubService, tags?: Record<string, string>): Promise<void>;
21
22
  isInitialized(cloudAccountId: CloudAccount["id"], environment: EnvironmentId): Promise<boolean>;
22
23
  provisionTerraformBackend(cloudAccount: CloudAccount, environment: EnvironmentId, tags?: Record<string, string>): Promise<TerraformBackend>;
23
24
  };
@@ -5,6 +5,13 @@ export type CreateBranchParams = {
5
5
  owner: string;
6
6
  repo: string;
7
7
  };
8
+ export type CreateOrUpdateEnvironmentSecretParams = {
9
+ environmentName: string;
10
+ owner: string;
11
+ repo: string;
12
+ secretName: string;
13
+ secretValue: string;
14
+ };
8
15
  export type FileContent = {
9
16
  content: string;
10
17
  sha: string;
@@ -21,6 +28,12 @@ export interface GitHubService {
21
28
  * @throws Error if branch creation fails
22
29
  */
23
30
  createBranch(params: CreateBranchParams): Promise<void>;
31
+ /**
32
+ * Creates or updates a secret in a GitHub repository environment.
33
+ * The value is automatically encrypted using the environment's public key.
34
+ * @throws Error if secret creation fails
35
+ */
36
+ createOrUpdateEnvironmentSecret(params: CreateOrUpdateEnvironmentSecretParams): Promise<void>;
24
37
  /**
25
38
  * Creates a pull request in a GitHub repository.
26
39
  * @throws Error if pull request creation fails
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import "core-js/actual/set/index.js";
2
+ import { configure, getConsoleSink } from "@logtape/logtape";
2
3
  import * as assert from "node:assert/strict";
3
4
  import { Octokit } from "octokit";
4
5
  import codemodRegistry from "./adapters/codemods/index.js";
@@ -13,7 +14,42 @@ import { getInfo } from "./domain/info.js";
13
14
  import { applyCodemodById } from "./use-cases/apply-codemod.js";
14
15
  import { listCodemods } from "./use-cases/list-codemods.js";
15
16
  import { requestAuthorization } from "./use-cases/request-authorization.js";
17
+ /**
18
+ * Returns `true` when `-v` or `--verbose` is present in argv.
19
+ *
20
+ * We inspect argv directly — instead of relying on Commander — because the
21
+ * logtape configuration must be in place before any command handler runs
22
+ * (including the ones that emit debug logs while parsing prompts).
23
+ */
24
+ const detectVerboseFromArgv = (argv) => argv.includes("-v") || argv.includes("--verbose");
25
+ const configureLogging = async (verbose) => {
26
+ const level = verbose ? "debug" : "info";
27
+ await configure({
28
+ loggers: [
29
+ { category: ["dx-cli"], lowestLevel: level, sinks: ["console"] },
30
+ // The environment generator (`gen.env`) emits debug messages about
31
+ // provisioned Azure resources; surfacing them is the main value of
32
+ // `--verbose` when running `dx init` / `dx add environment`.
33
+ { category: ["gen"], lowestLevel: level, sinks: ["console"] },
34
+ // `savemoney` already emits structured debug output by default.
35
+ { category: ["savemoney"], lowestLevel: "debug", sinks: ["console"] },
36
+ { category: ["json"], lowestLevel: "info", sinks: ["rawJson"] },
37
+ {
38
+ category: ["logtape", "meta"],
39
+ lowestLevel: "warning",
40
+ sinks: ["console"],
41
+ },
42
+ ],
43
+ sinks: {
44
+ console: getConsoleSink(),
45
+ rawJson(record) {
46
+ console.log(record.rawMessage);
47
+ },
48
+ },
49
+ });
50
+ };
16
51
  export const runCli = async (version) => {
52
+ await configureLogging(detectVerboseFromArgv(process.argv));
17
53
  // Creating the adapters
18
54
  const repositoryReader = makeRepositoryReader();
19
55
  const packageJsonReader = makePackageJsonReader();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-cli",
3
- "version": "0.20.1",
3
+ "version": "0.21.0",
4
4
  "type": "module",
5
5
  "description": "A CLI useful to manage DX tools.",
6
6
  "repository": {
@@ -39,6 +39,7 @@
39
39
  "execa": "^9.6.1",
40
40
  "glob": "^11.1.0",
41
41
  "inquirer": "^9.3.8",
42
+ "libsodium-wrappers": "^0.8.2",
42
43
  "neverthrow": "^8.2.0",
43
44
  "node-plop": "^0.32.3",
44
45
  "octokit": "^5.0.5",
@@ -52,10 +53,11 @@
52
53
  "devDependencies": {
53
54
  "@tsconfig/node24": "24.0.4",
54
55
  "@types/inquirer": "^9.0.9",
56
+ "@types/libsodium-wrappers": "^0.8.2",
55
57
  "@types/node": "^22.19.17",
56
58
  "@types/semver": "^7.7.1",
57
59
  "@vitest/coverage-v8": "^3.2.4",
58
- "eslint": "^10.2.0",
60
+ "eslint": "^10.2.1",
59
61
  "memfs": "^4.57.1",
60
62
  "plop": "^4.0.5",
61
63
  "prettier": "3.8.3",
@@ -0,0 +1,19 @@
1
+ name: Release Bootstrapper Infrastructure - {{@root.env.name}}
2
+ on:
3
+ workflow_dispatch:
4
+ push:
5
+ branches:
6
+ - main
7
+ paths:
8
+ - "infra/bootstrapper/**"
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ release:
15
+ uses: pagopa/dx/.github/workflows/release-terraform-bootstrapper-v1.yaml@main
16
+ name: Release Bootstrapper ({{@root.env.name}})
17
+ secrets: inherit
18
+ with:
19
+ environment: '{{@root.env.name}}'