polyci 0.0.1 → 0.0.3
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/main.js +145 -119
- package/package.json +8 -3
package/dist/main.js
CHANGED
|
@@ -1,29 +1,25 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import { execSync } from "node:child_process";
|
|
3
2
|
import * as fs from "node:fs";
|
|
4
3
|
import * as path from "node:path";
|
|
5
4
|
import pino from "pino";
|
|
6
5
|
import pretty from "pino-pretty";
|
|
7
6
|
const log = pino(pretty());
|
|
8
|
-
|
|
9
|
-
return execSync(command, {
|
|
10
|
-
encoding: "utf8",
|
|
11
|
-
cwd: cwd ?? process.cwd(),
|
|
12
|
-
}).trim();
|
|
13
|
-
}
|
|
14
|
-
const BRANCH_RULE = "/^(main)|(develop)|(release(-[a-z0-9]+)*)|(feature(-[a-z0-9]+)*)|(patch(-[a-z0-9]+)*)$/";
|
|
15
|
-
const IGNORED_DIRS = new Set(["node_modules", ".git", "dist"]);
|
|
7
|
+
const DEFAULT_BRANCH_RULE = "/^(main)|(develop)|(release(-[a-z0-9]+)*)|(feature(-[a-z0-9]+)*)|(patch(-[a-z0-9]+)*)$/";
|
|
16
8
|
function parseArgs() {
|
|
17
9
|
const program = new Command();
|
|
18
10
|
program
|
|
19
11
|
.argument("[output]", "Output pipeline file path (or use --output)")
|
|
20
12
|
.option("-o, --output <path>", "Output pipeline file path")
|
|
13
|
+
.option("--modules-root <path>", "Modules root directory", "./modules")
|
|
14
|
+
.option("--branch-rule <regex>", "Branch rule regex for module jobs", DEFAULT_BRANCH_RULE)
|
|
21
15
|
.option("--cwd <path>", "Working directory", process.cwd())
|
|
22
16
|
.parse();
|
|
23
17
|
const options = program.opts();
|
|
24
18
|
const output = options.output ?? program.args[0] ?? "";
|
|
25
19
|
const cwd = path.resolve(options.cwd);
|
|
26
|
-
|
|
20
|
+
const modulesRoot = path.resolve(cwd, options.modulesRoot);
|
|
21
|
+
const branchRule = options.branchRule;
|
|
22
|
+
return { cwd, output, modulesRoot, branchRule };
|
|
27
23
|
}
|
|
28
24
|
function toPosixPath(p) {
|
|
29
25
|
return p.split(path.sep).join("/");
|
|
@@ -36,6 +32,10 @@ function toJobId(value) {
|
|
|
36
32
|
.toLowerCase();
|
|
37
33
|
}
|
|
38
34
|
function detectModuleType(directory) {
|
|
35
|
+
const baseName = path.basename(directory);
|
|
36
|
+
if (baseName === "node_modules" || baseName === ".git" || baseName === "dist") {
|
|
37
|
+
return "ignored";
|
|
38
|
+
}
|
|
39
39
|
const packageJson = path.join(directory, "package.json");
|
|
40
40
|
const viteConfig = path.join(directory, "vite.config.ts");
|
|
41
41
|
if (fs.existsSync(packageJson) && fs.existsSync(viteConfig)) {
|
|
@@ -56,11 +56,15 @@ function detectModuleType(directory) {
|
|
|
56
56
|
}
|
|
57
57
|
return null;
|
|
58
58
|
}
|
|
59
|
-
function discoverModulesRecursively(
|
|
59
|
+
function discoverModulesRecursively(repoRoot, modulesRoot, scanDir, modules) {
|
|
60
60
|
const moduleType = detectModuleType(scanDir);
|
|
61
61
|
if (moduleType !== null) {
|
|
62
|
+
if (moduleType === "ignored") {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
62
65
|
const relativeModulePath = toPosixPath(path.relative(repoRoot, scanDir));
|
|
63
|
-
const
|
|
66
|
+
const relativeNamePath = toPosixPath(path.relative(modulesRoot, scanDir));
|
|
67
|
+
const moduleName = relativeNamePath.split("/").join("-");
|
|
64
68
|
modules.push({
|
|
65
69
|
moduleName,
|
|
66
70
|
modulePath: relativeModulePath,
|
|
@@ -73,30 +77,27 @@ function discoverModulesRecursively(scanDir, repoRoot, modules) {
|
|
|
73
77
|
for (const entry of entries) {
|
|
74
78
|
if (!entry.isDirectory())
|
|
75
79
|
continue;
|
|
76
|
-
|
|
77
|
-
continue;
|
|
78
|
-
discoverModulesRecursively(path.join(scanDir, entry.name), repoRoot, modules);
|
|
80
|
+
discoverModulesRecursively(repoRoot, modulesRoot, path.join(scanDir, entry.name), modules);
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
|
-
function discoverModules(repoRoot) {
|
|
82
|
-
const modulesRoot = path.join(repoRoot, "modules");
|
|
83
|
+
function discoverModules(repoRoot, modulesRoot) {
|
|
83
84
|
if (!fs.existsSync(modulesRoot) || !fs.statSync(modulesRoot).isDirectory()) {
|
|
84
85
|
return [];
|
|
85
86
|
}
|
|
86
87
|
const modules = [];
|
|
87
|
-
discoverModulesRecursively(modulesRoot,
|
|
88
|
-
modules.sort((a, b) => a.modulePath.localeCompare(b.modulePath));
|
|
88
|
+
discoverModulesRecursively(repoRoot, modulesRoot, modulesRoot, modules);
|
|
89
|
+
modules.sort((a, b) => a.modulePath.localeCompare(b.modulePath)); //TODO: Sort by dependency order or earliest modified module first
|
|
89
90
|
return modules;
|
|
90
91
|
}
|
|
91
92
|
function appendGlobalVariables(lines) {
|
|
92
93
|
lines.push("variables:");
|
|
93
|
-
lines.push(" IMAGE_LINUX: alpine:latest
|
|
94
|
-
lines.push(" IMAGE_NODE: node:alpine
|
|
94
|
+
lines.push(" IMAGE_LINUX: alpine:latest");
|
|
95
|
+
lines.push(" IMAGE_NODE: node:alpine");
|
|
95
96
|
lines.push(" IMAGE_GIT: alpine/git:latest");
|
|
96
|
-
lines.push(" IMAGE_NGINX: nginx:alpine-slim
|
|
97
|
-
lines.push(" IMAGE_DOCKER: docker:latest
|
|
97
|
+
lines.push(" IMAGE_NGINX: nginx:alpine-slim");
|
|
98
|
+
lines.push(" IMAGE_DOCKER: docker:latest");
|
|
98
99
|
lines.push(" IMAGE_COMPOSE: docker:cli");
|
|
99
|
-
lines.push(" GIT_PACKAGE: git
|
|
100
|
+
lines.push(" GIT_PACKAGE: git");
|
|
100
101
|
lines.push("");
|
|
101
102
|
lines.push("stages:");
|
|
102
103
|
lines.push(" - build");
|
|
@@ -106,18 +107,12 @@ function appendGlobalVariables(lines) {
|
|
|
106
107
|
lines.push(" - deploy");
|
|
107
108
|
lines.push("");
|
|
108
109
|
}
|
|
109
|
-
function
|
|
110
|
-
lines.push(" rules:");
|
|
111
|
-
lines.push(" - if: $CI_COMMIT_MESSAGE =~ /^release:/");
|
|
112
|
-
lines.push(" when: never");
|
|
113
|
-
lines.push(` - if: $CI_COMMIT_BRANCH =~ ${BRANCH_RULE}`);
|
|
114
|
-
lines.push(" changes:");
|
|
115
|
-
lines.push(` - ${modulePath}/**/*`);
|
|
116
|
-
}
|
|
117
|
-
function appendModuleBuildJob(lines, module) {
|
|
110
|
+
function appendModuleBuildJob(lines, module, branchRule) {
|
|
118
111
|
lines.push(`${module.jobId}_build:`);
|
|
119
112
|
lines.push(" stage: build");
|
|
120
|
-
|
|
113
|
+
lines.push(" rules:");
|
|
114
|
+
lines.push(" changes:");
|
|
115
|
+
lines.push(` - ${module.modulePath}/**/*`);
|
|
121
116
|
lines.push(" image: $IMAGE_NODE");
|
|
122
117
|
lines.push(" variables:");
|
|
123
118
|
lines.push(` MODULE_NAME: ${module.moduleName}`);
|
|
@@ -133,13 +128,14 @@ function appendModuleBuildJob(lines, module) {
|
|
|
133
128
|
lines.push(" expire_in: 1 day");
|
|
134
129
|
lines.push("");
|
|
135
130
|
}
|
|
136
|
-
function appendModuleTestJob(lines, module) {
|
|
131
|
+
function appendModuleTestJob(lines, module, branchRule) {
|
|
137
132
|
lines.push(`${module.jobId}_test:`);
|
|
138
133
|
lines.push(" stage: test");
|
|
139
|
-
|
|
134
|
+
lines.push(" rules:");
|
|
135
|
+
lines.push(" changes:");
|
|
136
|
+
lines.push(` - ${module.modulePath}/**/*`);
|
|
140
137
|
lines.push(" needs:");
|
|
141
138
|
lines.push(` - job: ${module.jobId}_build`);
|
|
142
|
-
lines.push(" optional: true");
|
|
143
139
|
lines.push(" image: $IMAGE_LINUX");
|
|
144
140
|
lines.push(" variables:");
|
|
145
141
|
lines.push(` MODULE_NAME: ${module.moduleName}`);
|
|
@@ -150,9 +146,63 @@ function appendModuleTestJob(lines, module) {
|
|
|
150
146
|
lines.push(' - echo "test is tasty"');
|
|
151
147
|
lines.push("");
|
|
152
148
|
}
|
|
149
|
+
function appendModuleReleaseJob(lines, module, branchRule) {
|
|
150
|
+
lines.push(`${module.jobId}_release:`);
|
|
151
|
+
lines.push(" stage: release");
|
|
152
|
+
lines.push(" rules:");
|
|
153
|
+
lines.push(" changes:");
|
|
154
|
+
lines.push(` - ${module.modulePath}/**/*`);
|
|
155
|
+
lines.push(" needs:");
|
|
156
|
+
lines.push(` - job: ${module.jobId}_build`);
|
|
157
|
+
lines.push(` - job: ${module.jobId}_test`);
|
|
158
|
+
lines.push(" image: $IMAGE_NODE");
|
|
159
|
+
lines.push(" variables:");
|
|
160
|
+
lines.push(` MODULE_NAME: ${module.moduleName}`);
|
|
161
|
+
lines.push(` MODULE_PATH: ${module.modulePath}`);
|
|
162
|
+
lines.push(` MODULE_TYPE: ${module.moduleType}`);
|
|
163
|
+
lines.push(" script:");
|
|
164
|
+
lines.push(" - apk update");
|
|
165
|
+
lines.push(" - apk add $GIT_PACKAGE");
|
|
166
|
+
lines.push(" - cp -r ci $MODULE_PATH/ci");
|
|
167
|
+
lines.push(" - cd $MODULE_PATH");
|
|
168
|
+
lines.push(" - npm ci");
|
|
169
|
+
lines.push(" - npx semalease semalease.env");
|
|
170
|
+
lines.push(" - source semalease.env");
|
|
171
|
+
lines.push(" - |");
|
|
172
|
+
lines.push(` if [ "$CI_COMMIT_BRANCH" = "main" ]; then`);
|
|
173
|
+
lines.push(` PACKAGE_VERSION="$NEXT_VERSION"`);
|
|
174
|
+
lines.push(` else`);
|
|
175
|
+
lines.push(` PACKAGE_VERSION="$NEXT_VERSION-$CI_COMMIT_BRANCH-$NEXT_INCREMENT"`);
|
|
176
|
+
lines.push(` fi`);
|
|
177
|
+
lines.push(` if [ "$MODULE_TYPE" = "node-express" ]; then`);
|
|
178
|
+
lines.push(` node -e "const fs=require('fs'); const pkg=JSON.parse(fs.readFileSync('package.json','utf8')); pkg.version=process.env.PACKAGE_VERSION; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\\n');"`);
|
|
179
|
+
lines.push(` node ci/prepare-deploy-variables.js --instance-branch $CI_COMMIT_BRANCH`);
|
|
180
|
+
lines.push(` elif [ "$MODULE_TYPE" = "node-vite" ]; then`);
|
|
181
|
+
lines.push(` node ci/set-release-data.js -i $CI_COMMIT_BRANCH --version=$NEXT_VERSION -t`);
|
|
182
|
+
lines.push(` node -e "const fs=require('fs'); const pkg=JSON.parse(fs.readFileSync('package.json','utf8')); pkg.version=process.env.PACKAGE_VERSION; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\\n');"`);
|
|
183
|
+
lines.push(` node ci/prepare-deploy-variables.js --instance-branch $CI_COMMIT_BRANCH`);
|
|
184
|
+
lines.push(` else`);
|
|
185
|
+
lines.push(` echo "Invalid module type: $MODULE_TYPE"`);
|
|
186
|
+
lines.push(` exit 1`);
|
|
187
|
+
lines.push(` fi`);
|
|
188
|
+
lines.push(` artifacts:`);
|
|
189
|
+
lines.push(` paths:`);
|
|
190
|
+
lines.push(` - $MODULE_PATH/dist`);
|
|
191
|
+
lines.push(` - $MODULE_PATH/package.json`);
|
|
192
|
+
lines.push(` - $MODULE_PATH/public/release.json`);
|
|
193
|
+
lines.push(` - $MODULE_PATH/semalease.env`);
|
|
194
|
+
lines.push(` - $MODULE_PATH/deploy.env`);
|
|
195
|
+
lines.push(` expire_in: 1 day`);
|
|
196
|
+
lines.push("");
|
|
197
|
+
}
|
|
153
198
|
function appendGlobalReleaseJob(lines, modules) {
|
|
154
199
|
lines.push("release_and_tag:");
|
|
155
200
|
lines.push(" stage: release");
|
|
201
|
+
lines.push(" needs:");
|
|
202
|
+
for (const module of modules) {
|
|
203
|
+
lines.push(` - job: ${module.jobId}_release`);
|
|
204
|
+
lines.push(` optional: true`);
|
|
205
|
+
}
|
|
156
206
|
lines.push(" image: $IMAGE_NODE");
|
|
157
207
|
lines.push(" variables:");
|
|
158
208
|
lines.push(" GITLAB_TOKEN: $SEMANTIC_RELEASE_TOKEN # Used to push release commits/tags.");
|
|
@@ -161,111 +211,87 @@ function appendGlobalReleaseJob(lines, modules) {
|
|
|
161
211
|
lines.push(" - apk add $GIT_PACKAGE");
|
|
162
212
|
lines.push(" - |");
|
|
163
213
|
lines.push(" set -euo pipefail");
|
|
164
|
-
lines.push(" git config user.email \"
|
|
165
|
-
lines.push(" git config user.name \"
|
|
214
|
+
lines.push(" git config user.email \"polyci@anarun.net\"");
|
|
215
|
+
lines.push(" git config user.name \"polyci\"");
|
|
166
216
|
lines.push(" git remote set-url origin \"https://oauth2:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git\"");
|
|
167
217
|
lines.push("");
|
|
168
|
-
lines.push(" if [ -n \"${CI_COMMIT_BEFORE_SHA:-}\" ] && [ \"${CI_COMMIT_BEFORE_SHA}\" != \"0000000000000000000000000000000000000000\" ]; then");
|
|
169
|
-
lines.push(" CHANGED_FILES=$(git diff --name-only \"${CI_COMMIT_BEFORE_SHA}\" \"${CI_COMMIT_SHA}\")");
|
|
170
|
-
lines.push(" else");
|
|
171
|
-
lines.push(" CHANGED_FILES=$(git show --pretty='' --name-only \"${CI_COMMIT_SHA}\")");
|
|
172
|
-
lines.push(" fi");
|
|
173
|
-
lines.push("");
|
|
174
|
-
lines.push(" MODULE_MATRIX=$(cat <<'EOF'");
|
|
175
|
-
for (const module of modules) {
|
|
176
|
-
lines.push(` ${module.moduleName}|${module.modulePath}`);
|
|
177
|
-
}
|
|
178
|
-
lines.push(" EOF");
|
|
179
|
-
lines.push(" )");
|
|
180
|
-
lines.push("");
|
|
181
|
-
lines.push(" AFFECTED_MODULES=\"\"");
|
|
182
|
-
lines.push(" while IFS='|' read -r MODULE_NAME MODULE_PATH; do");
|
|
183
|
-
lines.push(" [ -n \"${MODULE_NAME}\" ] || continue");
|
|
184
|
-
lines.push(" if printf '%s\\n' \"${CHANGED_FILES}\" | grep -q \"^${MODULE_PATH}/\"; then");
|
|
185
|
-
lines.push(" AFFECTED_MODULES=\"${AFFECTED_MODULES} ${MODULE_NAME}|${MODULE_PATH}\"");
|
|
186
|
-
lines.push(" fi");
|
|
187
|
-
lines.push(" done <<'EOF'");
|
|
188
218
|
for (const module of modules) {
|
|
189
|
-
lines.push(`
|
|
219
|
+
lines.push(` echo "Tagging release for ${module.moduleName} (${module.modulePath})"`);
|
|
220
|
+
lines.push(` if [ ! -f "${module.modulePath}/semalease.env" ]; then`);
|
|
221
|
+
lines.push(` echo "Missing ${module.modulePath}/semalease.env, skipping ${module.moduleName}"`);
|
|
222
|
+
lines.push(" continue");
|
|
223
|
+
lines.push(" fi");
|
|
224
|
+
lines.push(` source "${module.modulePath}/semalease.env"`);
|
|
225
|
+
lines.push(" if [ \"$CI_COMMIT_BRANCH\" = \"main\" ]; then");
|
|
226
|
+
lines.push(" if [ \"${NEXT_VERSION:-}\" = \"${LATEST_VERSION:-}\" ]; then");
|
|
227
|
+
lines.push(` echo "Version did not change for ${module.moduleName} on branch $CI_COMMIT_BRANCH, skipping tag"`);
|
|
228
|
+
lines.push(" continue");
|
|
229
|
+
lines.push(" fi");
|
|
230
|
+
lines.push(` TAG_NAME="${module.moduleName}-v\${NEXT_VERSION}"`);
|
|
231
|
+
lines.push(" else");
|
|
232
|
+
lines.push(" if [ \"${NEXT_VERSION:-}\" = \"${LATEST_VERSION:-}\" ] && [ \"${NEXT_INCREMENT:-}\" = \"${LATEST_INCREMENT:-}\" ]; then");
|
|
233
|
+
lines.push(` echo "Version/increment did not change for ${module.moduleName} on branch $CI_COMMIT_BRANCH, skipping tag"`);
|
|
234
|
+
lines.push(" continue");
|
|
235
|
+
lines.push(" fi");
|
|
236
|
+
lines.push(` TAG_NAME="${module.moduleName}-v\${NEXT_VERSION}-\${CI_COMMIT_BRANCH}-\${NEXT_INCREMENT}"`);
|
|
237
|
+
lines.push(" fi");
|
|
238
|
+
if (module.moduleType === "node-express") {
|
|
239
|
+
lines.push(` git add "${module.modulePath}/package.json"`);
|
|
240
|
+
}
|
|
241
|
+
else if (module.moduleType === "node-vite") {
|
|
242
|
+
lines.push(` git add "${module.modulePath}/package.json" "${module.modulePath}/public/release.json"`);
|
|
243
|
+
}
|
|
244
|
+
lines.push(" git tag \"${TAG_NAME}\"");
|
|
190
245
|
}
|
|
191
|
-
lines.push(" EOF");
|
|
192
|
-
lines.push("");
|
|
193
|
-
lines.push(" if [ -z \"${AFFECTED_MODULES}\" ]; then");
|
|
194
|
-
lines.push(" echo \"No affected modules in current commit range\" ");
|
|
195
|
-
lines.push(" exit 0");
|
|
196
|
-
lines.push(" fi");
|
|
197
|
-
lines.push("");
|
|
198
|
-
lines.push(" for entry in ${AFFECTED_MODULES}; do");
|
|
199
|
-
lines.push(" MODULE_NAME=${entry%%|*}");
|
|
200
|
-
lines.push(" MODULE_PATH=${entry#*|}");
|
|
201
|
-
lines.push(" echo \"Tagging release for ${MODULE_NAME} (${MODULE_PATH})\"");
|
|
202
|
-
lines.push(" cd \"${MODULE_PATH}\"");
|
|
203
|
-
lines.push(" npm ci");
|
|
204
|
-
lines.push(" npx semalease semalease.env");
|
|
205
|
-
lines.push(" source semalease.env");
|
|
206
|
-
lines.push(" cd - >/dev/null");
|
|
207
|
-
lines.push("");
|
|
208
|
-
lines.push(" if [ -z \"${NEXT_VERSION:-}\" ]; then");
|
|
209
|
-
lines.push(" echo \"No NEXT_VERSION for ${MODULE_NAME}, skipping tag\"");
|
|
210
|
-
lines.push(" continue");
|
|
211
|
-
lines.push(" fi");
|
|
212
|
-
lines.push("");
|
|
213
|
-
lines.push(" TAG_NAME=\"${MODULE_NAME}/v${NEXT_VERSION}\"");
|
|
214
|
-
lines.push(" if git rev-parse \"${TAG_NAME}\" >/dev/null 2>&1; then");
|
|
215
|
-
lines.push(" echo \"Tag ${TAG_NAME} already exists, skipping\"");
|
|
216
|
-
lines.push(" continue");
|
|
217
|
-
lines.push(" fi");
|
|
218
|
-
lines.push(" git tag \"${TAG_NAME}\"");
|
|
219
|
-
lines.push(" done");
|
|
220
|
-
lines.push("");
|
|
221
|
-
lines.push(" if [ -n \"$(git status --porcelain)\" ]; then");
|
|
222
|
-
lines.push(" git add -A");
|
|
223
|
-
lines.push(" git commit -m \"release: update affected modules\"");
|
|
224
|
-
lines.push(" fi");
|
|
225
246
|
lines.push("");
|
|
247
|
+
lines.push(" git commit -m \"release: update affected modules\"");
|
|
226
248
|
lines.push(" git push origin HEAD");
|
|
227
249
|
lines.push(" git push origin --tags");
|
|
250
|
+
lines.push(` artifacts:`);
|
|
251
|
+
lines.push(` paths:`);
|
|
252
|
+
for (const module of modules) {
|
|
253
|
+
lines.push(` - ${module.modulePath}/dist`);
|
|
254
|
+
lines.push(` - ${module.modulePath}/deploy.env`);
|
|
255
|
+
}
|
|
256
|
+
lines.push(` expire_in: 1 day`);
|
|
228
257
|
lines.push("");
|
|
229
258
|
}
|
|
230
|
-
function appendModulePublishJob(lines, module) {
|
|
259
|
+
function appendModulePublishJob(lines, module, branchRule) {
|
|
231
260
|
lines.push(`${module.jobId}_publish:`);
|
|
232
261
|
lines.push(" stage: publish");
|
|
233
|
-
|
|
262
|
+
lines.push(" rules:");
|
|
263
|
+
lines.push(" changes:");
|
|
264
|
+
lines.push(` - ${module.modulePath}/**/*`);
|
|
234
265
|
lines.push(" needs:");
|
|
235
266
|
lines.push(` - job: ${module.jobId}_test`);
|
|
236
|
-
lines.push(" optional: true");
|
|
237
267
|
lines.push(" - job: release_and_tag");
|
|
238
|
-
lines.push(" optional: true");
|
|
239
268
|
lines.push(" image: $IMAGE_DOCKER");
|
|
240
269
|
lines.push(" variables:");
|
|
241
270
|
lines.push(` MODULE_NAME: ${module.moduleName}`);
|
|
242
271
|
lines.push(` MODULE_PATH: ${module.modulePath}`);
|
|
243
272
|
lines.push(` MODULE_TYPE: ${module.moduleType}`);
|
|
244
273
|
lines.push(" script:");
|
|
274
|
+
lines.push(" - cp -r ci $MODULE_PATH/ci");
|
|
245
275
|
lines.push(" - cd $MODULE_PATH");
|
|
276
|
+
lines.push(" - source deploy.env");
|
|
246
277
|
lines.push(" - npm ci");
|
|
247
|
-
lines.push(" -
|
|
248
|
-
lines.push(" - source semalease.env");
|
|
249
|
-
lines.push(" - node ../ci/set-release-data.js -i $CI_COMMIT_BRANCH --version=${NEXT_VERSION} -t");
|
|
250
|
-
lines.push(" - npm run build");
|
|
251
|
-
lines.push(" - node ci/prepare-deploy-variables.js");
|
|
252
|
-
lines.push(" - echo -n $CI_JOB_TOKEN | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY");
|
|
253
|
-
lines.push(" - cp ../ci/$MODULE_TYPE/Dockerfile .");
|
|
278
|
+
lines.push(" - cp ci/$MODULE_TYPE/Dockerfile .");
|
|
254
279
|
lines.push(" - docker build --tag $CI_REGISTRY_IMAGE/$MODULE_NAME:v$INSTANCE_VERSION .");
|
|
255
280
|
lines.push(" - docker push $CI_REGISTRY_IMAGE/$MODULE_NAME:v$INSTANCE_VERSION");
|
|
256
281
|
lines.push(" artifacts:");
|
|
257
282
|
lines.push(" reports:");
|
|
258
|
-
lines.push(" dotenv: $MODULE_PATH
|
|
283
|
+
lines.push(" dotenv: $MODULE_PATH/deploy.env");
|
|
259
284
|
lines.push(" expire_in: 1 day");
|
|
260
285
|
lines.push("");
|
|
261
286
|
}
|
|
262
|
-
function appendModuleDeployJob(lines, module) {
|
|
287
|
+
function appendModuleDeployJob(lines, module, branchRule) {
|
|
263
288
|
lines.push(`${module.jobId}_deploy:`);
|
|
264
289
|
lines.push(" stage: deploy");
|
|
265
|
-
|
|
290
|
+
lines.push(" rules:");
|
|
291
|
+
lines.push(" changes:");
|
|
292
|
+
lines.push(` - ${module.modulePath}/**/*`);
|
|
266
293
|
lines.push(" needs:");
|
|
267
294
|
lines.push(` - job: ${module.jobId}_publish`);
|
|
268
|
-
lines.push(" optional: true");
|
|
269
295
|
lines.push(" image: $IMAGE_COMPOSE");
|
|
270
296
|
lines.push(" variables:");
|
|
271
297
|
lines.push(` MODULE_NAME: ${module.moduleName}`);
|
|
@@ -289,34 +315,34 @@ function appendModuleDeployJob(lines, module) {
|
|
|
289
315
|
lines.push(" - rm -rf ~/.ssh");
|
|
290
316
|
lines.push("");
|
|
291
317
|
}
|
|
292
|
-
function buildPipeline(modules) {
|
|
318
|
+
function buildPipeline(modules, branchRule) {
|
|
293
319
|
const lines = [];
|
|
294
320
|
appendGlobalVariables(lines);
|
|
295
321
|
for (const module of modules) {
|
|
296
|
-
appendModuleBuildJob(lines, module);
|
|
297
|
-
appendModuleTestJob(lines, module);
|
|
322
|
+
appendModuleBuildJob(lines, module, branchRule);
|
|
323
|
+
appendModuleTestJob(lines, module, branchRule);
|
|
324
|
+
appendModuleReleaseJob(lines, module, branchRule);
|
|
298
325
|
}
|
|
299
326
|
appendGlobalReleaseJob(lines, modules);
|
|
300
327
|
for (const module of modules) {
|
|
301
|
-
appendModulePublishJob(lines, module);
|
|
302
|
-
appendModuleDeployJob(lines, module);
|
|
328
|
+
appendModulePublishJob(lines, module, branchRule);
|
|
329
|
+
appendModuleDeployJob(lines, module, branchRule);
|
|
303
330
|
}
|
|
304
331
|
return `${lines.join("\n").trimEnd()}\n`;
|
|
305
332
|
}
|
|
306
333
|
function main() {
|
|
307
|
-
const { cwd, output } = parseArgs();
|
|
334
|
+
const { cwd, output, modulesRoot, branchRule } = parseArgs();
|
|
308
335
|
if (!output) {
|
|
309
336
|
log.error("Output path is required. Use [output] or --output <path>.");
|
|
310
337
|
process.exit(1);
|
|
311
338
|
}
|
|
312
|
-
const modules = discoverModules(cwd);
|
|
339
|
+
const modules = discoverModules(cwd, modulesRoot);
|
|
313
340
|
if (modules.length === 0) {
|
|
314
|
-
log.error({ cwd }, "No supported modules were discovered under
|
|
341
|
+
log.error({ cwd, modulesRoot }, "No supported modules were discovered under modules root");
|
|
315
342
|
process.exit(1);
|
|
316
343
|
}
|
|
317
|
-
const pipeline = buildPipeline(modules);
|
|
344
|
+
const pipeline = buildPipeline(modules, branchRule);
|
|
318
345
|
const outputPath = path.resolve(cwd, output);
|
|
319
|
-
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
320
346
|
fs.writeFileSync(outputPath, pipeline, "utf8");
|
|
321
347
|
log.info({ modules: modules.map((m) => m.modulePath), outputPath }, "Generated GitLab pipeline");
|
|
322
348
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polyci",
|
|
3
3
|
"description": "Monorepo CI/CD utilities.",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"author": "Alexander Tsarev",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"main": "./dist/main.js",
|
|
10
|
-
"bin":
|
|
11
|
-
|
|
10
|
+
"bin": {
|
|
11
|
+
"polyci": "dist/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"readme.md"
|
|
16
|
+
],
|
|
12
17
|
"publishConfig": {
|
|
13
18
|
"access": "public"
|
|
14
19
|
},
|