@vaharoni/devops 1.1.0 → 1.1.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.
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +196 -46
- package/dist/libs/init-generator.d.ts +41 -0
- package/dist/libs/init-generator.d.ts.map +1 -0
- package/dist/libs/init-generator.js +123 -0
- package/package.json +3 -1
- package/src/cli/init.ts +221 -48
- package/src/libs/init-generator.ts +165 -0
- package/src/target-templates/README.md +1 -0
- package/src/target-templates/cluster-resource-options/README.md +2 -0
- package/src/target-templates/{.devops → cluster-resource-options}/postgres/production/configurations/07-SGObjectStorage.yaml +1 -1
- package/src/target-templates/{.devops → cluster-resource-options}/postgres/production/configurations/08-SGScript.yaml +1 -1
- package/src/target-templates/{.devops → cluster-resource-options}/postgres/staging/configurations/07-SGObjectStorage.yaml +1 -1
- package/src/target-templates/{.devops → cluster-resource-options}/postgres/staging/configurations/08-SGScript.yaml +1 -1
- package/src/target-templates/infra-variants/README.md +2 -0
- package/src/target-templates/infra-variants/digitalocean/.devops/config/constants.yaml +18 -0
- package/src/target-templates/infra-variants/digitalocean/.github/workflows/k8s-build.yaml +73 -0
- package/src/target-templates/infra-variants/gcloud/.devops/config/constants.yaml +15 -0
- package/src/target-templates/infra-variants/gcloud/.devops/manifests/ingress.yaml.hb +22 -0
- package/src/target-templates/infra-variants/gcloud/.github/workflows/k8s-build.yaml +77 -0
- package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/config/constants.yaml +4 -4
- package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/infra/hetzner/abandoned/harbor-values.yaml +2 -2
- package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/infra/hetzner/abandoned/hcloud-config.yaml +1 -1
- package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/infra/hetzner/harbor-cert.yaml +2 -2
- package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/infra/hetzner/harbor-values.yaml +2 -2
- package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/infra/hetzner/hcloud-config.yaml +1 -1
- package/src/target-templates/{.github → infra-variants/hetzner/.github}/workflows/k8s-build.yaml +0 -4
- package/src/target-templates/lang-variants-common/README.md +4 -0
- package/src/target-templates/{.devops → lang-variants-common/python/.devops}/config/images.yaml +4 -4
- package/src/target-templates/{.devops → lang-variants-common/python/.devops}/manifests/prefect.yaml.hb +1 -0
- package/src/target-templates/{pyproject.toml → lang-variants-common/python/pyproject.toml} +1 -1
- package/src/target-templates/lang-variants-common/typescript/.devops/config/images.yaml +69 -0
- package/src/target-templates/lang-variants-common/typescript/.devops/manifests/_index.yaml +19 -0
- package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/manifests/cron-jobs.yaml.hb +1 -0
- package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/manifests/db-migrate-job.yaml.hb +1 -0
- package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/manifests/deployment-debug.yaml.hb +1 -0
- package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/manifests/deployment-process.yaml.hb +1 -0
- package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/manifests/deployment-web.yaml.hb +1 -0
- package/src/target-templates/lang-variants-common/typescript/.github/actions/connect-to-gke@v1/action.yaml +43 -0
- package/src/target-templates/{.github → lang-variants-common/typescript/.github}/actions/connect-to-infra@v1/action.yaml +22 -1
- package/src/target-templates/lang-variants-prisma/README.md +3 -0
- package/src/target-templates/config/.env.development +0 -1
- package/src/target-templates/config/.env.global +0 -4
- package/src/target-templates/config/.env.test +0 -1
- package/src/target-templates/libs/example-node-lib/bun.lock +0 -27
- /package/src/target-templates/{.devops/infra/test.yaml → cluster-resource-options/dns-test/dns-test.yaml} +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/milvus/production/milvus-values.yaml +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/milvus/staging/milvus-values.yaml +0 -0
- /package/src/target-templates/{.devops/infra → cluster-resource-options/monitoring-ingress}/monitoring-ingress.yaml +0 -0
- /package/src/target-templates/{.devops/postgres/DailyOperatorRestart.yaml → cluster-resource-options/postgres/daily-operator-restart.yaml} +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/postgres/production/cluster/PodDisruptionBudget.yaml +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/postgres/production/cluster/SGCluster.yaml +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/postgres/production/cluster/StackGres-alerts.yaml +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/postgres/production/configurations/06-SGDistributedLogs.yaml +0 -0
- /package/src/target-templates/{.devops/infra → cluster-resource-options/postgres}/stackgres-ui-ingress.yaml +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/postgres/staging/cluster/SGCluster.yaml +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/prefect/production/prefect-values.yaml +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/prefect/staging/prefect-values.yaml +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/redis/production/redis-values.yaml +0 -0
- /package/src/target-templates/{.devops → cluster-resource-options}/redis/staging/redis-values.yaml +0 -0
- /package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/infra/hetzner/cert-manager.yaml +0 -0
- /package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/infra/hetzner/ingress-nginx-annotations.yaml +0 -0
- /package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/infra/hetzner/ingress-nginx-configmap.yaml +0 -0
- /package/src/target-templates/{.devops → infra-variants/hetzner/.devops}/infra/hetzner/retain-storage-class.yaml +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/python/.devops}/docker-images/python-services/python-exec.sh +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/python/.devops}/docker-images/python-services/python-run.sh +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/python/.devops}/docker-images/python-services.Dockerfile +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/python/.devops}/manifests/_index.yaml +0 -0
- /package/src/target-templates/{applications → lang-variants-common/python/applications}/example-data-pipeline/pyproject.toml +0 -0
- /package/src/target-templates/{applications → lang-variants-common/python/applications}/example-data-pipeline/src/example_data_pipeline/main.py +0 -0
- /package/src/target-templates/{applications → lang-variants-common/python/applications}/example-python/pyproject.toml +0 -0
- /package/src/target-templates/{applications → lang-variants-common/python/applications}/example-python/src/example_python/__init__.py +0 -0
- /package/src/target-templates/{applications → lang-variants-common/python/applications}/example-python/src/example_python/main.py +0 -0
- /package/src/target-templates/{applications → lang-variants-common/python/applications}/example-python/src/example_python/scripts.py +0 -0
- /package/src/target-templates/{applications → lang-variants-common/python/applications}/example-python/tests/__init__.py +0 -0
- /package/src/target-templates/{devopspy → lang-variants-common/python/devopspy} +0 -0
- /package/src/target-templates/{libs → lang-variants-common/python/libs}/example-python-lib/pyproject.toml +0 -0
- /package/src/target-templates/{libs → lang-variants-common/python/libs}/example-python-lib/src/example_python_lib/__init__.py +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/docker-images/common/docker-common.sh +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/docker-images/node-services/node-exec.sh +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/docker-images/node-services/node-run.sh +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/docker-images/node-services.Dockerfile +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/env.example.yaml +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/manifests/ingress.yaml.hb +0 -0
- /package/src/target-templates/{.devops → lang-variants-common/typescript/.devops}/manifests/service.yaml.hb +0 -0
- /package/src/target-templates/{.github → lang-variants-common/typescript/.github}/actions/build-image@v1/action.yaml +0 -0
- /package/src/target-templates/{.github → lang-variants-common/typescript/.github}/actions/connect-to-digital-ocean@v1/action.yaml +0 -0
- /package/src/target-templates/{.github → lang-variants-common/typescript/.github}/actions/connect-to-hetzner@v1/action.yaml +0 -0
- /package/src/target-templates/{.github → lang-variants-common/typescript/.github}/actions/db-migrate@v1/action.yaml +0 -0
- /package/src/target-templates/{.github → lang-variants-common/typescript/.github}/actions/deploy-image@v1/action.yaml +0 -0
- /package/src/target-templates/{.github → lang-variants-common/typescript/.github}/actions/setup-prereq@v1/action.yaml +0 -0
- /package/src/target-templates/{applications → lang-variants-common/typescript/applications}/example-node/index.ts +0 -0
- /package/src/target-templates/{applications → lang-variants-common/typescript/applications}/example-node/package.json +0 -0
- /package/src/target-templates/{applications → lang-variants-common/typescript/applications}/example-node/tsconfig.json +0 -0
- /package/src/target-templates/{applications → lang-variants-common/typescript/applications}/jobs/README.md +0 -0
- /package/src/target-templates/{applications → lang-variants-common/typescript/applications}/jobs/index.ts +0 -0
- /package/src/target-templates/{applications → lang-variants-common/typescript/applications}/jobs/package.json +0 -0
- /package/src/target-templates/{applications → lang-variants-common/typescript/applications}/jobs/tsconfig.json +0 -0
- /package/src/target-templates/{devops → lang-variants-common/typescript/devops} +0 -0
- /package/src/target-templates/{libs → lang-variants-common/typescript/libs}/example-node-lib/index.ts +0 -0
- /package/src/target-templates/{libs → lang-variants-common/typescript/libs}/example-node-lib/package.json +0 -0
- /package/src/target-templates/{libs → lang-variants-common/typescript/libs}/example-node-lib/tsconfig.json +0 -0
- /package/src/target-templates/{tmp → lang-variants-common/typescript/tmp}/.gitkeep +0 -0
- /package/src/target-templates/{tsconfig.json → lang-variants-common/typescript/tsconfig.json} +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/python/db}/db/__init__.py +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/python/db}/db/db_client_test.py +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/python/db}/pyproject.toml +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/typescript/db}/db-client-test.ts +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/typescript/db}/db-client.ts +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/typescript/db}/env.yaml +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/typescript/db}/package.json +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/typescript/db}/prisma/schema.prisma +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/typescript/db}/prisma-setup-vitest.ts +0 -0
- /package/src/target-templates/{db → lang-variants-prisma/typescript/db}/tsconfig.json +0 -0
- /package/src/target-templates/{dml → lang-variants-prisma/typescript/dml}/package.json +0 -0
- /package/src/target-templates/{dml → lang-variants-prisma/typescript/dml}/tsconfig.json +0 -0
package/dist/cli/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAC;AAmB/D,iBAAe,GAAG,CAAC,MAAM,EAAE,gBAAgB,iBAG1C;;;;;;;;AAED,wBAEE"}
|
package/dist/cli/init.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import fs from "fs-extra";
|
|
4
|
-
const __file__ = url.fileURLToPath(import.meta.url);
|
|
5
|
-
const __root__ = path.join(path.dirname(__file__), "../..");
|
|
6
|
-
const templatesDir = path.join(__root__, "src/target-templates");
|
|
7
|
-
const targetDir = process.cwd(); // User's current working directory
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import { InitGenerator } from "../libs/init-generator";
|
|
8
3
|
import { CLICommandParser, printUsageAndExit } from "./common";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import fs from 'fs-extra';
|
|
9
6
|
const oneLiner = "Initializes the devops utility by copying template files to the current folder";
|
|
10
7
|
const keyExamples = `$ devops init`;
|
|
11
8
|
const usage = `
|
|
@@ -20,52 +17,205 @@ EXAMPLES
|
|
|
20
17
|
async function run(cmdObj) {
|
|
21
18
|
if (cmdObj.help)
|
|
22
19
|
printUsageAndExit(usage);
|
|
23
|
-
|
|
20
|
+
createFiles();
|
|
24
21
|
}
|
|
25
22
|
export default {
|
|
26
23
|
init: { oneLiner, keyExamples, run },
|
|
27
24
|
};
|
|
28
|
-
async function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
37
|
-
console.log(successMessage);
|
|
25
|
+
async function createFiles() {
|
|
26
|
+
const tc = new InitGenerator();
|
|
27
|
+
const userChoices = await getUserChoices(tc.projectName);
|
|
28
|
+
// Language variants
|
|
29
|
+
tc.addCopiedFolder("lang-variants-common/typescript", ".");
|
|
30
|
+
if (userChoices.usePython) {
|
|
31
|
+
tc.addCopiedFolder("lang-variants-common/python", ".");
|
|
32
|
+
tc.enableSubtitution("pyproject.toml");
|
|
38
33
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
tc.enableSubtitution(".devops/config/images.yaml");
|
|
35
|
+
tc.setMessageGenerator(".envrc", envrcMessage);
|
|
36
|
+
// gitignore
|
|
37
|
+
const gitIgnore = gitIgnoreContent(userChoices.infraVariant, userChoices.usePython);
|
|
38
|
+
tc.addGeneratedFile(".gitignore", gitIgnore);
|
|
39
|
+
tc.setMessageGenerator(".gitignore", gitignoreMessageGen(gitIgnore));
|
|
40
|
+
// Infra variants
|
|
41
|
+
tc.addCopiedFolder(`infra-variants/${userChoices.infraVariant}`, ".");
|
|
42
|
+
tc.enableSubtitution(".devops/config/constants.yaml");
|
|
43
|
+
if (userChoices.infraVariant === "hetzner") {
|
|
44
|
+
tc.enableSubtitution(".devops/infra/hetzner/harbor-cert.yaml");
|
|
45
|
+
tc.enableSubtitution(".devops/infra/hetzner/harbor-values.yaml");
|
|
46
|
+
tc.enableSubtitution(".devops/infra/hetzner/hcloud-config.yaml");
|
|
42
47
|
}
|
|
48
|
+
// Prisma
|
|
49
|
+
if (userChoices.usePrisma) {
|
|
50
|
+
tc.addCopiedFolder("lang-variants-prisma/typescript", ".");
|
|
51
|
+
if (userChoices.usePython) {
|
|
52
|
+
tc.addCopiedFolder("lang-variants-prisma/python", ".");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Cluster resources
|
|
56
|
+
const clusterResources = new Set(userChoices.clusterResources);
|
|
57
|
+
if (clusterResources.has("dns-test")) {
|
|
58
|
+
tc.addCopiedFolder("cluster-resource-options/dns-test", ".devops/infra/dns-test");
|
|
59
|
+
}
|
|
60
|
+
if (clusterResources.has("monitoring-ingress")) {
|
|
61
|
+
tc.addCopiedFolder("cluster-resource-options/monitoring-ingress", ".devops/infra/monitoring-ingress");
|
|
62
|
+
}
|
|
63
|
+
if (clusterResources.has("postgres")) {
|
|
64
|
+
tc.addCopiedFolder("cluster-resource-options/postgres", ".devops/infra/postgres");
|
|
65
|
+
// prettier-ignore
|
|
66
|
+
tc.enableSubtitution(".devops/infra/postgres/staging/configurations/07-SGObjectStorage.yaml");
|
|
67
|
+
// prettier-ignore
|
|
68
|
+
tc.enableSubtitution(".devops/infra/postgres/staging/configurations/08-SGScript.yaml");
|
|
69
|
+
// prettier-ignore
|
|
70
|
+
tc.enableSubtitution(".devops/infra/postgres/production/configurations/07-SGObjectStorage.yaml");
|
|
71
|
+
// prettier-ignore
|
|
72
|
+
tc.enableSubtitution(".devops/infra/postgres/production/configurations/08-SGScript.yaml");
|
|
73
|
+
}
|
|
74
|
+
if (clusterResources.has("redis")) {
|
|
75
|
+
tc.addCopiedFolder("cluster-resource-options/redis", ".devops/infra/redis");
|
|
76
|
+
}
|
|
77
|
+
if (clusterResources.has("milvus")) {
|
|
78
|
+
tc.addCopiedFolder("cluster-resource-options/milvus", ".devops/infra/milvus");
|
|
79
|
+
}
|
|
80
|
+
if (clusterResources.has("prefect") && userChoices.usePython) {
|
|
81
|
+
tc.addCopiedFolder("cluster-resource-options/prefect", ".devops/infra/prefect");
|
|
82
|
+
}
|
|
83
|
+
tc.run({
|
|
84
|
+
substitution: {
|
|
85
|
+
'PROJECT_NAME': userChoices.projectName,
|
|
86
|
+
'STAGING_DOMAIN': userChoices.stagingDomain,
|
|
87
|
+
'PRODUCTION_DOMAIN': userChoices.productionDomain,
|
|
88
|
+
'GCLOUD_PROJECT_ID': userChoices.gcloudProjectId,
|
|
89
|
+
'REGISTRY_IMAGE_PATH_PREFIX': userChoices.registryImagePathPrefix,
|
|
90
|
+
'REGISTRY_BASE_URL': userChoices.registryBaseUrl,
|
|
91
|
+
},
|
|
92
|
+
messages: [
|
|
93
|
+
packageJsonMessage(userChoices.usePrisma)
|
|
94
|
+
]
|
|
95
|
+
});
|
|
43
96
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
To finish the setup:
|
|
48
|
-
|
|
49
|
-
1. add the following entry to the main package.json:
|
|
50
|
-
"workspaces": [
|
|
51
|
-
"libs/**",
|
|
52
|
-
"applications/**",
|
|
97
|
+
function packageJsonMessage(usePrisma) {
|
|
98
|
+
const prismaMessage = usePrisma
|
|
99
|
+
? `,
|
|
53
100
|
"db/**",
|
|
54
|
-
"dml/**"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
101
|
+
"dml/**"`
|
|
102
|
+
: "";
|
|
103
|
+
return `add the following entry to the main ${chalk.blue("package.json")}:
|
|
104
|
+
${chalk.yellow(`"workspaces": [
|
|
105
|
+
"libs/**",
|
|
106
|
+
"applications/**"${prismaMessage}
|
|
107
|
+
],`)}`;
|
|
108
|
+
}
|
|
109
|
+
function gitIgnoreContent(infraVariant, usePython) {
|
|
110
|
+
const common = `**/.env*
|
|
59
111
|
config/kubeconfig
|
|
60
112
|
tmp/**
|
|
61
|
-
!tmp/**/.gitkeep
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
113
|
+
!tmp/**/.gitkeep`;
|
|
114
|
+
const gcloud = infraVariant === 'gcloud'
|
|
115
|
+
? 'config/gke_gcloud_auth_plugin_cache'
|
|
116
|
+
: null;
|
|
117
|
+
const python = usePython
|
|
118
|
+
? `venv/
|
|
119
|
+
**/__pycache__`
|
|
120
|
+
: null;
|
|
121
|
+
return [common, gcloud, python].filter(Boolean).join('\n');
|
|
122
|
+
}
|
|
123
|
+
function gitignoreMessageGen(content) {
|
|
124
|
+
return (exists) => {
|
|
125
|
+
if (!exists)
|
|
126
|
+
return;
|
|
127
|
+
return `add the following to your ${chalk.blue(".gitignore")}:
|
|
128
|
+
${chalk.yellow(content)}`;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function envrcMessage(targetExists, fileInfo) {
|
|
132
|
+
if (fileInfo.type !== 'copied')
|
|
133
|
+
throw new Error(`envrcMessage() expects a copied file, got ${fileInfo.type}`);
|
|
134
|
+
if (targetExists) {
|
|
135
|
+
const content = fs.readFileSync(fileInfo.sourceAbs, 'utf-8');
|
|
136
|
+
return `add the following to your ${chalk.blue(".envrc")} and run ${chalk.yellow("direnv allow")}:
|
|
137
|
+
${chalk.yellow(content)}`;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
return `Enable ${chalk.blue(".envrc")} by installing ${chalk.blue('direnv')} and running ${chalk.yellow("direnv allow")}`;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function getUserChoices(projectName) {
|
|
144
|
+
const defaultProjectName = projectName || "changeme";
|
|
145
|
+
return inquirer.prompt([
|
|
146
|
+
{
|
|
147
|
+
type: "input",
|
|
148
|
+
name: "projectName",
|
|
149
|
+
message: `Enter the project name (default: '${defaultProjectName}')`,
|
|
150
|
+
default: defaultProjectName,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
type: "input",
|
|
154
|
+
name: "stagingDomain",
|
|
155
|
+
message: "Enter the staging domain (default: 'staging.com')",
|
|
156
|
+
default: "staging.com",
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
type: "input",
|
|
160
|
+
name: "productionDomain",
|
|
161
|
+
message: "Enter the production domain (default: 'production.com')",
|
|
162
|
+
default: "production.com",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
type: "list",
|
|
166
|
+
name: "infraVariant",
|
|
167
|
+
message: "Where does your cluster run?",
|
|
168
|
+
choices: [
|
|
169
|
+
{ name: "Google Cloud", value: "gcloud" },
|
|
170
|
+
{ name: "Digital Ocean", value: "digitalocean" },
|
|
171
|
+
{ name: "Hetzner", value: "hetzner" },
|
|
172
|
+
],
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
type: "input",
|
|
176
|
+
name: "gcloudProjectId",
|
|
177
|
+
message: "Enter the GCP project ID (default: 'changeme')",
|
|
178
|
+
default: "changeme",
|
|
179
|
+
when: (answers) => answers.infraVariant === "gcloud",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
type: "input",
|
|
183
|
+
name: "registryImagePathPrefix",
|
|
184
|
+
message: (answers) => `Enter your Digital Ocean container registry name (default: '${answers.projectName}')`,
|
|
185
|
+
default: (answers) => answers.projectName,
|
|
186
|
+
when: (answers) => answers.infraVariant === "digitalocean",
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
type: "input",
|
|
190
|
+
name: "registryBaseUrl",
|
|
191
|
+
message: (answers) => `Enter your registry base URL (default: 'registry.${answers.stagingDomain}')`,
|
|
192
|
+
default: (answers) => `registry.${answers.stagingDomain}`,
|
|
193
|
+
when: (answers) => answers.infraVariant === "hetzner",
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
type: "confirm",
|
|
197
|
+
name: "usePython",
|
|
198
|
+
message: "Add support for Python?",
|
|
199
|
+
default: true,
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
type: "confirm",
|
|
203
|
+
name: "usePrisma",
|
|
204
|
+
message: "Add support for Prisma?",
|
|
205
|
+
default: true,
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
type: "checkbox",
|
|
209
|
+
name: "clusterResources",
|
|
210
|
+
message: "Optional manifests and helm charts to add",
|
|
211
|
+
choices: (answers) => [
|
|
212
|
+
{ name: "Manifest to test DNS setup", value: "dns-test" },
|
|
213
|
+
{ name: "Manifest to setup ingress for graphana and prometheus", value: "monitoring-ingress" },
|
|
214
|
+
{ name: "Stackgres CRDs and manifests for Postgres", value: "postgres" },
|
|
215
|
+
{ name: "Redis Helm chart values", value: "redis" },
|
|
216
|
+
{ name: "Milvus helm chart values", value: "milvus" },
|
|
217
|
+
...(answers.usePython ? [{ name: "Prefect Helm chart values", value: "prefect" }] : [])
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
]);
|
|
221
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
type MessageGeneratorFn = (targetExists: boolean, fileInfo: InitGeneratorFileInfo) => string | null | undefined;
|
|
2
|
+
type CommonFileInfo = {
|
|
3
|
+
targetRel: string;
|
|
4
|
+
targetAbs: string;
|
|
5
|
+
targetFolderAbs: string;
|
|
6
|
+
targetExists: boolean;
|
|
7
|
+
messageGenerator?: MessageGeneratorFn;
|
|
8
|
+
};
|
|
9
|
+
export type InitGeneratorCopiedFileInfo = CommonFileInfo & {
|
|
10
|
+
type: "copied";
|
|
11
|
+
sourceRel: string;
|
|
12
|
+
sourceAbs: string;
|
|
13
|
+
enableSubstitution?: boolean;
|
|
14
|
+
};
|
|
15
|
+
type InitGeneratorGeneratedFileInfo = CommonFileInfo & {
|
|
16
|
+
type: "generated";
|
|
17
|
+
content: string;
|
|
18
|
+
};
|
|
19
|
+
export type InitGeneratorFileInfo = InitGeneratorCopiedFileInfo | InitGeneratorGeneratedFileInfo;
|
|
20
|
+
export declare class InitGenerator {
|
|
21
|
+
projectName?: string;
|
|
22
|
+
/** The key is targetRel */
|
|
23
|
+
files: Record<string, InitGeneratorFileInfo>;
|
|
24
|
+
constructor();
|
|
25
|
+
_ensureFileExists(targetRel: string): void;
|
|
26
|
+
enableSubtitution(targetRel: string): void;
|
|
27
|
+
setMessageGenerator(targetRel: string, messageGen: MessageGeneratorFn): void;
|
|
28
|
+
addGeneratedFile(targetRel: string, content: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* @param source relative path under the templates folder. All files and folders under `source` are copied directly under `target`.
|
|
31
|
+
* @param target relative path under the project root folder.
|
|
32
|
+
* If the target file exists already in `files`, it will be overridden.
|
|
33
|
+
*/
|
|
34
|
+
addCopiedFolder(source: string, target: string): void;
|
|
35
|
+
run({ substitution, messages, }: {
|
|
36
|
+
substitution?: Record<string, string | undefined>;
|
|
37
|
+
messages?: string[];
|
|
38
|
+
}): void;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=init-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-generator.d.ts","sourceRoot":"","sources":["../../src/libs/init-generator.ts"],"names":[],"mappings":"AAWA,KAAK,kBAAkB,GAAG,CAAC,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,qBAAqB,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAEhH,KAAK,cAAc,GAAG;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;CACvC,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG,cAAc,GAAE;IACxD,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAA;AAED,KAAK,8BAA8B,GAAG,cAAc,GAAG;IACrD,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,2BAA2B,GAAG,8BAA8B,CAAC;AAEjG,qBAAa,aAAa;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAM;;IASlD,iBAAiB,CAAC,SAAS,EAAE,MAAM;IAMnC,iBAAiB,CAAC,SAAS,EAAE,MAAM;IAQnC,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB;IAKrE,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAcnD;;;;OAIG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAsB9C,GAAG,CAAC,EACF,YAAiB,EACjB,QAAa,GACd,EAAG;QACF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;QAClD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB;CAkDF"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import url from "url";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import fg from 'fast-glob';
|
|
6
|
+
const __file__ = url.fileURLToPath(import.meta.url);
|
|
7
|
+
const __root__ = path.join(path.dirname(__file__), "../..");
|
|
8
|
+
const templatesDir = path.join(__root__, "src/target-templates");
|
|
9
|
+
const targetDir = process.cwd(); // User's current working directory
|
|
10
|
+
export class InitGenerator {
|
|
11
|
+
projectName;
|
|
12
|
+
/** The key is targetRel */
|
|
13
|
+
files = {};
|
|
14
|
+
constructor() {
|
|
15
|
+
if (fs.existsSync("package.json")) {
|
|
16
|
+
const packageJson = fs.readJSONSync("package.json");
|
|
17
|
+
this.projectName = packageJson.name;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
_ensureFileExists(targetRel) {
|
|
21
|
+
if (!this.files[targetRel]) {
|
|
22
|
+
throw new Error(`File for target "${targetRel}" not found.`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
enableSubtitution(targetRel) {
|
|
26
|
+
this._ensureFileExists(targetRel);
|
|
27
|
+
if (this.files[targetRel].type !== "copied") {
|
|
28
|
+
throw new Error(`File for target "${targetRel}" is not a copied file.`);
|
|
29
|
+
}
|
|
30
|
+
this.files[targetRel].enableSubstitution = true;
|
|
31
|
+
}
|
|
32
|
+
setMessageGenerator(targetRel, messageGen) {
|
|
33
|
+
this._ensureFileExists(targetRel);
|
|
34
|
+
this.files[targetRel].messageGenerator = messageGen;
|
|
35
|
+
}
|
|
36
|
+
addGeneratedFile(targetRel, content) {
|
|
37
|
+
const targetAbs = path.join(targetDir, targetRel);
|
|
38
|
+
const targetFolderAbs = path.dirname(targetAbs);
|
|
39
|
+
const exists = fs.existsSync(targetAbs);
|
|
40
|
+
this.files[targetRel] = {
|
|
41
|
+
type: "generated",
|
|
42
|
+
targetRel,
|
|
43
|
+
targetAbs,
|
|
44
|
+
targetFolderAbs,
|
|
45
|
+
targetExists: exists,
|
|
46
|
+
content,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* @param source relative path under the templates folder. All files and folders under `source` are copied directly under `target`.
|
|
51
|
+
* @param target relative path under the project root folder.
|
|
52
|
+
* If the target file exists already in `files`, it will be overridden.
|
|
53
|
+
*/
|
|
54
|
+
addCopiedFolder(source, target) {
|
|
55
|
+
const pathPrefix = path.join(templatesDir, source);
|
|
56
|
+
const glob = path.join(pathPrefix, '**/*');
|
|
57
|
+
fg.globSync(glob, { dot: true }).forEach((sourceAbs) => {
|
|
58
|
+
const sourceRel = path.relative(templatesDir, sourceAbs);
|
|
59
|
+
const pathUnderSource = path.relative(pathPrefix, sourceAbs);
|
|
60
|
+
const targetRel = path.join(target, pathUnderSource);
|
|
61
|
+
const targetAbs = path.join(targetDir, targetRel);
|
|
62
|
+
const targetFolderAbs = path.dirname(targetAbs);
|
|
63
|
+
const exists = fs.existsSync(targetAbs);
|
|
64
|
+
this.files[targetRel] = {
|
|
65
|
+
type: "copied",
|
|
66
|
+
sourceRel,
|
|
67
|
+
targetRel,
|
|
68
|
+
sourceAbs,
|
|
69
|
+
targetAbs,
|
|
70
|
+
targetFolderAbs,
|
|
71
|
+
targetExists: exists,
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
run({ substitution = {}, messages = [], }) {
|
|
76
|
+
const fileMessages = [];
|
|
77
|
+
Object.values(this.files).forEach((fileInfo) => {
|
|
78
|
+
if (fileInfo.messageGenerator) {
|
|
79
|
+
const message = fileInfo.messageGenerator(fileInfo.targetExists, fileInfo);
|
|
80
|
+
if (message) {
|
|
81
|
+
fileMessages.push(message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (fileInfo.targetExists) {
|
|
85
|
+
console.log(`Skipped ${chalk.yellow(fileInfo.targetRel)} (exists)`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// Create or copy
|
|
89
|
+
if (!fs.existsSync(fileInfo.targetFolderAbs)) {
|
|
90
|
+
fs.mkdirSync(fileInfo.targetFolderAbs, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
if (fileInfo.type === 'generated') {
|
|
93
|
+
fs.writeFileSync(fileInfo.targetAbs, fileInfo.content, 'utf8');
|
|
94
|
+
}
|
|
95
|
+
else if (fileInfo.enableSubstitution) {
|
|
96
|
+
const content = fs.readFileSync(fileInfo.sourceAbs, 'utf8');
|
|
97
|
+
const substitutedContent = content.replace(/\$([A-Z_]+)/g, (_, varName) => {
|
|
98
|
+
const value = substitution[varName];
|
|
99
|
+
if (!value) {
|
|
100
|
+
throw new Error(`${chalk.blue("TemplateCopier.run()")}: Variable ${chalk.yellow(varName)} is needed by ${chalk.yellow(fileInfo.targetRel)} but is undefined.`);
|
|
101
|
+
}
|
|
102
|
+
return value;
|
|
103
|
+
});
|
|
104
|
+
fs.writeFileSync(fileInfo.targetAbs, substitutedContent);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
fs.copySync(fileInfo.sourceAbs, fileInfo.targetAbs, {
|
|
108
|
+
overwrite: false,
|
|
109
|
+
errorOnExist: false,
|
|
110
|
+
dereference: false,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
console.log(`Created ${chalk.green(fileInfo.targetRel)}`);
|
|
114
|
+
});
|
|
115
|
+
const allMessages = [...messages, ...fileMessages];
|
|
116
|
+
if (!allMessages.length)
|
|
117
|
+
return;
|
|
118
|
+
console.log(chalk.blue("\nNext steps:"));
|
|
119
|
+
allMessages.forEach((msg, i) => {
|
|
120
|
+
console.log(`${i + 1}. ${msg}\n`);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaharoni/devops",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.2",
|
|
5
5
|
"description": "Devops utility",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -34,9 +34,11 @@
|
|
|
34
34
|
"@iarna/toml": "^2.2.5",
|
|
35
35
|
"chalk": "^5.3.0",
|
|
36
36
|
"concurrently": "^9.1.2",
|
|
37
|
+
"fast-glob": "^3.3.3",
|
|
37
38
|
"fs-extra": "11.2.0",
|
|
38
39
|
"glob": "^11.0.1",
|
|
39
40
|
"handlebars": "^4.7.8",
|
|
41
|
+
"inquirer": "^12.7.0",
|
|
40
42
|
"lodash": "^4.17.21",
|
|
41
43
|
"tsx": "^4.19.3",
|
|
42
44
|
"yaml": "^2.4.2",
|