polyci 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.js +68 -63
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -5,15 +5,22 @@ import pino from "pino";
5
5
  import pretty from "pino-pretty";
6
6
  const log = pino(pretty());
7
7
  const DEFAULT_TAG_TEMPLATE = "{module}-v{version}";
8
- const DEFAULT_BRANCH_TAG_TEMPLATE = "{module}-v{version}-{branch}-{increment}";
9
- const ALLOWED_TAG_PLACEHOLDERS = new Set(["module", "branch", "version", "increment"]);
10
- function applyTagTemplate(template, moduleName) {
8
+ const DEFAULT_VERSION_TEMPLATE = "{version}";
9
+ const DEFAULT_BRANCH_VERSION_TEMPLATE = "{version}-{branch}-{increment}";
10
+ const DEFAULT_TAG_PATTERN = "^$MODULE_NAME-v(?<version>\\d+(\\.\\d+)*)-$CI_COMMIT_BRANCH-(?<increment>\\d+(\\.\\d+)*)$";
11
+ const ALLOWED_TAG_PLACEHOLDERS = new Set(["module", "version"]);
12
+ const ALLOWED_VERSION_PLACEHOLDERS = new Set(["branch", "version", "increment"]);
13
+ function applyVersionTemplate(template) {
11
14
  return template
12
- .replaceAll("{module}", moduleName)
13
15
  .replaceAll("{branch}", "${CI_COMMIT_BRANCH}")
14
16
  .replaceAll("{version}", "${NEXT_VERSION}")
15
17
  .replaceAll("{increment}", "${NEXT_INCREMENT}");
16
18
  }
19
+ function applyTagTemplate(template, moduleName, version) {
20
+ return template
21
+ .replaceAll("{module}", moduleName)
22
+ .replaceAll("{version}", version);
23
+ }
17
24
  function getInvalidTagTemplatePlaceholders(template) {
18
25
  const matches = template.matchAll(/\{([^}]+)\}/g);
19
26
  const invalid = new Set();
@@ -25,6 +32,17 @@ function getInvalidTagTemplatePlaceholders(template) {
25
32
  }
26
33
  return [...invalid];
27
34
  }
