polyci 0.0.6 → 0.0.7

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 +62 -21
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -4,24 +4,65 @@ import * as path from "node:path";
4
4
  import pino from "pino";
5
5
  import pretty from "pino-pretty";
6
6
  const log = pino(pretty());
7
- const DEFAULT_BRANCH_RULE = "/^(main)|(develop)|(release(-[a-z0-9]+)*)|(feature(-[a-z0-9]+)*)|(patch(-[a-z0-9]+)*)$/";
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) {
11
+ return template
12
+ .replaceAll("{module}", moduleName)
13
+ .replaceAll("{branch}", "${CI_COMMIT_BRANCH}")
14
+ .replaceAll("{version}", "${NEXT_VERSION}")
15
+ .replaceAll("{increment}", "${NEXT_INCREMENT}");
16
+ }
17
+ function getInvalidTagTemplatePlaceholders(template) {
18
+ const matches = template.matchAll(/\{([^}]+)\}/g);
19
+ const invalid = new Set();
20
+ for (const match of matches) {
21
+ const placeholder = match[1];
22
+ if (!ALLOWED_TAG_PLACEHOLDERS.has(placeholder)) {
23
+ invalid.add(placeholder);
24
+ }
25
+ }
26
+ return [...invalid];
27
+ }
8
28
  function parseArgs() {
9
29
  const program = new Command();
10
30
  program
11
31
  .argument("[output]", "Output pipeline file path (or use --output)")
12
32
  .option("-o, --output <path>", "Output pipeline file path")
13
33
  .option("--modules-root <path>", "Modules root directory", "./modules")
14
- .option("--branch-rule <regex>", "Branch rule regex for module jobs", DEFAULT_BRANCH_RULE)
15
34
  .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)
16
37
  .option("--cwd <path>", "Working directory", process.cwd())
17
38
  .parse();
18
39
  const options = program.opts();
19
40
  const output = options.output ?? program.args[0] ?? "";
20
41
  const cwd = path.resolve(options.cwd);
21
42
  const modulesRoot = path.resolve(cwd, options.modulesRoot);
22
- const branchRule = options.branchRule;
23
43
  const mainBranch = options.mainBranch;
