cistack 5.0.0 → 5.1.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cistack",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "description": "Automatically generate GitHub Actions CI/CD pipelines by analysing your codebase",
5
5
  "main": "src/index.js",
6
6
  "types": "index.d.ts",
@@ -150,6 +150,11 @@ class DependabotGenerator {
150
150
  directory: '/',
151
151
  schedule: { interval: 'weekly', day: 'monday' },
152
152
  'open-pull-requests-limit': 10,
153
+ groups: {
154
+ 'github-actions-updates': {
155
+ patterns: ['*'],
156
+ },
157
+ },
153
158
  });
154
159
 
155
160
  const doc = { version: 2, updates };
package/src/index.js CHANGED
@@ -124,7 +124,7 @@ class CIFlow {
124
124
  if (this._workflowLayout(finalConfig) !== 'split') {
125
125
  workflows = [combineWorkflows(workflows, { config: finalConfig, releaseInfo: combinedReleaseInfo })];
126
126
  }
127
- spinner.succeed(chalk.green(`Generated ${workflows.length} workflow file(s)`));
127
+ spinner.succeed(chalk.green(`Generated ${this._workflowCountLabel(workflows.length)}`));
128
128
 
129
129
  // ── 10. Write files ────────────────────────────────────────────────
130
130
  if (this.dryRun) {
@@ -136,7 +136,11 @@ class CIFlow {
136
136
 
137
137
  console.log('\n' + chalk.bold.green('✅ Done! Your GitHub Actions pipeline is ready.'));
138
138
  if (!this.dryRun) {
139
- console.log(chalk.dim(` Workflows ${this.outputDir}`));
139
+ if (workflows.length === 1) {
140
+ console.log(chalk.dim(` Pipeline → ${path.join(this.outputDir, workflows[0].filename)}`));
141
+ } else {
142
+ console.log(chalk.dim(` Workflows → ${this.outputDir}`));
143
+ }
140
144
  console.log(chalk.dim(` Dependabot → ${path.join(this.projectPath, '.github', 'dependabot.yml')}\n`));
141
145
  }
142
146
  } catch (err) {
@@ -263,6 +267,14 @@ class CIFlow {
263
267
  return layout === 'split' ? 'split' : 'single';
264
268
  }
265
269
 
270
+ _workflowCountLabel(count) {
271
+ return `${count} workflow file${count === 1 ? '' : 's'}`;
272
+ }
273
+
274
+ _displayWorkflowPath(filename) {
275
+ return path.posix.join('.github/workflows', filename);
276
+ }
277
+
266
278
  async _interactiveConfirm(config) {
267
279
  const { confirmed } = await inquirer.prompt([
268
280
  {
@@ -377,11 +389,11 @@ class CIFlow {
377
389
  const { content: merged, changes } = smartMergeWorkflow(existing, wf.content);
378
390
 
379
391
  if (changes.length === 0) {
380
- console.log(chalk.dim(` ○ No changes: ${wf.filename}`));
392
+ console.log(chalk.dim(` ○ No changes: ${this._displayWorkflowPath(wf.filename)}`));
381
393
  continue;
382
394
  }
383
395
 
384
- console.log(chalk.yellow(` ↻ Smart-merged: ${wf.filename}`));
396
+ console.log(chalk.yellow(` ↻ Smart-merged: ${this._displayWorkflowPath(wf.filename)}`));
385
397
  for (const c of changes) {
386
398
  console.log(chalk.dim(` • ${c}`));
387
399
  }
@@ -389,10 +401,10 @@ class CIFlow {
389
401
  writeFile(filePath, merged);
390
402
  } else if (exists && this.force) {
391
403
  writeFile(filePath, wf.content);
392
- console.log(chalk.green(` ✔ Overwritten: ${wf.filename}`));
404
+ console.log(chalk.green(` ✔ Overwritten: ${this._displayWorkflowPath(wf.filename)}`));
393
405
  } else {
394
406
  writeFile(filePath, wf.content);
395
- console.log(chalk.green(` ✔ Written: ${wf.filename}`));
407
+ console.log(chalk.green(` ✔ Written: ${this._displayWorkflowPath(wf.filename)}`));
396
408
  }
397
409
  }
398
410
  }
package/tests/run.js CHANGED
@@ -213,6 +213,33 @@ test('Dependabot skips empty npm manifests and uses the bun ecosystem for bun.lo
213
213
  assert(!bunDependabot.updates.some((entry) => entry['package-ecosystem'] === 'npm'));
214
214
  });
215
215
 
216
+ test('Dependabot groups GitHub Actions updates into a single pull request', async () => {
217
+ const projectDir = makeTempDir();
218
+ writeFiles(projectDir, {
219
+ '.github/workflows/ci.yml': [
220
+ 'name: CI',
221
+ 'jobs:',
222
+ ' test:',
223
+ ' runs-on: ubuntu-latest',
224
+ ' steps:',
225
+ ' - uses: actions/checkout@v4',
226
+ ' - uses: actions/setup-node@v4',
227
+ ' - uses: actions/upload-artifact@v4',
228
+ ].join('\n'),
229
+ });
230
+
231
+ const info = await new CodebaseAnalyzer(projectDir).analyse();
232
+ const dependabot = parseWorkflow(new DependabotGenerator(info).generate().content);
233
+ const gha = dependabot.updates.find((entry) => entry['package-ecosystem'] === 'github-actions');
234
+
235
+ assert(gha);
236
+ assert.deepEqual(gha.groups, {
237
+ 'github-actions-updates': {
238
+ patterns: ['*'],
239
+ },
240
+ });
241
+ });
242
+
216
243
  test('GCP App Engine detection documents only the secrets the generated deploy flow uses', async () => {
217
244
  const projectDir = makeTempDir();
218
245
  writeFiles(projectDir, {
@@ -883,6 +910,29 @@ test('CLI smoke test still generates workflows in dry-run mode', () => {
883
910
  assert(output.includes('Done! Your GitHub Actions pipeline is ready.'));
884
911
  });
885
912
 
913
+ test('CLI write output shows the pipeline file path in single-layout mode', () => {
914
+ const projectDir = makeTempDir();
915
+ writeFiles(projectDir, {
916
+ 'package.json': json({
917
+ name: 'cli-write-app',
918
+ version: '1.0.0',
919
+ scripts: {
920
+ test: 'echo ok',
921
+ },
922
+ }),
923
+ });
924
+
925
+ const output = execFileSync(process.execPath, ['bin/ciflow.js', 'generate', '--path', projectDir, '--no-prompt'], {
926
+ cwd: repoRoot,
927
+ encoding: 'utf8',
928
+ stdio: ['ignore', 'pipe', 'pipe'],
929
+ });
930
+
931
+ assert(output.includes('✔ Written: .github/workflows/pipeline.yml'));
932
+ assert(output.includes(`Pipeline → ${path.join(projectDir, '.github', 'workflows', 'pipeline.yml')}`));
933
+ assert(output.includes(`Dependabot → ${path.join(projectDir, '.github', 'dependabot.yml')}`));
934
+ });
935
+
886
936
  test('CLI supports opting back into split workflow files', () => {
887
937
  const projectDir = makeTempDir();
888
938
  writeFiles(projectDir, {