@pagopa/dx-cli 0.15.5 → 0.16.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.
package/bin/index.js CHANGED
@@ -23,4 +23,4 @@ await configure({
23
23
  },
24
24
  });
25
25
 
26
- runCli(packageJson.version);
26
+ runCli(packageJson.version).catch((error) => console.error(error.message));
@@ -1,36 +1,20 @@
1
+ import { getLogger } from "@logtape/logtape";
1
2
  import chalk from "chalk";
2
3
  import { Command } from "commander";
3
- import { $ } from "execa";
4
- import { errAsync, okAsync, ResultAsync } from "neverthrow";
4
+ import { $, ExecaError } from "execa";
5
+ import { okAsync, ResultAsync } from "neverthrow";
5
6
  import * as path from "node:path";
6
7
  import { oraPromise } from "ora";
7
- import { Repository, RepositoryNotFoundError, } from "../../../domain/github.js";
8
+ import { z } from "zod";
9
+ import { Repository, } from "../../../domain/github.js";
8
10
  import { tf$ } from "../../execa/terraform.js";
9
- import { payloadSchema as answersSchema, PLOP_MONOREPO_GENERATOR_NAME, } from "../../plop/generators/monorepo/index.js";
10
- import { setMonorepoGenerator } from "../../plop/index.js";
11
- import { getGenerator, getPrompts, initPlop } from "../../plop/index.js";
12
- import { decode } from "../../zod/index.js";
11
+ import { getPlopInstance, runDeploymentEnvironmentGenerator, runMonorepoGenerator, } from "../../plop/index.js";
13
12
  import { exitWithError } from "../index.js";
14
13
  const withSpinner = (text, successText, failText, promise) => ResultAsync.fromPromise(oraPromise(promise, {
15
14
  failText,
16
15
  successText,
17
16
  text,
18
- }), (cause) => {
19
- console.error(`Something went wrong: ${JSON.stringify(cause, null, 2)}`);
20
- return new Error(failText, { cause });
21
- });
22
- // TODO: Check Cloud Environment exists
23
- // TODO: Check CSP CLI is installed
24
- // TODO: Check user has permissions to handle Terraform state
25
- const validateAnswers = (githubService) => (answers) => ResultAsync.fromPromise(githubService.getRepository(answers.repoOwner, answers.repoName), (error) => error)
26
- .andThen(({ fullName }) => errAsync(new Error(`Repository ${fullName} already exists.`)))
27
- .orElse((error) => error instanceof RepositoryNotFoundError
28
- ? // If repository is not found, it's safe to proceed
29
- okAsync(answers)
30
- : // Otherwise, propagate the error
31
- errAsync(error))
32
- .map(() => answers);
33
- const runGeneratorActions = (generator) => (answers) => withSpinner("Creating workspace files...", "Workspace files created successfully!", "Failed to create workspace files.", generator.runActions(answers)).map(() => answers);
17
+ }), (cause) => new Error(failText, { cause }));
34
18
  const displaySummary = (initResult) => {
35
19
  const { pr, repository } = initResult;
36
20
  console.log(chalk.green.bold("\nWorkspace created successfully!"));
@@ -51,21 +35,41 @@ const displaySummary = (initResult) => {
51
35
  console.log(`Please, manually create a Pull Request in the GitHub repository to review the scaffolded code.\n`);
52
36
  }
53
37
  };