24
- return { cwd, output, modulesRoot, branchRule, mainBranch };
44
+ 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
49
+ .map((x) => `{${x}}`)
50
+ .join(", ")}. Allowed: {module}, {branch}, {version}, {increment}.`);
51
+ }
52
+ const invalidSecondary = getInvalidTagTemplatePlaceholders(branchTagTemplate);
53
+ if (invalidSecondary.length > 0) {
54
+ program.error(`Invalid --branch-tag-template placeholders: ${invalidSecondary
55
+ .map((x) => `{${x}}`)
56
+ .join(", ")}. Allowed: {module}, {branch}, {version}, {increment}.`);
57
+ }
58
+ return {
59
+ cwd,
60
+ output,
61
+ modulesRoot,
62
+ mainBranch,
63
+ tagTemplate,
64
+ branchTagTemplate,
65
+ };
25
66
  }
26
67
  function toPosixPath(p) {
27
68
  return p.split(path.sep).join("/");
@@ -109,7 +150,7 @@ function appendGlobalVariables(lines) {
109
150
  lines.push(" - deploy");
110
151
  lines.push("");
111
152
  }
112
- function appendModuleBuildJob(lines, module, branchRule) {
153
+ function appendModuleBuildJob(lines, module) {
113
154
  lines.push(`${module.jobId}_build:`);
114
155
  lines.push(" stage: build");
115
156
  lines.push(" rules:");
@@ -130,7 +171,7 @@ function appendModuleBuildJob(lines, module, branchRule) {
130
171
  lines.push(" expire_in: 1 day");
131
172
  lines.push("");
132
173
  }
133
- function appendModuleTestJob(lines, module, branchRule) {
174
+ function appendModuleTestJob(lines, module) {
134
175
  lines.push(`${module.jobId}_test:`);
135
176
  lines.push(" stage: test");
136
177
  lines.push(" rules:");
@@ -148,7 +189,7 @@ function appendModuleTestJob(lines, module, branchRule) {
148
189
  lines.push(' - echo "test is tasty"');
149
190
  lines.push("");
150
191
  }
151
- function appendModuleReleaseJob(lines, module, branchRule) {
192
+ function appendModuleReleaseJob(lines, module) {
152
193
  lines.push(`${module.jobId}_release:`);
153
194
  lines.push(" stage: release");
154
195
  lines.push(" rules:");
@@ -197,7 +238,7 @@ function appendModuleReleaseJob(lines, module, branchRule) {
197
238
  lines.push(` expire_in: 1 day`);
198
239
  lines.push("");
199
240
  }
200
- function appendGlobalReleaseJob(lines, modules, mainBranch) {
241
+ function appendGlobalReleaseJob(lines, modules, mainBranch, tagTemplate, branchTagTemplate) {
201
242
  lines.push("release_and_tag:");
202
243
  lines.push(" stage: release");
203
244
  lines.push(" needs:");
@@ -225,13 +266,13 @@ function appendGlobalReleaseJob(lines, modules, mainBranch) {
225
266
  lines.push(" TAG_NAME=\"\"");
226
267
  lines.push(` if [ "$CI_COMMIT_BRANCH" = "${mainBranch}" ]; then`);
227
268
  lines.push(" if [ \"${NEXT_VERSION:-}\" != \"${LATEST_VERSION:-}\" ]; then");
228
- lines.push(` TAG_NAME="${module.moduleName}-v\${NEXT_VERSION}"`);
269
+ lines.push(` TAG_NAME="${applyTagTemplate(tagTemplate, module.moduleName)}"`);
229
270
  lines.push(" else");
230
271
  lines.push(` echo "Version did not change for ${module.moduleName} on branch $CI_COMMIT_BRANCH, skipping tag"`);
231
272
  lines.push(" fi");
232
273
  lines.push(" else");
233
274
  lines.push(" if [ \"${NEXT_VERSION:-}\" != \"${LATEST_VERSION:-}\" ] || [ \"${NEXT_INCREMENT:-}\" != \"${LATEST_INCREMENT:-}\" ]; then");
234
- lines.push(` TAG_NAME="${module.moduleName}-v\${NEXT_VERSION}-\${CI_COMMIT_BRANCH}-\${NEXT_INCREMENT}"`);
275
+ lines.push(` TAG_NAME="${applyTagTemplate(branchTagTemplate, module.moduleName)}"`);
235
276
  lines.push(" else");
236
277
  lines.push(` echo "Version/increment did not change for ${module.moduleName} on branch $CI_COMMIT_BRANCH, skipping tag"`);
237
278
  lines.push(" fi");
@@ -267,7 +308,7 @@ function appendGlobalReleaseJob(lines, modules, mainBranch) {
267
308
  lines.push(` expire_in: 1 day`);
268
309
  lines.push("");
269
310
  }
270
- function appendModulePublishJob(lines, module, branchRule) {
311
+ function appendModulePublishJob(lines, module) {
271
312
  lines.push(`${module.jobId}_publish:`);
272
313
  lines.push(" stage: publish");
273
314
  lines.push(" rules:");
@@ -295,7 +336,7 @@ function appendModulePublishJob(lines, module, branchRule) {
295
336
  lines.push(" expire_in: 1 day");
296
337
  lines.push("");
297
338
  }
298
- function appendModuleDeployJob(lines, module, branchRule) {
339
+ function appendModuleDeployJob(lines, module) {
299
340
  lines.push(`${module.jobId}_deploy:`);
300
341
  lines.push(" stage: deploy");
301
342
  lines.push(" rules:");
@@ -326,23 +367,23 @@ function appendModuleDeployJob(lines, module, branchRule) {
326
367
  lines.push(" - rm -rf ~/.ssh");
327
368
  lines.push("");
328
369
  }
329
- function buildPipeline(modules, branchRule, mainBranch) {
370
+ function buildPipeline(modules, mainBranch, tagTemplate, branchTagTemplate) {
330
371
  const lines = [];
331
372
  appendGlobalVariables(lines);
332
373
  for (const module of modules) {
333
- appendModuleBuildJob(lines, module, branchRule);
334
- appendModuleTestJob(lines, module, branchRule);
335
- appendModuleReleaseJob(lines, module, branchRule);
374
+ appendModuleBuildJob(lines, module);
375
+ appendModuleTestJob(lines, module);
376
+ appendModuleReleaseJob(lines, module);
336
377
  }
337
- appendGlobalReleaseJob(lines, modules, mainBranch);
378
+ appendGlobalReleaseJob(lines, modules, mainBranch, tagTemplate, branchTagTemplate);
338
379
  for (const module of modules) {
339
- appendModulePublishJob(lines, module, branchRule);
340
- appendModuleDeployJob(lines, module, branchRule);
380
+ appendModulePublishJob(lines, module);
381
+ appendModuleDeployJob(lines, module);
341
382
  }
342
383
  return `${lines.join("\n").trimEnd()}\n`;
343
384
  }
344
385
  function main() {
345
- const { cwd, output, modulesRoot, branchRule, mainBranch } = parseArgs();
386
+ const { cwd, output, modulesRoot, mainBranch, tagTemplate, branchTagTemplate, } = parseArgs();
346
387
  if (!output) {
347
388
  log.error("Output path is required. Use [output] or --output <path>.");
348
389
  process.exit(1);
@@ -352,7 +393,7 @@ function main() {
352
393
  log.error({ cwd, modulesRoot }, "No supported modules were discovered under modules root");
353
394
  process.exit(1);
354
395
  }
355
- const pipeline = buildPipeline(modules, branchRule, mainBranch);
396
+ const pipeline = buildPipeline(modules, mainBranch, tagTemplate, branchTagTemplate);
356
397
  const outputPath = path.resolve(cwd, output);
357
398
  fs.writeFileSync(outputPath, pipeline, "utf8");
358
399
  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.6",
4
+ "version": "0.0.7",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "author": "Alexander Tsarev",