@pagopa/dx-cli 0.23.0 → 0.23.2

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 (102) hide show
  1. package/dist/adapters/commander/commands/init.js +62 -27
  2. package/dist/adapters/commander/index.js +1 -1
  3. package/dist/adapters/plop/index.d.ts +19 -1
  4. package/dist/adapters/plop/index.js +19 -6
  5. package/package.json +5 -5
  6. package/templates/monorepo/nx.json +0 -1
  7. package/dist/adapters/azure/__tests__/cloud-account-repository.test.d.ts +0 -1
  8. package/dist/adapters/azure/__tests__/cloud-account-repository.test.js +0 -95
  9. package/dist/adapters/azure/__tests__/cloud-account-service.test.d.ts +0 -1
  10. package/dist/adapters/azure/__tests__/cloud-account-service.test.js +0 -378
  11. package/dist/adapters/codemods/__tests__/registry.test.d.ts +0 -1
  12. package/dist/adapters/codemods/__tests__/registry.test.js +0 -56
  13. package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.d.ts +0 -1
  14. package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.js +0 -77
  15. package/dist/adapters/codemods/__tests__/use-pnpm.test.d.ts +0 -1
  16. package/dist/adapters/codemods/__tests__/use-pnpm.test.js +0 -148
  17. package/dist/adapters/commander/__tests__/env.test.d.ts +0 -1
  18. package/dist/adapters/commander/__tests__/env.test.js +0 -45
  19. package/dist/adapters/commander/__tests__/error-reporting.test.d.ts +0 -1
  20. package/dist/adapters/commander/__tests__/error-reporting.test.js +0 -63
  21. package/dist/adapters/commander/__tests__/exit-with-error.test.d.ts +0 -1
  22. package/dist/adapters/commander/__tests__/exit-with-error.test.js +0 -92
  23. package/dist/adapters/commander/__tests__/global-options.test.d.ts +0 -1
  24. package/dist/adapters/commander/__tests__/global-options.test.js +0 -33
  25. package/dist/adapters/commander/__tests__/spec.test.d.ts +0 -8
  26. package/dist/adapters/commander/__tests__/spec.test.js +0 -264
  27. package/dist/adapters/commander/commands/__tests__/add.test.d.ts +0 -4
  28. package/dist/adapters/commander/commands/__tests__/add.test.js +0 -167
  29. package/dist/adapters/commander/commands/__tests__/init-command.test.d.ts +0 -4
  30. package/dist/adapters/commander/commands/__tests__/init-command.test.js +0 -44
  31. package/dist/adapters/commander/commands/__tests__/init.test.d.ts +0 -4
  32. package/dist/adapters/commander/commands/__tests__/init.test.js +0 -48
  33. package/dist/adapters/commander/commands/__tests__/preconditions.test.d.ts +0 -1
  34. package/dist/adapters/commander/commands/__tests__/preconditions.test.js +0 -32
  35. package/dist/adapters/commander/commands/__tests__/savemoney.test.d.ts +0 -8
  36. package/dist/adapters/commander/commands/__tests__/savemoney.test.js +0 -60
  37. package/dist/adapters/commander/commands/__tests__/spec.test.d.ts +0 -7
  38. package/dist/adapters/commander/commands/__tests__/spec.test.js +0 -85
  39. package/dist/adapters/commander/presenters/__tests__/index.test.d.ts +0 -1
  40. package/dist/adapters/commander/presenters/__tests__/index.test.js +0 -23
  41. package/dist/adapters/commander/presenters/__tests__/json.test.d.ts +0 -1
  42. package/dist/adapters/commander/presenters/__tests__/json.test.js +0 -108
  43. package/dist/adapters/commander/presenters/__tests__/text.test.d.ts +0 -1
  44. package/dist/adapters/commander/presenters/__tests__/text.test.js +0 -60
  45. package/dist/adapters/github/__tests__/github-repo.spec.d.ts +0 -1
  46. package/dist/adapters/github/__tests__/github-repo.spec.js +0 -67
  47. package/dist/adapters/node/__tests__/data.d.ts +0 -18
  48. package/dist/adapters/node/__tests__/data.js +0 -22
  49. package/dist/adapters/node/__tests__/package-json.test.d.ts +0 -1
  50. package/dist/adapters/node/__tests__/package-json.test.js +0 -86
  51. package/dist/adapters/node/__tests__/repository.test.d.ts +0 -1
  52. package/dist/adapters/node/__tests__/repository.test.js +0 -77
  53. package/dist/adapters/node/fs/__tests__/file-reader.test.d.ts +0 -1
  54. package/dist/adapters/node/fs/__tests__/file-reader.test.js +0 -80
  55. package/dist/adapters/node/json/__tests__/index.test.d.ts +0 -1
  56. package/dist/adapters/node/json/__tests__/index.test.js +0 -14
  57. package/dist/adapters/octokit/__tests__/index.test.d.ts +0 -1
  58. package/dist/adapters/octokit/__tests__/index.test.js +0 -414
  59. package/dist/adapters/pagopa-technology/__tests__/authorization.test.d.ts +0 -4
  60. package/dist/adapters/pagopa-technology/__tests__/authorization.test.js +0 -548
  61. package/dist/adapters/plop/__tests__/run-actions.test.d.ts +0 -1
  62. package/dist/adapters/plop/__tests__/run-actions.test.js +0 -68
  63. package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.d.ts +0 -1
  64. package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.js +0 -171
  65. package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.d.ts +0 -1
  66. package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.js +0 -134
  67. package/dist/adapters/plop/generators/__tests__/temp-dir.d.ts +0 -2
  68. package/dist/adapters/plop/generators/__tests__/temp-dir.js +0 -13
  69. package/dist/adapters/plop/generators/environment/__tests__/actions.test.d.ts +0 -2
  70. package/dist/adapters/plop/generators/environment/__tests__/actions.test.js +0 -92
  71. package/dist/adapters/plop/generators/environment/__tests__/generation.test.d.ts +0 -1
  72. package/dist/adapters/plop/generators/environment/__tests__/generation.test.js +0 -213
  73. package/dist/adapters/plop/generators/environment/__tests__/prompts.test.d.ts +0 -1
  74. package/dist/adapters/plop/generators/environment/__tests__/prompts.test.js +0 -182
  75. package/dist/adapters/plop/generators/monorepo/__tests__/generation.test.d.ts +0 -1
  76. package/dist/adapters/plop/generators/monorepo/__tests__/generation.test.js +0 -79
  77. package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.d.ts +0 -1
  78. package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.js +0 -113
  79. package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.d.ts +0 -1
  80. package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.js +0 -35
  81. package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.d.ts +0 -1
  82. package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.js +0 -60
  83. package/dist/adapters/yaml/__tests__/index.test.d.ts +0 -1
  84. package/dist/adapters/yaml/__tests__/index.test.js +0 -53
  85. package/dist/domain/__tests__/data.d.ts +0 -15
  86. package/dist/domain/__tests__/data.js +0 -26
  87. package/dist/domain/__tests__/environment.test.d.ts +0 -1
  88. package/dist/domain/__tests__/environment.test.js +0 -332
  89. package/dist/domain/__tests__/info.test.d.ts +0 -1
  90. package/dist/domain/__tests__/info.test.js +0 -77
  91. package/dist/domain/__tests__/package-json.test.d.ts +0 -1
  92. package/dist/domain/__tests__/package-json.test.js +0 -39
  93. package/dist/domain/__tests__/repository.test.d.ts +0 -1
  94. package/dist/domain/__tests__/repository.test.js +0 -111
  95. package/dist/domain/__tests__/workspace.test.d.ts +0 -1
  96. package/dist/domain/__tests__/workspace.test.js +0 -57
  97. package/dist/use-cases/__tests__/apply-codemod.test.d.ts +0 -1
  98. package/dist/use-cases/__tests__/apply-codemod.test.js +0 -71
  99. package/dist/use-cases/__tests__/list-codemods.test.d.ts +0 -1
  100. package/dist/use-cases/__tests__/list-codemods.test.js +0 -37
  101. package/dist/use-cases/__tests__/request-authorization.test.d.ts +0 -4
  102. package/dist/use-cases/__tests__/request-authorization.test.js +0 -43