54
- const checkTerraformCliIsInstalled = (text, successText, failText) => withSpinner(text, successText, failText, tf$ `terraform -version`);
55
- const checkPreconditions = () => checkTerraformCliIsInstalled("Checking Terraform CLI is installed...", "Terraform CLI is installed!", "Terraform CLI is not installed.");
38
+ 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`);
39
+ const azureAccountSchema = z.object({
40
+ user: z.object({
41
+ name: z.string().min(1),
42
+ }),
43
+ });
44
+ const ensureAzLogin = async () => {
45
+ const { stdout } = await tf$ `az account show`;
46
+ await tf$ `az group list`;
47
+ const parsed = JSON.parse(stdout);
48
+ const { user } = azureAccountSchema.parse(parsed);
49
+ return user.name;
50
+ };
51
+ 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());
52
+ const checkPreconditions = () => checkTerraformCliIsInstalled().andThen(() => checkAzLogin());
56
53
  const createRemoteRepository = ({ repoName, repoOwner, }) => {
57
- const cwd = path.resolve(repoName, "infra", "repository");
54
+ const logger = getLogger(["dx-cli", "init"]);
55
+ const repo$ = tf$({ cwd: path.resolve("infra", "repository") });
58
56
  const applyTerraform = async () => {
59
- await tf$({ cwd }) `terraform init`;
60
- await tf$({ cwd }) `terraform apply -auto-approve`;
57
+ try {
58
+ await repo$ `terraform init`;
59
+ await repo$ `terraform apply -auto-approve`;
60
+ }
61
+ catch (error) {
62
+ if (error instanceof ExecaError) {
63
+ logger.error(error.shortMessage);
64
+ }
65
+ throw error;
66
+ }
61
67
  };
62
68
  return withSpinner("Creating GitHub repository...", "GitHub repository created successfully!", "Failed to create GitHub repository.", applyTerraform()).map(() => new Repository(repoName, repoOwner));
63
69
  };
64
70
  const initializeGitRepository = (repository) => {
65
- const cwd = path.resolve(repository.name);
66
71
  const branchName = "features/scaffold-workspace";
67
72
  const git$ = $({
68
- cwd,
69
73
  shell: true,
70
74
  });
71
75
  const pushToOrigin = async () => {
@@ -73,7 +77,7 @@ const initializeGitRepository = (repository) => {
73
77
  await git$ `git add README.md`;
74
78
  await git$ `git commit --no-gpg-sign -m "Create README.md"`;
75
79
  await git$ `git branch -M main`;
76
- await git$ `git remote add origin ${repository.ssh}`;
80
+ await git$ `git remote add origin ${repository.origin}`;
77
81
  await git$ `git push -u origin main`;
78
82
  await git$ `git switch -c ${branchName}`;
79
83
  await git$ `git add .`;
@@ -82,16 +86,12 @@ const initializeGitRepository = (repository) => {
82
86
  };
83
87
  return withSpinner("Pushing code to GitHub...", "Code pushed to GitHub successfully!", "Failed to push code to GitHub.", pushToOrigin()).map(() => ({ branchName, repository }));
84
88
  };
85
- const handleNewGitHubRepository = (githubService) => (answers) => createRemoteRepository(answers)
89
+ const handleNewGitHubRepository = (githubService) => (payload) => createRemoteRepository(payload)
86
90
  .andThen(initializeGitRepository)
87
91
  .andThen((localWorkspace) => createPullRequest(githubService)(localWorkspace).map((pr) => ({
88
92
  pr,
89
93
  repository: localWorkspace.repository,
90
94
  })));
91
- const makeInitResult = (answers, { pr, repository }) => ({
92
- pr,
93
- repository,
94
- });
95
95
  const createPullRequest = (githubService) => ({ branchName, repository, }) => withSpinner("Creating Pull Request...", "Pull Request created successfully!", "Failed to create Pull Request.", githubService.createPullRequest({
96
96
  base: "main",
97
97
  body: "This PR contains the scaffolded monorepo structure.",
@@ -102,25 +102,29 @@ const createPullRequest = (githubService) => ({ branchName, repository, }) => wi
102
102
  }))
103
103
  // If PR creation fails, don't block the workflow
104
104
  .orElse(() => okAsync(undefined));
105
+ const handleGeneratorError = (err) => {
106
+ const logger = getLogger(["dx-cli", "init"]);
107
+ if (err instanceof Error) {
108
+ logger.error(err.message);
109
+ }
110
+ return new Error("Failed to run the generator");
111
+ };
105
112
  export const makeInitCommand = ({ gitHubService, }) => new Command()
106
113
  .name("init")
107
- .description("Command to initialize resources (like projects, subscriptions, ...)")
108
- .addCommand(new Command("project")
109
- .description("Initialize a new monorepo project")
114
+ .description("Initialize a new DX workspace")
110
115
  .action(async function () {
111
116
  await checkPreconditions()
112
- .andThen(initPlop)
113
- .andTee(setMonorepoGenerator)
114
- .andThen((plop) => getGenerator(plop)(PLOP_MONOREPO_GENERATOR_NAME))
115
- .andThen((generator) =>
116
- // Ask the user the questions defined in the plop generator
117
- getPrompts(generator)
118
- // Decode the answers to match the Answers schema
119
- .andThen(decode(answersSchema))
120
- // Validate the answers (like checking permissions, checking GitHub user or org existence, etc.)
121
- .andThen(validateAnswers(gitHubService))
122
- // Run the generator with the provided answers (this will create the files locally)
123
- .andThen(runGeneratorActions(generator)))
124
- .andThen((answers) => handleNewGitHubRepository(gitHubService)(answers).map((repoPr) => makeInitResult(answers, repoPr)))
117
+ .andTee(() => {
118
+ console.log(chalk.blue.bold("\nWorkspace Info"));
119
+ })
120
+ .andThen(() => ResultAsync.fromPromise(getPlopInstance(), () => new Error("Failed to initialize plop")))
121
+ .andThen((plop) => ResultAsync.fromPromise(runMonorepoGenerator(plop, gitHubService), handleGeneratorError)
122
+ .andTee((payload) => {
123
+ process.chdir(payload.repoName);
124
+ console.log(chalk.blue.bold("\nCloud Environment"));
125
+ })
126
+ .andThen((payload) => ResultAsync.fromPromise(runDeploymentEnvironmentGenerator(plop), handleGeneratorError).map(() => payload)))
127
+ .andTee(() => console.log()) // Print a new line before the gh repo creation logs
128
+ .andThen((payload) => handleNewGitHubRepository(gitHubService)(payload))
125
129
  .match(displaySummary, exitWithError(this));
126
- }));
130
+ });
@@ -9,7 +9,7 @@ export declare const makeMockPackageJson: (overrides?: Partial<PackageJson>) =>
9
9
  typescript: string;
10
10
  };
11
11
  name: string;
12
- scripts: Map<string & import("zod/v4").$brand<"ScriptName">, string> | {
12
+ scripts: Map<string & import("zod").$brand<"ScriptName">, string> | {
13
13
  build: string;
14
14
  "code-review": string;
15
15
  };
@@ -19,6 +19,7 @@ export declare class OctokitGitHubService implements GitHubService {
19
19
  }): Promise<PullRequest>;
20
20
  getRepository(owner: string, name: string): Promise<Repository>;
21
21
  }
22
+ export declare const getGitHubPAT: () => Promise<string | undefined>;
22
23
  export declare const fetchLatestTag: ({ client, owner, repo }: GitHubReleaseParam) => ResultAsync<import("semver").SemVer | null, Error>;
23
24
  export declare const fetchLatestRelease: ({ client, owner, repo, }: GitHubReleaseParam) => ResultAsync<import("semver").SemVer | null, Error>;
24
25
  export {};
@@ -1,3 +1,4 @@
1
+ import { $ } from "execa";
1
2
  import { ResultAsync } from "neverthrow";
2
3
  import { RequestError } from "octokit";
3
4
  import semverParse from "semver/functions/parse.js";
@@ -44,6 +45,21 @@ export class OctokitGitHubService {
44
45
  }
45
46
  }
46
47
  }
48
+ // Follow the same order of precedence of gh cli
49
+ // https://cli.github.com/manual/gh_help_environment
50
+ export const getGitHubPAT = async () => {
51
+ if (process.env.GH_TOKEN) {
52
+ return process.env.GH_TOKEN;
53
+ }
54
+ if (process.env.GITHUB_TOKEN) {
55
+ return process.env.GITHUB_TOKEN;
56
+ }
57
+ const result = await $({ reject: false }) `gh auth token`;
58
+ if (!result.failed && result.exitCode === 0) {
59
+ return result.stdout.trim();
60
+ }
61
+ return undefined;
62
+ };
47
63
  export const fetchLatestTag = ({ client, owner, repo }) => ResultAsync.fromPromise(
48
64
  // Get repository tags
49
65
  client.request("GET /repos/{owner}/{repo}/tags", {
@@ -4,11 +4,13 @@ import { formatTerraformCode } from "../../../terraform/fmt.js";
4
4
  import { payloadSchema } from "./prompts.js";
5
5
  const addModule = (env, templatesPath) => {
6
6
  const cloudAccountsByCsp = Object.groupBy(env.cloudAccounts, (account) => account.csp);
7
+ const includesProdIO = env.cloudAccounts.some((account) => account.displayName === "PROD-IO");
8
+ const cwd = process.cwd();
7
9
  return (name, terraformBackendKey) => [
8
10
  {
9
11
  base: templatesPath,
10
- data: { cloudAccountsByCsp },
11
- destination: "infra",
12
+ data: { cloudAccountsByCsp, includesProdIO },
13
+ destination: path.join(cwd, "infra"),
12
14
  force: true,
13
15
  templateFiles: path.join(templatesPath, name),
14
16
  transform: formatTerraformCode,
@@ -18,7 +20,7 @@ const addModule = (env, templatesPath) => {
18
20
  {
19
21
  base: path.join(templatesPath, "shared"),
20
22
  data: { cloudAccountsByCsp, terraformBackendKey },
21
- destination: `infra/${name}/{{env.name}}`,
23
+ destination: path.join(cwd, "infra", name, "{{env.name}}"),
22
24
  force: true,
23
25
  templateFiles: path.join(templatesPath, "shared"),
24
26
  transform: formatTerraformCode,
@@ -1,3 +1,6 @@
1
1
  import { type NodePlopAPI } from "node-plop";
2
2
  import { CloudAccountRepository, CloudAccountService } from "../../../../domain/cloud-account.js";
3
+ import { Payload, payloadSchema } from "./prompts.js";
4
+ export declare const PLOP_ENVIRONMENT_GENERATOR_NAME = "DX_DeploymentEnvironment";
5
+ export { Payload, payloadSchema };
3
6
  export default function (plop: NodePlopAPI, templatesPath: string, cloudAccountRepository: CloudAccountRepository, cloudAccountService: CloudAccountService): void;
@@ -2,16 +2,20 @@ import setGetTerraformBackend from "../../actions/get-terraform-backend.js";
2
2
  import setInitCloudAccountsAction from "../../actions/init-cloud-accounts.js";
3
3
  import setProvisionTerraformBackendAction from "../../actions/provision-terraform-backend.js";
4
4
  import setEnvShortHelper from "../../helpers/env-short.js";
5
+ import setEqHelper from "../../helpers/eq.js";
5
6
  import setResourcePrefixHelper from "../../helpers/resource-prefix.js";
6
7
  import getActions from "./actions.js";
7
- import getPrompts from "./prompts.js";
8
+ import getPrompts, { payloadSchema } from "./prompts.js";
9
+ export const PLOP_ENVIRONMENT_GENERATOR_NAME = "DX_DeploymentEnvironment";
10
+ export { payloadSchema };
8
11
  export default function (plop, templatesPath, cloudAccountRepository, cloudAccountService) {
9
12
  setEnvShortHelper(plop);
10
13
  setResourcePrefixHelper(plop);
14
+ setEqHelper(plop);
11
15
  setGetTerraformBackend(plop, cloudAccountService);
12
16
  setProvisionTerraformBackendAction(plop, cloudAccountService);
13
17
  setInitCloudAccountsAction(plop, cloudAccountService);
14
- plop.setGenerator("DX_DeploymentEnvironment", {
18
+ plop.setGenerator(PLOP_ENVIRONMENT_GENERATOR_NAME, {
15
19
  actions: getActions(templatesPath),
16
20
  description: "Generate a new deployment environment",
17
21
  prompts: getPrompts({ cloudAccountRepository, cloudAccountService }),
@@ -13,18 +13,18 @@ const validatePrompt = (schema) => (input) => {
13
13
  };
14
14
  const getPrompts = () => [
15
15
  {
16
- message: "Repository name",
16
+ message: "Name",
17
17
  name: "repoName",
18
18
  validate: validatePrompt(payloadSchema.shape.repoName),
19
19
  },
20
20
  {
21
21
  default: payloadSchema.shape.repoOwner.def.defaultValue,
22
- message: "GitHub repository owner (User or Organization)",
22
+ message: "GitHub Organization",
23
23
  name: "repoOwner",
24
24
  validate: validatePrompt(payloadSchema.shape.repoOwner),
25
25
  },
26
26
  {
27
- message: "Repository description",
27
+ message: "Description",
28
28
  name: "repoDescription",
29
29
  },
30
30
  ];
@@ -0,0 +1,3 @@
1
+ import { type NodePlopAPI } from "node-plop";
2
+ declare const _default: (plop: NodePlopAPI) => void;
3
+ export default _default;
@@ -0,0 +1,3 @@
1
+ export default (plop) => {
2
+ plop.setHelper("eq", (a, b) => a === b);
3
+ };
@@ -1,8 +1,8 @@
1
1
  import type { NodePlopAPI } from "plop";
2
- import { Result, ResultAsync } from "neverthrow";
3
- import { PlopGenerator } from "node-plop";
4
- export declare const initPlop: () => ResultAsync<NodePlopAPI, Error>;
5
- export declare const getGenerator: (plopAPI: NodePlopAPI) => (name: string) => Result<PlopGenerator, Error>;
6
- export declare const getPrompts: (generator: PlopGenerator) => ResultAsync<any, Error>;
2
+ import { GitHubService } from "../../domain/github.js";
3
+ import { Payload as MonorepoPayload } from "../plop/generators/monorepo/index.js";
7
4
  export declare const setMonorepoGenerator: (plop: NodePlopAPI) => void;
5
+ export declare const getPlopInstance: () => Promise<NodePlopAPI>;
6
+ export declare const runMonorepoGenerator: (plop: NodePlopAPI, githubService: GitHubService) => Promise<MonorepoPayload>;
7
+ export declare const runDeploymentEnvironmentGenerator: (plop: NodePlopAPI) => Promise<void>;
8
8
  export declare const setDeploymentEnvironmentGenerator: (plop: NodePlopAPI) => void;
@@ -1,22 +1,69 @@
1
- import { DefaultAzureCredential } from "@azure/identity";
2
- import { Result, ResultAsync } from "neverthrow";
1
+ import { AzureCliCredential } from "@azure/identity";
2
+ import { getLogger } from "@logtape/logtape";
3
3
  import nodePlop from "node-plop";
4
4
  import path from "node:path";
5
5
  import { Octokit } from "octokit";
6
+ import { oraPromise } from "ora";
7
+ import { RepositoryNotFoundError } from "../../domain/github.js";
6
8
  import { AzureSubscriptionRepository } from "../azure/cloud-account-repository.js";
7
9
  import { AzureCloudAccountService } from "../azure/cloud-account-service.js";
8
- import createDeploymentEnvironmentGenerator from "../plop/generators/environment/index.js";
9
- import createMonorepoGenerator from "../plop/generators/monorepo/index.js";
10
- export const initPlop = () => ResultAsync.fromPromise(nodePlop(), () => new Error("Failed to initialize plop"));
11
- export const getGenerator = (plopAPI) => Result.fromThrowable(plopAPI.getGenerator, () => new Error("Generator not found"));
12
- export const getPrompts = (generator) => ResultAsync.fromPromise(generator.runPrompts(), (cause) => new Error("Failed to run the generator prompts", { cause }));
10
+ import createDeploymentEnvironmentGenerator, { PLOP_ENVIRONMENT_GENERATOR_NAME, } from "../plop/generators/environment/index.js";
11
+ import createMonorepoGenerator, { payloadSchema as monorepoPayloadSchema, PLOP_MONOREPO_GENERATOR_NAME, } from "../plop/generators/monorepo/index.js";
13
12
  export const setMonorepoGenerator = (plop) => {
14
13
  const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
15
14
  const templatesPath = path.join(import.meta.dirname, "../../../templates/monorepo");
16
15
  createMonorepoGenerator(plop, templatesPath, octokit);
17
16
  };
17
+ const validatePayload = async (payload, github) => {
18
+ try {
19
+ const repo = await github.getRepository(payload.repoOwner, payload.repoName);
20
+ throw new Error(`Repository ${repo.fullName} already exists.`);
21
+ }
22
+ catch (error) {
23
+ if (!(error instanceof RepositoryNotFoundError)) {
24
+ throw error;
25
+ }
26
+ }
27
+ };
28
+ export const getPlopInstance = async () => {
29
+ const plop = await nodePlop();
30
+ setMonorepoGenerator(plop);
31
+ setDeploymentEnvironmentGenerator(plop);
32
+ return plop;
33
+ };
34
+ const runActions = async (generator, payload) => {
35
+ const logger = getLogger(["dx-cli", "init"]);
36
+ const result = await generator.runActions(payload);
37
+ if (result.failures.length > 0) {
38
+ for (const failure of result.failures) {
39
+ logger.error(failure.message);
40
+ }
41
+ throw new Error("One or more actions failed during generation.");
42
+ }
43
+ };
44
+ export const runMonorepoGenerator = async (plop, githubService) => {
45
+ const generator = plop.getGenerator(PLOP_MONOREPO_GENERATOR_NAME);
46
+ const answers = await generator.runPrompts();
47
+ const payload = monorepoPayloadSchema.parse(answers);
48
+ await validatePayload(payload, githubService);
49
+ await oraPromise(runActions(generator, payload), {
50
+ failText: "Failed to create workspace files.",
51
+ successText: "Workspace files created successfully!",
52
+ text: "Creating workspace files...",
53
+ });
54
+ return payload;
55
+ };
56
+ export const runDeploymentEnvironmentGenerator = async (plop) => {
57
+ const generator = plop.getGenerator(PLOP_ENVIRONMENT_GENERATOR_NAME);
58
+ const payload = await generator.runPrompts();
59
+ await oraPromise(runActions(generator, payload), {
60
+ failText: "Failed to create deployment environment",
61
+ successText: "Environment created successfully!",
62
+ text: "Creating environment...",
63
+ });
64
+ };
18
65
  export const setDeploymentEnvironmentGenerator = (plop) => {
19
- const credential = new DefaultAzureCredential();
66
+ const credential = new AzureCliCredential();
20
67
  const cloudAccountRepository = new AzureSubscriptionRepository(credential);
21
68
  const cloudAccountService = new AzureCloudAccountService(credential);
22
69
  const templatesPath = path.join(import.meta.dirname, "../../../templates/environment");
@@ -27,6 +27,7 @@ export declare class Repository {
27
27
  readonly name: string;
28
28
  readonly owner: string;
29
29
  get fullName(): string;
30
+ get origin(): string;
30
31
  get ssh(): string;
31
32
  get url(): string;
32
33
  constructor(name: string, owner: string);
@@ -10,6 +10,9 @@ export class Repository {
10
10
  get fullName() {
11
11
  return `${this.owner}/${this.name}`;
12
12
  }
13
+ get origin() {
14
+ return `https://github.com/${this.owner}/${this.name}.git`;
15
+ }
13
16
  get ssh() {
14
17
  return `git@github.com:${this.owner}/${this.name}.git`;
15
18
  }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  import "core-js/actual/set/index.js";