35
+ function getInvalidVersionTemplatePlaceholders(template) {
36
+ const matches = template.matchAll(/\{([^}]+)\}/g);
37
+ const invalid = new Set();
38
+ for (const match of matches) {
39
+ const placeholder = match[1];
40
+ if (!ALLOWED_VERSION_PLACEHOLDERS.has(placeholder)) {
41
+ invalid.add(placeholder);
42
+ }
43
+ }
44
+ return [...invalid];
45
+ }
28
46
  function parseArgs() {
29
47
  const program = new Command();
30
48
  program
@@ -32,8 +50,10 @@ function parseArgs() {
32
50
  .option("-o, --output <path>", "Output pipeline file path")
33
51
  .option("--modules-root <path>", "Modules root directory", "./modules")
34
52
  .option("--main-branch <name>", "Primary branch name for release tagging logic", "main")
35
- .option("--tag-template <template>", "Template for non-primary branch tags; use placeholders {module}, {branch}, {version}, {increment}", DEFAULT_TAG_TEMPLATE)
36
- .option("--branch-tag-template <template>", "Template for non-primary branch tags; use placeholders {module}, {branch}, {version}, {increment}", DEFAULT_BRANCH_TAG_TEMPLATE)
53
+ .option("--version-template <template>", "Template for primary branch module version; placeholders {version}, {branch}, {increment}", DEFAULT_VERSION_TEMPLATE)
54
+ .option("--branch-version-template <template>", "Template for non-primary branch module version; placeholders {version}, {branch}, {increment}", DEFAULT_BRANCH_VERSION_TEMPLATE)
55
+ .option("--tag-template <template>", "Template for non-primary branch tags; use placeholders {module}, {version}", DEFAULT_TAG_TEMPLATE)
56
+ .option("--tag-pattern <pattern>", "Tag pattern passed to semalease to find the latest tag and calculate the next version/increment", DEFAULT_TAG_PATTERN)
37
57
  .option("--cwd <path>", "Working directory", process.cwd())
38
58
  .parse();
39
59
  const options = program.opts();
@@ -41,17 +61,25 @@ function parseArgs() {
41
61
  const cwd = path.resolve(options.cwd);
42
62
  const modulesRoot = path.resolve(cwd, options.modulesRoot);
43
63
  const mainBranch = options.mainBranch;
64
+ const versionTemplate = options.versionTemplate;
65
+ const branchVersionTemplate = options.branchVersionTemplate;
44
66
  const tagTemplate = options.tagTemplate;
45
- const branchTagTemplate = options.branchTagTemplate;
46
- const invalidPrimary = getInvalidTagTemplatePlaceholders(tagTemplate);
47
- if (invalidPrimary.length > 0) {
48
- program.error(`Invalid --tag-template placeholders: ${invalidPrimary
67
+ const tagPattern = options.tagPattern;
68
+ const invalidVersionTemplate = getInvalidVersionTemplatePlaceholders(versionTemplate);
69
+ if (invalidVersionTemplate.length > 0) {
70
+ program.error(`Invalid --version-template placeholders: ${invalidVersionTemplate
49
71
  .map((x) => `{${x}}`)
50
- .join(", ")}. Allowed: {module}, {branch}, {version}, {increment}.`);
72
+ .join(", ")}. Allowed: {version}, {branch}, {increment}.`);
51
73
  }
52
- const invalidSecondary = getInvalidTagTemplatePlaceholders(branchTagTemplate);
53
- if (invalidSecondary.length > 0) {
54
- program.error(`Invalid --branch-tag-template placeholders: ${invalidSecondary
74
+ const invalidBranchVersionTemplate = getInvalidVersionTemplatePlaceholders(branchVersionTemplate);
75
+ if (invalidBranchVersionTemplate.length > 0) {
76
+ program.error(`Invalid --branch-version-template placeholders: ${invalidBranchVersionTemplate
77
+ .map((x) => `{${x}}`)
78
+ .join(", ")}. Allowed: {version}, {branch}, {increment}.`);
79
+ }
80
+ const invalidTagTemplate = getInvalidTagTemplatePlaceholders(tagTemplate);
81
+ if (invalidTagTemplate.length > 0) {
82
+ program.error(`Invalid --tag-template placeholders: ${invalidTagTemplate
55
83
  .map((x) => `{${x}}`)
56
84
  .join(", ")}. Allowed: {module}, {branch}, {version}, {increment}.`);
57
85
  }
@@ -60,8 +88,10 @@ function parseArgs() {
60
88
  output,
61
89
  modulesRoot,
62
90
  mainBranch,
91
+ versionTemplate,
92
+ branchVersionTemplate,
63
93
  tagTemplate,
64
- branchTagTemplate,
94
+ tagPattern,
65
95
  };
66
96
  }
67
97
  function toPosixPath(p) {
@@ -190,7 +220,7 @@ function appendModuleTestJob(lines, module) {
190
220
  lines.push(` - echo "test is tasty"`);
191
221
  lines.push(``);
192
222
  }
193
- function appendModuleReleaseJob(lines, module) {
223
+ function appendModuleReleaseJob(lines, module, tagPattern) {
194
224
  lines.push(`${module.jobId}_release:`);
195
225
  lines.push(` stage: release`);
196
226
  lines.push(` rules:`);
@@ -207,41 +237,16 @@ function appendModuleReleaseJob(lines, module) {
207
237
  lines.push(` script:`);
208
238
  lines.push(` - apk update`);
209
239
  lines.push(` - apk add $GIT_PACKAGE`);
210
- lines.push(` - cp -r ci $MODULE_PATH/ci`);
211
- lines.push(` - cd $MODULE_PATH`);
212
- lines.push(` - npm ci`);
213
- lines.push(` - git tag -l "^${module.moduleName}-v(?<version>\\d+(\\.\\d+)*)-$CI_COMMIT_BRANCH-(?<increment>\\d+(\\.\\d+)*)$"`);
214
- lines.push(` - npx semalease --tag-pattern "^${module.moduleName}-v(?<version>\\d+(\\.\\d+)*)-$CI_COMMIT_BRANCH-(?<increment>\\d+(\\.\\d+)*)$" semalease.env`);
215
- lines.push(` - source semalease.env`);
216
- lines.push(` - |`);
217
- lines.push(` if [ "$CI_COMMIT_BRANCH" = "main" ]; then`);
218
- lines.push(` PACKAGE_VERSION="$NEXT_VERSION"`);
219
- lines.push(` else`);
220
- lines.push(` PACKAGE_VERSION="$NEXT_VERSION-$CI_COMMIT_BRANCH-$NEXT_INCREMENT"`);
221
- lines.push(` fi`);
222
- lines.push(` - |`);
223
- lines.push(` if [ "$MODULE_TYPE" = "node-express" ]; then`);
224
- lines.push(` node -e "const fs=require('fs'); const pkg=JSON.parse(fs.readFileSync('package.json','utf8')); pkg.version=process.argv[1]; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\\n');" "$PACKAGE_VERSION"`);
225
- lines.push(` node ci/prepare-deploy-variables.js --instance-branch $CI_COMMIT_BRANCH`);
226
- lines.push(` elif [ "$MODULE_TYPE" = "node-vite" ]; then`);
227
- lines.push(` node ci/set-release-data.js -i $CI_COMMIT_BRANCH --version=$PACKAGE_VERSION -t`);
228
- lines.push(` node -e "const fs=require('fs'); const pkg=JSON.parse(fs.readFileSync('package.json','utf8')); pkg.version=process.argv[1]; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\\n');" "$PACKAGE_VERSION"`);
229
- lines.push(` node ci/prepare-deploy-variables.js --instance-branch $CI_COMMIT_BRANCH`);
230
- lines.push(` else`);
231
- lines.push(` echo "Invalid module type: $MODULE_TYPE"`);
232
- lines.push(` exit 1`);
233
- lines.push(` fi`);
240
+ lines.push(` - cd ${module.modulePath}`);
241
+ lines.push(` - npx semalease --tag-pattern "${tagPattern}" semalease.env`);
234
242
  lines.push(` artifacts:`);
235
243
  lines.push(` paths:`);
236
244
  lines.push(` - $MODULE_PATH/dist`);
237
- lines.push(` - $MODULE_PATH/package.json`);
238
- lines.push(` - $MODULE_PATH/public/release.json`);
239
245
  lines.push(` - $MODULE_PATH/semalease.env`);
240
- lines.push(` - $MODULE_PATH/deploy.env`);
241
246
  lines.push(` expire_in: 1 day`);
242
247
  lines.push(``);
243
248
  }
244
- function appendGlobalReleaseJob(lines, modules, mainBranch, tagTemplate, branchTagTemplate) {
249
+ function appendGlobalReleaseJob(lines, modules, mainBranch, versionTemplate, branchVersionTemplate, tagTemplate) {
245
250
  lines.push(`release_and_tag:`);
246
251
  lines.push(` stage: release`);
247
252
  lines.push(` needs:`);
@@ -266,31 +271,31 @@ function appendGlobalReleaseJob(lines, modules, mainBranch, tagTemplate, branchT
266
271
  lines.push(` - |`);
267
272
  lines.push(` if [ -f "${module.modulePath}/semalease.env" ]; then`);
268
273
  lines.push(` . "${module.modulePath}/semalease.env"`);
269
- lines.push(` TAG_NAME=""`);
274
+ lines.push(` MODULE_TAG=""`);
270
275
  lines.push(` if [ "$CI_COMMIT_BRANCH" = "${mainBranch}" ]; then`);
271
276
  lines.push(` if [ "\${NEXT_VERSION:-}" != "\${LATEST_VERSION:-}" ]; then`);
272
- lines.push(` TAG_NAME="${applyTagTemplate(tagTemplate, module.moduleName)}"`);
277
+ lines.push(` MODULE_VERSION="${applyVersionTemplate(versionTemplate)}"`);
278
+ lines.push(` MODULE_TAG="${applyTagTemplate(tagTemplate, module.moduleName, applyVersionTemplate(versionTemplate))}"`);
273
279
  lines.push(` else`);
274
- lines.push(` echo "Version did not change for ${module.moduleName} on branch $CI_COMMIT_BRANCH, skipping tag"`);
280
+ lines.push(` echo "Version did not change for ${module.moduleName} on branch $CI_COMMIT_BRANCH, skipping release."`);
275
281
  lines.push(` fi`);
276
282
  lines.push(` else`);
277
283
  lines.push(` if [ "\${NEXT_VERSION:-}" != "\${LATEST_VERSION:-}" ] || [ "\${NEXT_INCREMENT:-}" != "\${LATEST_INCREMENT:-}" ]; then`);
278
- lines.push(` TAG_NAME="${applyTagTemplate(branchTagTemplate, module.moduleName)}"`);
284
+ lines.push(` MODULE_VERSION="${applyVersionTemplate(branchVersionTemplate)}"`);
285
+ lines.push(` MODULE_TAG="${applyTagTemplate(tagTemplate, module.moduleName, applyVersionTemplate(branchVersionTemplate))}"`);
279
286
  lines.push(` else`);
280
- lines.push(` echo "Version/increment did not change for ${module.moduleName} on branch $CI_COMMIT_BRANCH, skipping tag"`);
287
+ lines.push(` echo "Version/increment did not change for ${module.moduleName} on branch $CI_COMMIT_BRANCH, skipping release."`);
281
288
  lines.push(` fi`);
282
289
  lines.push(` fi`);
283
- lines.push(` if [ "$TAG_NAME" != "" ]; then`);
284
- if (module.moduleType === "node-express") {
285
- lines.push(` git add "${module.modulePath}/package.json"`);
286
- }
287
- else if (module.moduleType === "node-vite") {
288
- lines.push(` git add "${module.modulePath}/package.json" "${module.modulePath}/public/release.json"`);
289
- }
290
- lines.push(` TAG_NAMES="\${TAG_NAMES} \${TAG_NAME}"`);
290
+ lines.push(` if [ "$MODULE_TAG" != "" ]; then`);
291
+ lines.push(` cp -r ci "${module.modulePath}/ci"`);
292
+ lines.push(` cd "${module.modulePath}"`);
293
+ lines.push(` source "ci/${module.moduleType}/release.sh"`);
294
+ lines.push(` cd - >/dev/null`);
295
+ lines.push(` TAG_NAMES="\${TAG_NAMES} \${MODULE_TAG}"`);
291
296
  lines.push(` fi`);
292
297
  lines.push(` else`);
293
- lines.push(` echo "Missing ${module.modulePath}/semalease.env, skipping ${module.moduleName}"`);
298
+ lines.push(` echo "Missing ${module.modulePath}/semalease.env, skipping ${module.moduleName} release."`);
294
299
  lines.push(` fi`);
295
300
  }
296
301
  lines.push(``);
@@ -376,15 +381,15 @@ function appendModuleDeployJob(lines, module) {
376
381
  lines.push(` - rm -rf ~/.ssh`);
377
382
  lines.push(``);
378
383
  }
379
- function buildPipeline(modules, mainBranch, tagTemplate, branchTagTemplate) {
384
+ function buildPipeline(modules, mainBranch, versionTemplate, branchVersionTemplate, tagTemplate, tagPattern) {
380
385
  const lines = [];
381
386
  appendGlobalVariables(lines);
382
387
  for (const module of modules) {
383
388
  appendModuleBuildJob(lines, module);
384
389
  appendModuleTestJob(lines, module);
385
- appendModuleReleaseJob(lines, module);
390
+ appendModuleReleaseJob(lines, module, tagPattern);
386
391
  }
387
- appendGlobalReleaseJob(lines, modules, mainBranch, tagTemplate, branchTagTemplate);
392
+ appendGlobalReleaseJob(lines, modules, mainBranch, versionTemplate, branchVersionTemplate, tagTemplate);
388
393
  for (const module of modules) {
389
394
  appendModulePublishJob(lines, module);
390
395
  appendModuleDeployJob(lines, module);
@@ -392,7 +397,7 @@ function buildPipeline(modules, mainBranch, tagTemplate, branchTagTemplate) {
392
397
  return `${lines.join("\n").trimEnd()}\n`;
393
398
  }
394
399
  function main() {
395
- const { cwd, output, modulesRoot, mainBranch, tagTemplate, branchTagTemplate, } = parseArgs();
400
+ const { cwd, output, modulesRoot, mainBranch, versionTemplate, branchVersionTemplate, tagTemplate, tagPattern } = parseArgs();
396
401
  if (!output) {
397
402
  log.error("Output path is required. Use [output] or --output <path>.");
398
403
  process.exit(1);
@@ -402,7 +407,7 @@ function main() {
402
407
  log.error({ cwd, modulesRoot }, "No supported modules were discovered under modules root");
403
408
  process.exit(1);
404
409
  }
405
- const pipeline = buildPipeline(modules, mainBranch, tagTemplate, branchTagTemplate);
410
+ const pipeline = buildPipeline(modules, mainBranch, versionTemplate, branchVersionTemplate, tagTemplate, tagPattern);
406
411
  const outputPath = path.resolve(cwd, output);
407
412
  fs.writeFileSync(outputPath, pipeline, "utf8");
408
413
  log.info({ modules: modules.map((m) => m.modulePath), outputPath }, "Generated GitLab pipeline");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "polyci",
3
3
  "description": "Monorepo CI/CD utilities.",
4
- "version": "0.0.21",
4
+ "version": "0.0.22",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "author": "Alexander Tsarev",