@@ -9,14 +9,17 @@ import { oraPromise } from "ora";
9
9
  import { z } from "zod";
10
10
  import { Repository, } from "../../../domain/github.js";
11
11
  import { tf$ } from "../../execa/terraform.js";
12
- import { getPlopInstance, runMonorepoGenerator } from "../../plop/index.js";
12
+ import { collectMonorepoPayload, getPlopInstance, runMonorepoActions, } from "../../plop/index.js";
13
13
  import { exitWithError } from "../index.js";
14
+ import { createCommandPresenter } from "../presenters/index.js";
14
15
  const isGitHubRepoCreationSkipped = (input) => "gitHubRepoCreationSkipped" in input;
15
- const withSpinner = (text, successText, failText, promise) => ResultAsync.fromPromise(oraPromise(promise, {
16
+ const withSpinner = (text, successText, failText, task) => ResultAsync.fromPromise(oraPromise(task(), {
16
17
  failText,
17
18
  successText,
18
19
  text,
19
20
  }), (cause) => new Error(failText, { cause }));
21
+ const asError = (message) => (cause) => new Error(message, { cause });
22
+ const trackStep = (presenter, name, task, mapError) => ResultAsync.fromPromise(presenter.trackStep(name, task), mapError);
20
23
  const displaySummary = (input) => {
21
24
  const docsUrl = "https://dx.pagopa.it/getting-started";
22
25
  if (isGitHubRepoCreationSkipped(input)) {
@@ -52,8 +55,12 @@ const displaySummary = (input) => {
52
55
  console.log(`Please, manually create a Pull Request in the GitHub repository to review the scaffolded code.\n`);
53
56
  }
54
57
  };
55
- const checkTerraformCliIsInstalled = () => withSpinner("Checking Terraform installation...", "Terraform is installed!", "Please install terraform CLI before running this command. If you use tfenv, run: tfenv install latest && tfenv use latest", tf$ `terraform -version`);
56
- const checkCorepackIsInstalled = () => withSpinner("Checking Corepack installation...", "Corepack is installed!", "Please install Corepack before running this command.", tf$ `corepack -v`);
58
+ const checkTerraformCli = () => tf$ `terraform -version`;
59
+ const checkTerraformCliIsInstalled = () => withSpinner("Checking Terraform installation...", "Terraform is installed!", "Please install terraform CLI before running this command. If you use tfenv, run: tfenv install latest && tfenv use latest", checkTerraformCli);
60
+ const trackTerraformCliIsInstalled = (presenter) => trackStep(presenter, "Checking Terraform installation...", checkTerraformCli, asError("Please install terraform CLI before running this command. If you use tfenv, run: tfenv install latest && tfenv use latest"));
61
+ const checkCorepack = () => tf$ `corepack -v`;
62
+ const checkCorepackIsInstalled = () => withSpinner("Checking Corepack installation...", "Corepack is installed!", "Please install Corepack before running this command.", checkCorepack);
63
+ const trackCorepackIsInstalled = (presenter) => trackStep(presenter, "Checking Corepack installation...", checkCorepack, asError("Please install Corepack before running this command."));
57
64
  const azureAccountSchema = z.object({
58
65
  user: z.object({
59
66
  name: z.string().min(1),
@@ -68,13 +75,14 @@ const ensureAzLogin = async () => {
68
75
  const { user } = azureAccountSchema.parse(parsed);
69
76
  return user.name;
70
77
  };
71
- const checkAzLogin = () => withSpinner("Check Azure login status...", (userName) => `You are logged in to Azure (${userName})`, "Please log in to Azure CLI using `az login` before running this command.", ensureAzLogin());
78
+ const checkAzLogin = () => withSpinner("Check Azure login status...", (userName) => `You are logged in to Azure (${userName})`, "Please log in to Azure CLI using `az login` before running this command.", ensureAzLogin);
79
+ const runInitPreconditions = (presenter) => trackTerraformCliIsInstalled(presenter).andThen(() => trackCorepackIsInstalled(presenter));
72
80
  // TODO(CES-1810): Make these checks concurrent to speed up the preconditions check phase
73
81
  export const checkInitPreconditions = () => checkTerraformCliIsInstalled().andThen(() => checkCorepackIsInstalled());
74
82
  export const checkAddEnvironmentPreconditions = () => checkTerraformCliIsInstalled()
75
83
  .andThen(() => checkAzLogin())
76
84
  .andThen(() => checkCorepackIsInstalled());
77
- const createRemoteRepository = ({ repoName, repoOwner, }) => {
85
+ const createRemoteRepositoryWithPresenter = (presenter) => ({ repoName, repoOwner, }) => {
78
86
  const logger = getLogger(["dx-cli", "init"]);
79
87
  const repo$ = tf$({ cwd: path.resolve("infra", "repository") });
80
88
  const applyTerraform = async () => {
@@ -89,9 +97,9 @@ const createRemoteRepository = ({ repoName, repoOwner, }) => {
89
97
  throw error;
90
98
  }
91
99
  };
92
- return withSpinner("Creating GitHub repository...", "GitHub repository created successfully!", "Failed to create GitHub repository.", applyTerraform()).map(() => new Repository(repoName, repoOwner));
100
+ return trackStep(presenter, "Creating GitHub repository...", applyTerraform, asError("Failed to create GitHub repository.")).map(() => new Repository(repoName, repoOwner));
93
101
  };
94
- const initializeGitRepository = (repository) => {
102
+ const initializeGitRepositoryWithPresenter = (presenter) => (repository) => {
95
103
  const branchName = "features/scaffold-workspace";
96
104
  const git$ = $({
97
105
  shell: true,
@@ -109,24 +117,24 @@ const initializeGitRepository = (repository) => {
109
117
  await git$ `git commit --no-gpg-sign -m "Scaffold workspace"`;
110
118
  await git$ `git push -u origin ${branchName}`;
111
119
  };
112
- return withSpinner("Pushing code to GitHub...", "Code pushed to GitHub successfully!", "Failed to push code to GitHub.", pushToOrigin()).map(() => ({ branchName, repository }));
120
+ return trackStep(presenter, "Pushing code to GitHub...", pushToOrigin, asError("Failed to push code to GitHub.")).map(() => ({ branchName, repository }));
113
121
  };
114
- const handleNewGitHubRepository = (githubService) => (payload) => createRemoteRepository(payload)
115
- .andThen(initializeGitRepository)
116
- .andThen((localWorkspace) => createPullRequest(githubService)(localWorkspace).map((pr) => ({
117
- pr,
118
- repository: localWorkspace.repository,
119
- })));
120
- const createPullRequest = (githubService) => ({ branchName, repository, }) => withSpinner("Creating Pull Request...", "Pull Request created successfully!", "Failed to create Pull Request.", githubService.createPullRequest({
122
+ const createPullRequestWithPresenter = ({ gitHubService, presenter }) => ({ branchName, repository, }) => trackStep(presenter, "Creating Pull Request...", () => gitHubService.createPullRequest({
121
123
  base: "main",
122
124
  body: "This PR contains the scaffolded monorepo structure.",
123
125
  head: branchName,
124
126
  owner: repository.owner,
125
127
  repo: repository.name,
126
128
  title: "Scaffold repository",
127
- }))
129
+ }), asError("Failed to create Pull Request."))
128
130
  // If PR creation fails, don't block the workflow
129
131
  .orElse(() => okAsync(undefined));
132
+ const handleNewGitHubRepositoryWithPresenter = (context) => (payload) => createRemoteRepositoryWithPresenter(context.presenter)(payload)
133
+ .andThen(initializeGitRepositoryWithPresenter(context.presenter))
134
+ .andThen((localWorkspace) => createPullRequestWithPresenter(context)(localWorkspace).map((pr) => ({
135
+ pr,
136
+ repository: localWorkspace.repository,
137
+ })));
130
138
  const handleGeneratorError = (err) => {
131
139
  const logger = getLogger(["dx-cli", "init"]);
132
140
  if (err instanceof Error) {
@@ -142,19 +150,46 @@ export const confirmGitHubRepoCreation = (payload) => ResultAsync.fromPromise(in
142
150
  type: "confirm",
143
151
  })
144
152
  .then(({ confirm }) => confirm), (cause) => new Error("Failed to read GitHub publish confirmation", { cause }));
153
+ const runInitAction = ({ gitHubService, presenter, }) => trackStep(presenter, "Initializing workspace generator...", getPlopInstance, asError("Failed to initialize plop"))
154
+ .andThen((plop) =>
155
+ // The prompt phase must run outside trackStep: in text mode trackStep
156
+ // renders a spinner that occupies the TTY and hides the prompts.
157
+ ResultAsync.fromPromise(collectMonorepoPayload(plop, gitHubService), handleGeneratorError))
158
+ .andThen(({ generator, payload }) => trackStep(presenter, "Scaffolding workspace...", () => runMonorepoActions(generator, payload), handleGeneratorError))
159
+ .andTee((payload) => {
160
+ process.chdir(payload.repoName);
161
+ })
162
+ .andThen((payload) => confirmGitHubRepoCreation(payload).andThen((confirmed) => confirmed
163
+ ? handleNewGitHubRepositoryWithPresenter({
164
+ gitHubService,
165
+ presenter,
166
+ })(payload)
167
+ : okAsync({ gitHubRepoCreationSkipped: true, payload })));
168
+ const reportSummary = (presenter, outputMode) => (result) => {
169
+ if (outputMode === "json") {
170
+ presenter.reportResult(result);
171
+ }
172
+ else {
173
+ displaySummary(result);
174
+ }
175
+ };
176
+ const reportCommandError = (command, presenter, outputMode) => (error) => {
177
+ if (outputMode === "json") {
178
+ presenter.reportError(error);
179
+ process.exitCode = 1;
180
+ }
181
+ else {
182
+ exitWithError(command)(error);
183
+ }
184
+ };
145
185
  export const makeInitCommand = (requireGitHubAuth) => new Command()
146
186
  .name("init")
147
187
  .description("Initialize a new DX workspace")
148
188
  .action(async function () {
149
- await checkInitPreconditions()
189
+ const { output } = this.optsWithGlobals();
190
+ const presenter = createCommandPresenter(output);
191
+ await runInitPreconditions(presenter)
150
192
  .andThen(() => requireGitHubAuth())
151
- .andThen((auth) => ResultAsync.fromPromise(getPlopInstance(), (cause) => new Error("Failed to initialize plop", { cause }))
152
- .andThen((plop) => ResultAsync.fromPromise(runMonorepoGenerator(plop, auth.gitHubService), handleGeneratorError))
153
- .andTee((payload) => {
154
- process.chdir(payload.repoName);
155
- })
156
- .andThen((payload) => confirmGitHubRepoCreation(payload).andThen((confirmed) => confirmed
157
- ? handleNewGitHubRepository(auth.gitHubService)(payload)
158
- : okAsync({ gitHubRepoCreationSkipped: true, payload }))))
159
- .match(displaySummary, exitWithError(this));
193
+ .andThen((auth) => runInitAction({ gitHubService: auth.gitHubService, presenter }))
194
+ .match(reportSummary(presenter, output), reportCommandError(this, presenter, output));
160
195
  });
@@ -20,7 +20,7 @@ export const makeCli = (deps, config, cliDeps, version) => {
20
20
  .description("The CLI for DX-Platform")
21
21
  .version(version)
22
22
  .option("-v, --verbose", "Enable verbose output: debug-level logs and full error chain (with stack traces) when a command fails", false)
23
- .addOption(new Option("--output <mode>", "Output mode: 'text' (human-readable, default) or 'json' (structured JSON envelope on stdout, NDJSON progress events on stderr)")
23
+ .addOption(new Option("--output <mode>", "Output mode: text (default, human-readable) or json (structured events to stdout for agents)")
24
24
  .choices(["text", "json"])
25
25
  .default("text"));
26
26
  program.addCommand(makeDoctorCommand(deps, config));
@@ -7,7 +7,25 @@ import { Payload as MonorepoPayload } from "../plop/generators/monorepo/index.js
7
7
  export declare const setMonorepoGenerator: (plop: NodePlopAPI) => void;
8
8
  export declare const getPlopInstance: () => Promise<NodePlopAPI>;
9
9
  export declare const runActions: (generator: PlopGenerator, payload: Answers) => Promise<void>;
10
- export declare const runMonorepoGenerator: (plop: NodePlopAPI, githubService: GitHubService) => Promise<MonorepoPayload>;
10
+ /**
11
+ * Collect the monorepo payload by running the generator's interactive prompts.
12
+ *
13
+ * This phase MUST run outside any spinner: a spinner (e.g. ora) occupies the
14
+ * TTY and prevents the inquirer prompts from being rendered. Callers should
15
+ * track only the subsequent {@link runMonorepoActions} phase, which is
16
+ * non-interactive.
17
+ */
18
+ export declare const collectMonorepoPayload: (plop: NodePlopAPI, githubService: GitHubService) => Promise<{
19
+ generator: PlopGenerator;
20
+ payload: MonorepoPayload;
21
+ }>;
22
+ /**
23
+ * Execute the monorepo generator actions for an already-collected payload.
24
+ *
25
+ * This phase is non-interactive, so callers are free to wrap it in a spinner
26
+ * or other progress indicator.
27
+ */
28
+ export declare const runMonorepoActions: (generator: PlopGenerator, payload: MonorepoPayload) => Promise<MonorepoPayload>;
11
29
  /**
12
30
  * Run the deployment environment generator
13
31
  *
@@ -48,17 +48,30 @@ export const runActions = async (generator, payload) => {
48
48
  throw new Error(`One or more actions failed during generation (${summary}).`);
49
49
  }
50
50
  };
51
- export const runMonorepoGenerator = async (plop, githubService) => {
51
+ /**
52
+ * Collect the monorepo payload by running the generator's interactive prompts.
53
+ *
54
+ * This phase MUST run outside any spinner: a spinner (e.g. ora) occupies the
55
+ * TTY and prevents the inquirer prompts from being rendered. Callers should
56
+ * track only the subsequent {@link runMonorepoActions} phase, which is
57
+ * non-interactive.
58
+ */
59
+ export const collectMonorepoPayload = async (plop, githubService) => {
52
60
  setMonorepoGenerator(plop);
53
61
  const generator = plop.getGenerator(PLOP_MONOREPO_GENERATOR_NAME);
54
62
  const answers = await generator.runPrompts();
55
63
  const payload = monorepoPayloadSchema.parse(answers);
56
64
  await validatePayload(payload, githubService);
57
- await oraPromise(runActions(generator, payload), {
58
- failText: "Failed to create workspace files.",
59
- successText: "Workspace files created successfully!",
60
- text: "Creating workspace files...",
61
- });
65
+ return { generator, payload };
66
+ };
67
+ /**
68
+ * Execute the monorepo generator actions for an already-collected payload.
69
+ *
70
+ * This phase is non-interactive, so callers are free to wrap it in a spinner
71
+ * or other progress indicator.
72
+ */
73
+ export const runMonorepoActions = async (generator, payload) => {
74
+ await runActions(generator, payload);
62
75
  return payload;
63
76
  };
64
77
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-cli",
3
- "version": "0.23.0",
3
+ "version": "0.23.2",
4
4
  "type": "module",
5
5
  "description": "A CLI useful to manage DX tools.",
6
6
  "repository": {
@@ -48,7 +48,7 @@
48
48
  "semver": "^7.7.4",
49
49
  "yaml": "^2.8.4",
50
50
  "zod": "^4.4.2",
51
- "@pagopa/dx-savemoney": "^0.3.0"
51
+ "@pagopa/dx-savemoney": "^0.3.1"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@tsconfig/node24": "24.0.4",
@@ -56,15 +56,15 @@
56
56
  "@types/libsodium-wrappers": "^0.8.2",
57
57
  "@types/node": "^22.19.17",
58
58
  "@types/semver": "^7.7.1",
59
- "@vitest/coverage-v8": "^3.2.4",
59
+ "@vitest/coverage-v8": "^4.1.8",
60
60
  "eslint": "^10.3.0",
61
61
  "fast-check": "^4.8.0",
62
62
  "memfs": "^4.57.2",
63
63
  "plop": "^4.0.5",
64
64
  "prettier": "3.8.3",
65
65
  "typescript": "~5.9.3",
66
- "vitest": "^3.2.4",
67
- "vitest-mock-extended": "^3.1.1",
66
+ "vitest": "^4.1.8",
67
+ "vitest-mock-extended": "^4.0.0",
68
68
  "@pagopa/eslint-config": "^6.0.4"
69
69
  },
70
70
  "engines": {
@@ -68,7 +68,6 @@
68
68
  },
69
69
  "build": {
70
70
  "targetName": "build",
71
- "configName": "tsconfig.json",
72
71
  "buildDepsName": "build-deps",
73
72
  "watchDepsName": "watch-deps"
74
73
  }
@@ -1,95 +0,0 @@
1
- import { describe, expect, it, vi } from "vitest";
2
- import { AzureSubscriptionRepository } from "../cloud-account-repository.js";
3
- const createMockSubscription = (overrides = {}) => ({
4
- displayName: "Test Subscription",
5
- state: "Enabled",
6
- subscriptionId: "00000000-0000-0000-0000-000000000001",
7
- ...overrides,
8
- });
9
- const createMockSubscriptionClient = (subscriptions) => {
10
- const listIterator = async function* () {
11
- for (const sub of subscriptions) {
12
- yield sub;
13
- }
14
- };
15
- return {
16
- subscriptions: {
17
- list: listIterator,
18
- },
19
- };
20
- };
21
- vi.mock("@azure/arm-resources-subscriptions", () => ({
22
- SubscriptionClient: vi.fn(),
23
- }));
24
- vi.mock("@azure/identity", () => ({
25
- DefaultAzureCredential: vi.fn(),
26
- }));
27
- import { SubscriptionClient } from "@azure/arm-resources-subscriptions";
28
- import { DefaultAzureCredential } from "@azure/identity";
29
- const MockedSubscriptionClient = SubscriptionClient;
30
- describe("AzureSubscriptionRepository", () => {
31
- it("should return a list of enabled subscriptions", async () => {
32
- const subscriptions = [
33
- createMockSubscription({
34
- displayName: "Sub 1",
35
- subscriptionId: "sub-1",
36
- }),
37
- createMockSubscription({
38
- displayName: "Sub 2",
39
- subscriptionId: "sub-2",
40
- }),
41
- ];
42
- MockedSubscriptionClient.mockImplementation(() => createMockSubscriptionClient(subscriptions));
43
- const repository = new AzureSubscriptionRepository(new DefaultAzureCredential());
44
- const result = await repository.list();
45
- expect(result).toHaveLength(2);
46
- expect(result[0]).toMatchObject({
47
- displayName: "Sub 1",
48
- id: "sub-1",
49
- });
50
- expect(result[1]).toMatchObject({
51
- displayName: "Sub 2",
52
- id: "sub-2",
53
- });
54
- });
55
- it("should filter out disabled subscriptions", async () => {
56
- const subscriptions = [
57
- createMockSubscription({
58
- displayName: "Enabled Sub",
59
- state: "Enabled",
60
- subscriptionId: "enabled-sub",
61
- }),
62
- createMockSubscription({
63
- displayName: "Disabled Sub",
64
- state: "Disabled",
65
- subscriptionId: "disabled-sub",
66
- }),
67
- ];
68
- MockedSubscriptionClient.mockImplementation(() => createMockSubscriptionClient(subscriptions));
69
- const repository = new AzureSubscriptionRepository(new DefaultAzureCredential());
70
- const result = await repository.list();
71
- expect(result).toHaveLength(1);
72
- expect(result[0]).toMatchObject({
73
- displayName: "Enabled Sub",
74
- id: "enabled-sub",
75
- });
76
- });
77
- it("should return an empty array when no subscriptions exist", async () => {
78
- MockedSubscriptionClient.mockImplementation(() => createMockSubscriptionClient([]));
79
- const repository = new AzureSubscriptionRepository(new DefaultAzureCredential());
80
- const result = await repository.list();
81
- expect(result).toEqual([]);
82
- });
83
- it("should filter out subscriptions with other states", async () => {
84
- const subscriptions = [
85
- createMockSubscription({ state: "Enabled" }),
86
- createMockSubscription({ state: "Warned" }),
87
- createMockSubscription({ state: "PastDue" }),
88
- createMockSubscription({ state: "Deleted" }),
89
- ];
90
- MockedSubscriptionClient.mockImplementation(() => createMockSubscriptionClient(subscriptions));
91
- const repository = new AzureSubscriptionRepository(new DefaultAzureCredential());
92
- const result = await repository.list();
93
- expect(result).toHaveLength(1);
94
- });
95
- });