2
- export declare const runCli: (version: string) => void;
2
+ export declare const runCli: (version: string) => Promise<void>;
package/dist/index.js CHANGED
@@ -1,22 +1,25 @@
1
1
  import "core-js/actual/set/index.js";
2
+ import * as assert from "node:assert/strict";
2
3
  import { Octokit } from "octokit";
3
4
  import codemodRegistry from "./adapters/codemods/index.js";
4
5
  import { makeCli } from "./adapters/commander/index.js";
5
6
  import { makeValidationReporter } from "./adapters/logtape/validation-reporter.js";
6
7
  import { makePackageJsonReader } from "./adapters/node/package-json.js";
7
8
  import { makeRepositoryReader } from "./adapters/node/repository.js";
8
- import { OctokitGitHubService } from "./adapters/octokit/index.js";
9
+ import { getGitHubPAT, OctokitGitHubService, } from "./adapters/octokit/index.js";
9
10
  import { getConfig } from "./config.js";
10
11
  import { getInfo } from "./domain/info.js";
11
12
  import { applyCodemodById } from "./use-cases/apply-codemod.js";
12
13
  import { listCodemods } from "./use-cases/list-codemods.js";
13
- export const runCli = (version) => {
14
+ export const runCli = async (version) => {
14
15
  // Creating the adapters
15
16
  const repositoryReader = makeRepositoryReader();
16
17
  const packageJsonReader = makePackageJsonReader();
17
18
  const validationReporter = makeValidationReporter();
19
+ const auth = await getGitHubPAT();
20
+ assert.ok(auth, "GitHub PAT is required. Please set the GH_TOKEN environment variable or login using GitHub CLI.");
18
21
  const octokit = new Octokit({
19
- auth: process.env.GITHUB_TOKEN,
22
+ auth,
20
23
  });
21
24
  const gitHubService = new OctokitGitHubService(octokit);
22
25
  const deps = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-cli",
3
- "version": "0.15.5",
3
+ "version": "0.16.1",
4
4
  "type": "module",
5
5
  "description": "A CLI useful to manage DX tools.",
6
6
  "repository": {
@@ -11,3 +11,48 @@ data "azuread_group" "externals" {
11
11
  display_name = "{{resourcePrefix @root}}-adgroup-externals"
12
12
  }
13
13
  {{/with}}
14
+
15
+ {{#with includesProdIO}}
16
+ data "azurerm_subscription" "PROD_IO" {
17
+ provider = azurerm.PROD-IO
18
+ }
19
+
20
+ data "azurerm_resource_group" "common_itn_01" {
21
+ provider = azurerm.PROD-IO
22
+ name = "io-p-itn-common-rg-01"
23
+ }
24
+
25
+ data "azurerm_resource_group" "common_weu" {
26
+ provider = azurerm.PROD-IO
27
+ name = "io-p-rg-common"
28
+ }
29
+
30
+ data "azurerm_resource_group" "dashboards" {
31
+ provider = azurerm.PROD-IO
32
+ name = "dashboards"
33
+ }
34
+
35
+ data "azurerm_container_app_environment" "runner" {
36
+ provider = azurerm.PROD-IO
37
+ name = "io-p-itn-github-runner-cae-01"
38
+ resource_group_name = "io-p-itn-github-runner-rg-01"
39
+ }
40
+
41
+ data "azurerm_api_management" "apim" {
42
+ provider = azurerm.PROD-IO
43
+ name = "io-p-itn-apim-01"
44
+ resource_group_name = data.azurerm_resource_group.common_itn_01.name
45
+ }
46
+
47
+ data "azurerm_key_vault" "common" {
48
+ provider = azurerm.PROD-IO
49
+ name = "io-p-kv-common"
50
+ resource_group_name = data.azurerm_resource_group.common_weu.name
51
+ }
52
+
53
+ data "azurerm_virtual_network" "common" {
54
+ provider = azurerm.PROD-IO
55
+ name = "io-p-itn-common-vnet-01"
56
+ resource_group_name = data.azurerm_resource_group.common_itn_01.name
57
+ }
58
+ {{/with}}
@@ -1,5 +1,52 @@
1
- {{#with cloudAccountsByCsp.azure}}
2
- {{#each this}}
1
+ {{#each cloudAccountsByCsp.azure}}
2
+ {{#if (eq displayName "PROD-IO")}}
3
+ module "azure-{{displayName}}_bootstrap" {
4
+ source = "pagopa-dx/azure-github-environment-bootstrap/azurerm"
5
+ version = "~> 3.0"
6
+
7
+ providers = {
8
+ azurerm = azurerm.{{displayName}}
9
+ }
10
+
11
+ environment = merge(local.environment, local.azure_accounts.{{displayName}})
12
+
13
+ subscription_id = data.azurerm_subscription.PROD_IO.id
14
+ tenant_id = data.azurerm_subscription.PROD_IO.tenant_id
15
+
16
+ entraid_groups = {
17
+ admins_object_id = data.azuread_group.admins.object_id
18
+ devs_object_id = data.azuread_group.developers.object_id
19
+ externals_object_id = data.azuread_group.externals.object_id
20
+ }
21
+
22
+ terraform_storage_account = {
23
+ name = "{{@root.terraform.backend.storageAccountName}}"
24
+ resource_group_name = "{{@root.terraform.backend.resourceGroupName}}"
25
+ }
26
+
27
+ repository = {
28
+ owner = "{{@root.github.owner}}"
29
+ name = "{{@root.github.repo}}"
30
+ }
31
+
32
+ github_private_runner = {
33
+ container_app_environment_id = data.azurerm_container_app_environment.runner.id
34
+ container_app_environment_location = data.azurerm_container_app_environment.runner.location
35
+ key_vault = {
36
+ name = data.azurerm_key_vault.common.name
37
+ resource_group_name = data.azurerm_key_vault.common.resource_group_name
38
+ }
39
+ }
40
+
41
+ apim_id = data.azurerm_api_management.apim.id
42
+ pep_vnet_id = data.azurerm_virtual_network.common.id
43
+ private_dns_zone_resource_group_id = data.azurerm_resource_group.common_weu.id
44
+ nat_gateway_resource_group_id = data.azurerm_resource_group.common_itn_01.id
45
+ opex_resource_group_id = data.azurerm_resource_group.dashboards.id
46
+
47
+ tags = local.tags
48
+ }
49
+ {{else}}
3
50
  module "azure-{{displayName}}_core_values" {
4
51
  source = "pagopa-dx/azure-core-values-exporter/azurerm"
5
52
  version = "~> 0.0"
@@ -64,7 +111,7 @@ module "azure-{{displayName}}_bootstrap" {
64
111
 
65
112
  tags = local.tags
66
113
  }
114
+ {{/if}}
67
115
  {{/each}}
68
- {{/with}}
69
116
 
70
117