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.
Files changed (2) hide show
  1. package/dist/main.js +145 -119
  2. 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
- function exec(command, cwd) {
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
- return { cwd, output };
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(scanDir, repoRoot, modules) {
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 moduleName = path.basename(scanDir);
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
- if (IGNORED_DIRS.has(entry.name))
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, repoRoot, modules);
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 #alpine:3.23.3");
94
- lines.push(" IMAGE_NODE: node:alpine #node:25.6.0-alpine3.23");
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 #nginx:1.29.5-alpine3.23-slim");
97
- lines.push(" IMAGE_DOCKER: docker:latest #docker:29.2.1-dind-alpine3.23");
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 #git=2.47.2-r0");
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 appendRulesForModule(lines, modulePath) {
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
- appendRulesForModule(lines, module.modulePath);
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
- appendRulesForModule(lines, module.modulePath);
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 \"ci-release@local\"");
165
- lines.push(" git config user.name \"CI Release\"");
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(` ${module.moduleName}|${module.modulePath}`);
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
- appendRulesForModule(lines, module.modulePath);
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(" - npx semalease semalease.env");
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/.env.deploy");
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
- appendRulesForModule(lines, module.modulePath);
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 ./modules");
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.1",
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": "./dist/cli.js",
11
- "files": ["dist", "readme.md"],
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
  },