@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 +1 -1
- package/dist/adapters/commander/commands/init.js +57 -53
- package/dist/adapters/node/__tests__/data.d.ts +1 -1
- package/dist/adapters/octokit/index.d.ts +1 -0
- package/dist/adapters/octokit/index.js +16 -0
- package/dist/adapters/plop/generators/environment/actions.js +5 -3
- package/dist/adapters/plop/generators/environment/index.d.ts +3 -0
- package/dist/adapters/plop/generators/environment/index.js +6 -2
- package/dist/adapters/plop/generators/monorepo/prompts.js +3 -3
- package/dist/adapters/plop/helpers/eq.d.ts +3 -0
- package/dist/adapters/plop/helpers/eq.js +3 -0
- package/dist/adapters/plop/index.d.ts +5 -5
- package/dist/adapters/plop/index.js +55 -8
- package/dist/domain/github.d.ts +1 -0
- package/dist/domain/github.js +3 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -3
- package/package.json +1 -1
- package/templates/environment/bootstrapper/{{env.name}}/data.tf.hbs +45 -0
- package/templates/environment/bootstrapper/{{env.name}}/main.tf.hbs +50 -3
package/bin/index.js
CHANGED
|
@@ -1,36 +1,20 @@
|
|
|
1
|
+
import { getLogger } from "@logtape/logtape";
|
|
1
2
|
import chalk from "chalk";
|
|
2
3
|
import { Command } from "commander";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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 {
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { Repository, } from "../../../domain/github.js";
|
|
8
10
|
import { tf$ } from "../../execa/terraform.js";
|
|
9
|
-
import {
|
|
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 = (
|
|
55
|
-
const
|
|
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
|
|
54
|
+
const logger = getLogger(["dx-cli", "init"]);
|
|
55
|
+
const repo$ = tf$({ cwd: path.resolve("infra", "repository") });
|
|
58
56
|
const applyTerraform = async () => {
|
|
59
|
-
|
|
60
|
-
|
|
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.
|
|
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) => (
|
|
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("
|
|
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
|
-
.
|
|
113
|
-
.
|
|
114
|
-
|
|
115
|
-
.andThen((
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
.
|
|
120
|
-
|
|
121
|
-
.andThen(
|
|
122
|
-
|
|
123
|
-
.andThen(
|
|
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
|
|
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:
|
|
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(
|
|
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: "
|
|
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
|
|
22
|
+
message: "GitHub Organization",
|
|
23
23
|
name: "repoOwner",
|
|
24
24
|
validate: validatePrompt(payloadSchema.shape.repoOwner),
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
message: "
|
|
27
|
+
message: "Description",
|
|
28
28
|
name: "repoDescription",
|
|
29
29
|
},
|
|
30
30
|
];
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { NodePlopAPI } from "plop";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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 {
|
|
2
|
-
import {
|
|
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
|
|
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");
|
package/dist/domain/github.d.ts
CHANGED
package/dist/domain/github.js
CHANGED
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
|
|
22
|
+
auth,
|
|
20
23
|
});
|
|
21
24
|
const gitHubService = new OctokitGitHubService(octokit);
|
|
22
25
|
const deps = {
|
package/package.json
CHANGED
|
@@ -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
|
-
{{#
|
|
2
|
-
{{#
|
|
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
|
|