@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
@@ -1,378 +0,0 @@
1
- import { DefaultAzureCredential } from "@azure/identity";
2
- import { test as baseTest, beforeEach, describe, expect, vi } from "vitest";
3
- import { AzureCloudAccountService } from "../cloud-account-service.js";
4
- const { queryResources } = vi.hoisted(() => ({
5
- queryResources: vi.fn().mockRejectedValue(new Error("Not implemented")),
6
- }));
7
- const { mockProviderGet, mockProviderRegister } = vi.hoisted(() => ({
8
- mockProviderGet: vi
9
- .fn()
10
- .mockResolvedValue({ registrationState: "Registered" }),
11
- mockProviderRegister: vi.fn().mockResolvedValue({}),
12
- }));
13
- const { mockRoleAssignmentsCreate, mockRoleAssignmentsListForScope } = vi.hoisted(() => ({
14
- mockRoleAssignmentsCreate: vi.fn().mockResolvedValue({}),
15
- mockRoleAssignmentsListForScope: vi.fn(),
16
- }));
17
- const { mockCreateFederatedIdentityCredential, mockCreateIdentity, mockCreateKeyVault, mockCreateResourceGroup, mockDeleteResourceGroup, mockGetSubscription, mockKeyVaultNameAvailability, mockSetSecret, } = vi.hoisted(() => ({
18
- mockCreateFederatedIdentityCredential: vi.fn().mockResolvedValue({}),
19
- mockCreateIdentity: vi
20
- .fn()
21
- .mockResolvedValue({ clientId: "client-1", principalId: "principal-1" }),
22
- mockCreateKeyVault: vi.fn().mockResolvedValue({}),
23
- mockCreateResourceGroup: vi.fn().mockResolvedValue({}),
24
- mockDeleteResourceGroup: vi.fn().mockResolvedValue({}),
25
- mockGetSubscription: vi.fn().mockResolvedValue({ tenantId: "tenant-1" }),
26
- mockKeyVaultNameAvailability: vi.fn().mockResolvedValue({
27
- nameAvailable: true,
28
- }),
29
- mockSetSecret: vi.fn().mockResolvedValue({}),
30
- }));
31
- vi.mock("@azure/arm-authorization", () => ({
32
- AuthorizationManagementClient: class {
33
- roleAssignments = {
34
- create: mockRoleAssignmentsCreate,
35
- listForScope: mockRoleAssignmentsListForScope,
36
- };
37
- },
38
- }));
39
- vi.mock("@azure/arm-keyvault", () => ({
40
- KeyVaultManagementClient: class {
41
- vaults = {
42
- beginCreateOrUpdateAndWait: mockCreateKeyVault,
43
- checkNameAvailability: mockKeyVaultNameAvailability,
44
- };
45
- },
46
- }));
47
- vi.mock("@azure/arm-msi", () => ({
48
- ManagedServiceIdentityClient: class {
49
- federatedIdentityCredentials = {
50
- createOrUpdate: mockCreateFederatedIdentityCredential,
51
- };
52
- userAssignedIdentities = {
53
- createOrUpdate: mockCreateIdentity,
54
- };
55
- },
56
- }));
57
- vi.mock("@azure/identity", () => ({
58
- DefaultAzureCredential: vi.fn(),
59
- }));
60
- vi.mock("@azure/arm-resourcegraph", () => ({
61
- ResourceGraphClient: class {
62
- resources = queryResources;
63
- },
64
- }));
65
- vi.mock("@azure/arm-resources", () => ({
66
- ResourceManagementClient: class {
67
- providers = {
68
- get: mockProviderGet,
69
- register: mockProviderRegister,
70
- };
71
- resourceGroups = {
72
- beginDeleteAndWait: mockDeleteResourceGroup,
73
- createOrUpdate: mockCreateResourceGroup,
74
- };
75
- },
76
- }));
77
- vi.mock("@azure/arm-resources-subscriptions", () => ({
78
- SubscriptionClient: class {
79
- subscriptions = {
80
- get: mockGetSubscription,
81
- };
82
- },
83
- }));
84
- vi.mock("@azure/keyvault-secrets", () => ({
85
- SecretClient: class {
86
- setSecret = mockSetSecret;
87
- },
88
- }));
89
- const test = baseTest.extend({
90
- // the empty pattern is required by vitest!!!
91
- // eslint-disable-next-line no-empty-pattern
92
- cloudAccountService: async ({}, use) => {
93
- const cloudAccountService = new AzureCloudAccountService(new DefaultAzureCredential());
94
- await use(cloudAccountService);
95
- },
96
- });
97
- beforeEach(() => {
98
- queryResources.mockReset();
99
- queryResources.mockResolvedValue({ data: [], totalRecords: 0 });
100
- mockCreateFederatedIdentityCredential.mockClear();
101
- mockCreateIdentity.mockClear();
102
- mockCreateIdentity.mockResolvedValue({
103
- clientId: "client-1",
104
- principalId: "principal-1",
105
- });
106
- mockCreateKeyVault.mockClear();
107
- mockCreateResourceGroup.mockClear();
108
- mockDeleteResourceGroup.mockClear();
109
- mockGetSubscription.mockClear();
110
- mockGetSubscription.mockResolvedValue({ tenantId: "tenant-1" });
111
- mockKeyVaultNameAvailability.mockClear();
112
- mockKeyVaultNameAvailability.mockResolvedValue({ nameAvailable: true });
113
- mockProviderGet.mockClear();
114
- mockProviderGet.mockResolvedValue({ registrationState: "Registered" });
115
- mockProviderRegister.mockClear();
116
- mockRoleAssignmentsCreate.mockClear();
117
- mockRoleAssignmentsListForScope.mockReset();
118
- mockSetSecret.mockClear();
119
- });
120
- describe("getTerraformBackend", () => {
121
- test("returns undefined when no matching storage account is found", async ({ cloudAccountService, }) => {
122
- queryResources.mockResolvedValueOnce({
123
- data: [],
124
- totalRecords: 0,
125
- });
126
- const result = await cloudAccountService.getTerraformBackend("sub-1", {
127
- name: "dev",
128
- prefix: "dx",
129
- });
130
- expect(result).toBeUndefined();
131
- });
132
- test("return the only matching storage account", async ({ cloudAccountService, }) => {
133
- queryResources.mockResolvedValueOnce({
134
- data: [
135
- {
136
- location: "italynorth",
137
- name: "dxditntfstatest01",
138
- resourceGroup: "dx-d-itn-tfstate-rg-01",
139
- subscriptionId: "sub-1",
140
- type: "microsoft.storage/storageaccounts",
141
- },
142
- ],
143
- totalRecords: 1,
144
- });
145
- const result = await cloudAccountService.getTerraformBackend("sub-1", {
146
- name: "dev",
147
- prefix: "dx",
148
- });
149
- expect(result).toEqual(expect.objectContaining({
150
- resourceGroupName: "dx-d-itn-tfstate-rg-01",
151
- storageAccountName: "dxditntfstatest01",
152
- type: "azurerm",
153
- }));
154
- });
155
- test("returns the best matching storage account among multiple", async ({ cloudAccountService, }) => {
156
- queryResources.mockResolvedValueOnce({
157
- data: [
158
- {
159
- location: "italynorth",
160
- name: "dxditntfstatest01",
161
- resourceGroup: "dx-d-itn-tfstate-rg-01",
162
- subscriptionId: "sub-1",
163
- type: "microsoft.storage/storageaccounts",
164
- },
165
- {
166
- location: "italynorth",
167
- name: "dxditntfstatest02",
168
- resourceGroup: "dx-d-itn-tfstate-rg-01",
169
- subscriptionId: "sub-1",
170
- type: "microsoft.storage/storageaccounts",
171
- },
172
- {
173
- location: "westeurope",
174
- name: "dxdweutfstatest01",
175
- resourceGroup: "dx-d-weu-tfstate-rg-01",
176
- subscriptionId: "sub-1",
177
- type: "microsoft.storage/storageaccounts",
178
- },
179
- ],
180
- totalRecords: 3,
181
- });
182
- const result = await cloudAccountService.getTerraformBackend("sub-1", {
183
- name: "dev",
184
- prefix: "dx",
185
- });
186
- expect(result).toEqual(expect.objectContaining({
187
- resourceGroupName: "dx-d-itn-tfstate-rg-01",
188
- storageAccountName: "dxditntfstatest02",
189
- type: "azurerm",
190
- }));
191
- });
192
- });
193
- describe("isInitialized", () => {
194
- test("returns true when both bootstrap identity and common Key Vault exist and all providers are registered", async ({ cloudAccountService, }) => {
195
- // First call: identity query → found
196
- queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
197
- // Second call: key vault query → found
198
- queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
199
- // Provider checks → all registered (default mock)
200
- const result = await cloudAccountService.isInitialized("sub-1", {
201
- name: "dev",
202
- prefix: "dx",
203
- });
204
- expect(result).toBe(true);
205
- });
206
- test("returns false when bootstrap identity exists but common Key Vault does not", async ({ cloudAccountService, }) => {
207
- // First call: identity query → found
208
- queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
209
- // Second call: key vault query → not found
210
- queryResources.mockResolvedValueOnce({ data: [], totalRecords: 0 });
211
- const result = await cloudAccountService.isInitialized("sub-1", {
212
- name: "dev",
213
- prefix: "dx",
214
- });
215
- expect(result).toBe(false);
216
- });
217
- test("returns false when common Key Vault exists but bootstrap identity does not", async ({ cloudAccountService, }) => {
218
- // First call: identity query → not found
219
- queryResources.mockResolvedValueOnce({ data: [], totalRecords: 0 });
220
- // Second call: key vault query → found
221
- queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
222
- const result = await cloudAccountService.isInitialized("sub-1", {
223
- name: "dev",
224
- prefix: "dx",
225
- });
226
- expect(result).toBe(false);
227
- });
228
- test("returns false when resources exist but a required provider is not registered", async ({ cloudAccountService, }) => {
229
- // Both resources exist
230
- queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
231
- queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
232
- // One provider is not registered
233
- mockProviderGet.mockResolvedValueOnce({
234
- registrationState: "NotRegistered",
235
- });
236
- const result = await cloudAccountService.isInitialized("sub-1", {
237
- name: "dev",
238
- prefix: "dx",
239
- });
240
- expect(result).toBe(false);
241
- });
242
- });
243
- describe("initialize", () => {
244
- test("assigns bootstrap roles and creates bootstrap environment secrets", async ({ cloudAccountService, }) => {
245
- const createOrUpdateEnvironmentSecret = vi
246
- .fn()
247
- .mockResolvedValue(undefined);
248
- await cloudAccountService.initialize({
249
- csp: "azure",
250
- defaultLocation: "italynorth",
251
- displayName: "Test subscription",
252
- id: "sub-1",
253
- }, {
254
- name: "dev",
255
- prefix: "dx",
256
- }, {
257
- clientId: "app-client-id",
258
- id: "app-id",
259
- installationId: "installation-id",
260
- key: "private-key\n",
261
- }, {
262
- owner: "pagopa",
263
- repo: "dx",
264
- }, {
265
- createBranch: vi.fn(),
266
- createOrUpdateEnvironmentSecret,
267
- createPullRequest: vi.fn(),
268
- getFileContent: vi.fn(),
269
- getRepository: vi.fn(),
270
- updateFile: vi.fn(),
271
- });
272
- expect(mockRoleAssignmentsCreate).toHaveBeenCalledTimes(3);
273
- expect(mockRoleAssignmentsCreate).toHaveBeenCalledWith("/subscriptions/sub-1", expect.any(String), expect.objectContaining({
274
- principalId: "principal-1",
275
- principalType: "ServicePrincipal",
276
- roleDefinitionId: "/subscriptions/sub-1/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168",
277
- }));
278
- expect(mockRoleAssignmentsCreate).toHaveBeenCalledWith("/subscriptions/sub-1", expect.any(String), expect.objectContaining({
279
- principalId: "principal-1",
280
- principalType: "ServicePrincipal",
281
- roleDefinitionId: "/subscriptions/sub-1/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
282
- }));
283
- expect(mockRoleAssignmentsCreate).toHaveBeenCalledWith("/subscriptions/sub-1", expect.any(String), expect.objectContaining({
284
- principalId: "principal-1",
285
- principalType: "ServicePrincipal",
286
- roleDefinitionId: "/subscriptions/sub-1/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe",
287
- }));
288
- expect(mockCreateFederatedIdentityCredential).toHaveBeenCalledWith("dx-d-itn-common-rg-01", "dx-d-itn-bootstrap-id-01", "dx-bootstrapper-dev-cd", {
289
- audiences: ["api://AzureADTokenExchange"],
290
- issuer: "https://token.actions.githubusercontent.com",
291
- subject: "repo:pagopa/dx:environment:bootstrapper-dev-cd",
292
- });
293
- expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledTimes(7);
294
- expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
295
- environmentName: "bootstrapper-dev-cd",
296
- owner: "pagopa",
297
- repo: "dx",
298
- secretName: "ARM_CLIENT_ID",
299
- secretValue: "client-1",
300
- });
301
- expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
302
- environmentName: "bootstrapper-dev-cd",
303
- owner: "pagopa",
304
- repo: "dx",
305
- secretName: "ARM_TENANT_ID",
306
- secretValue: "tenant-1",
307
- });
308
- expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
309
- environmentName: "bootstrapper-dev-cd",
310
- owner: "pagopa",
311
- repo: "dx",
312
- secretName: "ARM_SUBSCRIPTION_ID",
313
- secretValue: "sub-1",
314
- });
315
- expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
316
- environmentName: "bootstrapper-dev-cd",
317
- owner: "pagopa",
318
- repo: "dx",
319
- secretName: "GH_APP_ID",
320
- secretValue: "app-id",
321
- });
322
- expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
323
- environmentName: "bootstrapper-dev-cd",
324
- owner: "pagopa",
325
- repo: "dx",
326
- secretName: "GH_APP_CLIENT_ID",
327
- secretValue: "app-client-id",
328
- });
329
- expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
330
- environmentName: "bootstrapper-dev-cd",
331
- owner: "pagopa",
332
- repo: "dx",
333
- secretName: "GH_APP_INSTALLATION_ID",
334
- secretValue: "installation-id",
335
- });
336
- expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
337
- environmentName: "bootstrapper-dev-cd",
338
- owner: "pagopa",
339
- repo: "dx",
340
- secretName: "GH_APP_KEY",
341
- secretValue: "private-key",
342
- });
343
- });
344
- test("uses a repository-specific federated credential name", async ({ cloudAccountService, }) => {
345
- const createOrUpdateEnvironmentSecret = vi
346
- .fn()
347
- .mockResolvedValue(undefined);
348
- await cloudAccountService.initialize({
349
- csp: "azure",
350
- defaultLocation: "italynorth",
351
- displayName: "Test subscription",
352
- id: "sub-1",
353
- }, {
354
- name: "dev",
355
- prefix: "dx",
356
- }, {
357
- clientId: "app-client-id",
358
- id: "app-id",
359
- installationId: "installation-id",
360
- key: "private-key\n",
361
- }, {
362
- owner: "pagopa",
363
- repo: "dx-playground",
364
- }, {
365
- createBranch: vi.fn(),
366
- createOrUpdateEnvironmentSecret,
367
- createPullRequest: vi.fn(),
368
- getFileContent: vi.fn(),
369
- getRepository: vi.fn(),
370
- updateFile: vi.fn(),
371
- });
372
- expect(mockCreateFederatedIdentityCredential).toHaveBeenCalledWith("dx-d-itn-common-rg-01", "dx-d-itn-bootstrap-id-01", "dx-playground-bootstrapper-dev-cd", {
373
- audiences: ["api://AzureADTokenExchange"],
374
- issuer: "https://token.actions.githubusercontent.com",
375
- subject: "repo:pagopa/dx-playground:environment:bootstrapper-dev-cd",
376
- });
377
- });
378
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,56 +0,0 @@
1
- import { ok } from "neverthrow";
2
- import { describe, expect, it, vi } from "vitest";
3
- import { LocalCodemodRegistry } from "../registry.js";
4
- describe("LocalCodemodRegistry", () => {
5
- const makeCodemod = (id, description = id) => ({
6
- apply: vi.fn().mockResolvedValue(undefined),
7
- description,
8
- id,
9
- });
10
- it("returns empty list when no codemods are registered", async () => {
11
- const registry = new LocalCodemodRegistry();
12
- const result = await registry.getAll();
13
- expect(result).toStrictEqual(ok([]));
14
- });
15
- it("adds codemods and lists them via getAll", async () => {
16
- const registry = new LocalCodemodRegistry();
17
- const a = makeCodemod("a", "A");
18
- const b = makeCodemod("b", "B");
19
- registry.add(a);
20
- registry.add(b);
21
- const result = await registry.getAll();
22
- expect.assertions(3);
23
- expect(result.isOk()).toBe(true);
24
- const expected = result.unwrapOr([]);
25
- expect(expected).toHaveLength(2);
26
- expect(expected).toEqual(expect.arrayContaining([
27
- expect.objectContaining({ id: "a" }),
28
- expect.objectContaining({ id: "b" }),
29
- ]));
30
- });
31
- it("retrieves a codemod by id and returns undefined when missing", async () => {
32
- const registry = new LocalCodemodRegistry();
33
- const a = makeCodemod("a", "A");
34
- registry.add(a);
35
- const found = await registry.getById("a");
36
- expect(found.isOk()).toBe(true);
37
- const expected = found.unwrapOr(undefined);
38
- expect(expected).toBe(a);
39
- const missing = await registry.getById("nope");
40
- expect(missing.isOk()).toBe(true);
41
- const missingValue = missing.unwrapOr(undefined);
42
- expect(missingValue).toBeUndefined();
43
- });
44
- it("overwrites an existing codemod when adding with the same id", async () => {
45
- const registry = new LocalCodemodRegistry();
46
- const first = makeCodemod("a", "first");
47
- const second = makeCodemod("a", "second");
48
- registry.add(first);
49
- registry.add(second);
50
- const byId = await registry.getById("a");
51
- expect(byId.isOk()).toBe(true);
52
- const byIdValue = byId.unwrapOr(undefined);
53
- expect(byIdValue).toBe(second);
54
- expect(byIdValue).not.toBe(first);
55
- });
56
- });
@@ -1,77 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { migrateWorkflow } from "../use-azure-appsvc.js";
3
- describe("migrateWorkflow", () => {
4
- const sha = "testsha";
5
- const migrate = migrateWorkflow(sha);
6
- it("adds disable_auto_staging_deploy under with for web_app_deploy", () => {
7
- const input = `
8
- jobs:
9
- deploy:
10
- uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
11
- with:
12
- web_app_name: my-app
13
- use_staging_slot: true
14
- `;
15
- const output = migrate(input, "workflow.yaml");
16
- expect(output).toContain("disable_auto_staging_deploy: true");
17
- });
18
- it("adds disable_auto_staging_deploy under with for function_app_deploy", () => {
19
- const input = `
20
- jobs:
21
- deploy:
22
- uses: pagopa/dx/.github/workflows/function_app_deploy.yaml@main
23
- with:
24
- function_app_name: my-func
25
- use_staging_slot: true
26
- `;
27
- const output = migrate(input, "workflow.yaml");
28
- expect(output).toContain("disable_auto_staging_deploy: true");
29
- });
30
- it("renames function_app_name to web_app_name", () => {
31
- const input = `
32
- jobs:
33
- deploy:
34
- uses: pagopa/dx/.github/workflows/function_app_deploy.yaml@main
35
- with:
36
- function_app_name: my-func
37
- `;
38
- const output = migrate(input, "workflow.yaml");
39
- expect(output).toContain("web_app_name: my-func");
40
- expect(output).not.toContain("function_app_name:");
41
- });
42
- it("removes use_staging_slot", () => {
43
- const input = `
44
- jobs:
45
- deploy:
46
- uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
47
- with:
48
- web_app_name: my-app
49
- use_staging_slot: true
50
- `;
51
- const output = migrate(input, "workflow.yaml");
52
- expect(output).not.toContain("use_staging_slot:");
53
- });
54
- it("updates uses to release-azure-appsvc.yaml@sha", () => {
55
- const input = `
56
- jobs:
57
- deploy:
58
- uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
59
- with:
60
- web_app_name: my-app
61
- `;
62
- const output = migrate(input, "workflow.yaml");
63
- expect(output).toContain(`uses: pagopa/dx/.github/workflows/release-azure-appsvc-v1.yaml@${sha}`);
64
- });
65
- it("does not change unrelated workflows", () => {
66
- const input = `
67
- jobs:
68
- build:
69
- runs-on: ubuntu-latest
70
- steps:
71
- - name: Checkout
72
- uses: actions/checkout@v3
73
- `;
74
- const output = migrate(input, "workflow.yaml");
75
- expect(output).toBe(input);
76
- });
77
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,148 +0,0 @@
1
- import { beforeEach, describe, expect, test, vi } from "vitest";
2
- import YAML from "yaml";
3
- import { extractPackageExtensions, NPM, preparePackageJsonForPnpm, usePnpm, writePnpmWorkspaceFile, Yarn, } from "../use-pnpm.js";
4
- const { readFile, stdout, writeFile } = vi.hoisted(() => ({
5
- readFile: vi.fn(async () => ""),
6
- stdout: vi.fn(),
7
- writeFile: vi.fn(),
8
- }));
9
- vi.mock("execa", () => ({
10
- $: vi.fn((opts) => {
11
- const hasOptions = typeof opts === "object" && Object.hasOwn(opts, "lines");
12
- if (hasOptions) {
13
- return () => stdout().then((output) => ({
14
- stdout: output.split("\n"),
15
- }));
16
- }
17
- return stdout().then((output) => ({
18
- stdout: output,
19
- }));
20
- }),
21
- }));
22
- vi.mock("node:fs/promises", () => ({
23
- default: {
24
- appendFile: () => Promise.resolve(),
25
- readFile,
26
- rm: () => Promise.resolve(),
27
- stat: () => Promise.resolve({
28
- isFile: () => true,
29
- }),
30
- writeFile,
31
- },
32
- }));
33
- vi.mock("../git.js", async () => ({
34
- getLatestCommitShaOrRef: async () => "dummy-sha",
35
- }));
36
- describe("pm", () => {
37
- test("yarn workspaces are parsed correctly", async () => {
38
- const yarn = new Yarn();
39
- stdout.mockResolvedValueOnce(`{"location":".","name":"io-messages"}\n{"location":"apps/citizen-func","name":"citizen-func"}`);
40
- const workspaces = await yarn.listWorkspaces();
41
- expect(workspaces).toEqual(["io-messages", "citizen-func"]);
42
- });
43
- test("npm workspaces are parsed correctly", async () => {
44
- const npm = new NPM();
45
- stdout.mockResolvedValueOnce(`[{ "name": "io-messages", "location": "." },{ "name": "citizen-func", "location": "apps/citizen-func" }]`);
46
- const workspaces = await npm.listWorkspaces();
47
- expect(workspaces).toEqual(["io-messages", "citizen-func"]);
48
- });
49
- });
50
- describe("extractPackageExtensions", () => {
51
- beforeEach(() => {
52
- vi.clearAllMocks();
53
- });
54
- test("returns packageExtensions only if present", async () => {
55
- const yarnrc = {
56
- packageExtensions: {
57
- "some-package@*": {
58
- peerDependencies: {
59
- react: "*",
60
- },
61
- },
62
- },
63
- };
64
- readFile.mockResolvedValueOnce(YAML.stringify(yarnrc));
65
- await expect(extractPackageExtensions()).resolves.toEqual(yarnrc.packageExtensions);
66
- expect(readFile).toHaveBeenCalledOnce();
67
- });
68
- test("returns undefined if packageExtensions is not present", async () => {
69
- const yarnrc = {
70
- someOtherField: {},
71
- };
72
- readFile.mockResolvedValueOnce(YAML.stringify(yarnrc));
73
- await expect(extractPackageExtensions()).resolves.toBeUndefined();
74
- expect(readFile).toHaveBeenCalledOnce();
75
- });
76
- });
77
- describe("preparePackageJsonForPnpm", () => {
78
- beforeEach(() => {
79
- vi.clearAllMocks();
80
- });
81
- test("removes packageManager field and keeps workspaces", async () => {
82
- const packageJson = {
83
- name: "test-monorepo",
84
- packageManager: "yarn@1.22.10",
85
- version: "1.0.0",
86
- workspaces: ["packages/*"],
87
- };
88
- readFile.mockResolvedValueOnce(JSON.stringify(packageJson, null, 2));
89
- const workspaces = await preparePackageJsonForPnpm();
90
- expect(workspaces).toEqual(["packages/*"]);
91
- expect(readFile).toHaveBeenCalledOnce();
92
- expect(writeFile).toHaveBeenCalledWith("package.json", JSON.stringify({
93
- name: packageJson.name,
94
- version: packageJson.version,
95
- }, null, 2));
96
- });
97
- });
98
- describe("writePnpmWorkspaceFile", () => {
99
- beforeEach(() => {
100
- vi.clearAllMocks();
101
- });
102
- test("writes pnpm-workspace.yaml with given workspaces", async () => {
103
- const workspaces = ["packages/*", "apps/*"];
104
- const packageExtensions = {
105
- "express@*": {
106
- peerDependencies: {
107
- typescript: "*",
108
- },
109
- },
110
- };
111
- await writePnpmWorkspaceFile(workspaces, packageExtensions);
112
- expect(writeFile).toHaveBeenCalledWith("pnpm-workspace.yaml", expect.stringContaining(YAML.stringify({ packages: workspaces })), "utf-8");
113
- expect(writeFile).toHaveBeenCalledWith("pnpm-workspace.yaml", expect.stringContaining(YAML.stringify({ packageExtensions })), "utf-8");
114
- });
115
- });
116
- describe("usePnpm", () => {
117
- beforeEach(() => {
118
- vi.resetAllMocks();
119
- });
120
- test("rejects if the project is already using pnpm", async () => {
121
- await expect(usePnpm("pnpm", "10.20")).rejects.toThrow();
122
- });
123
- test.each([
124
- { expected: false, version: "18.0.0" },
125
- { expected: false, version: "20.10.0" },
126
- { expected: false, version: "20.19.4" },
127
- { expected: true, version: "22.0.0" },
128
- { expected: true, version: "20.19.5" },
129
- ])("rejects if Node.js version is less than required ($version)", async ({ expected, version }) => {
130
- stdout.mockResolvedValue("[]");
131
- readFile.mockResolvedValueOnce(JSON.stringify({ name: "test-monorepo", workspaces: [] }));
132
- await expect(usePnpm("npm", version).then(() => true, () => false)).resolves.toBe(expected);
133
- });
134
- test("moves workspaces from package.json to pnpm-workspace.yaml", async () => {
135
- const packageJson = {
136
- name: "test-monorepo",
137
- packageManager: "yarn@1.22.10",
138
- version: "1.0.0",
139
- workspaces: ["packages/*"],
140
- };
141
- readFile.mockResolvedValueOnce(JSON.stringify(packageJson, null, 2));
142
- stdout.mockResolvedValue(`[]`); // npm list workspaces
143
- await usePnpm("npm", "22.0.0");
144
- expect(writeFile).toHaveBeenNthCalledWith(2, "pnpm-workspace.yaml", expect.stringContaining(YAML.stringify({
145
- packages: packageJson.workspaces,
146
- })), "utf-8");
147
- });
148
- });
@@ -1 +0,0 @@
1
- export {};