cistack 3.2.0 → 4.0.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/src/index.js CHANGED
@@ -42,17 +42,16 @@ class CIFlow {
42
42
  try {
43
43
  // ── 1. Load cistack.config.js ─────────────────────────────────────
44
44
  const configLoader = new ConfigLoader(this.projectPath);
45
- const userConfig = configLoader.load();
45
+ const userConfig = await configLoader.load();
46
46
  if (Object.keys(userConfig).length > 0) {
47
47
  spinner.info(chalk.cyan('cistack.config.js loaded'));
48
- spinner.start('Scanning project...');
49
- // Allow config to override outputDir
50
48
  if (userConfig.outputDir) {
51
49
  this.outputDir = path.join(this.projectPath, userConfig.outputDir);
52
50
  }
53
51
  }
54
52
 
55
53
  // ── 2. Analyse the codebase ───────────────────────────────────────
54
+ if (!spinner.isSpinning) spinner.start('Scanning project...');
56
55
  const analyzer = new CodebaseAnalyzer(this.projectPath, { verbose: this.verbose });
57
56
  const codebaseInfo = await analyzer.analyse();
58
57
  spinner.succeed(chalk.green('Project scanned'));
@@ -81,13 +80,22 @@ class CIFlow {
81
80
  frameworks,
82
81
  languages,
83
82
  testing,
83
+ releaseInfo,
84
84
  envVars,
85
85
  monorepoPackages,
86
+ lockFiles: codebaseInfo.lockFiles,
87
+ defaultBranch: codebaseInfo.defaultBranch,
88
+ currentBranch: codebaseInfo.currentBranch,
86
89
  _config: userConfig,
87
90
  });
88
91
 
89
92
  // ── 5. Print summary ───────────────────────────────────────────────
90
- this._printSummary(finalConfig, releaseInfo, envVars, monorepoPackages);
93
+ this._printSummary(
94
+ finalConfig,
95
+ finalConfig.releaseInfo || releaseInfo,
96
+ finalConfig.envVars || envVars,
97
+ finalConfig.monorepoPackages || monorepoPackages
98
+ );
91
99
 
92
100
  // ── 6. Optional interactive confirmation ──────────────────────────
93
101
  if (this.prompt) {
@@ -104,10 +112,11 @@ class CIFlow {
104
112
  const dependabotGen = new DependabotGenerator(codebaseInfo);
105
113
  const dependabotFile = dependabotGen.generate();
106
114
 
107
- // ── 9. Generate release.yml (if release tooling detected) ─────────
115
+ // ── 9. Generate release.yml (if release tooling detected or configured)
108
116
  let releaseWorkflow = null;
109
- if (releaseInfo) {
110
- const releaseGen = new ReleaseGenerator(releaseInfo, finalConfig, this.projectPath);
117
+ const combinedReleaseInfo = finalConfig.releaseInfo || releaseInfo;
118
+ if (combinedReleaseInfo) {
119
+ const releaseGen = new ReleaseGenerator(combinedReleaseInfo, finalConfig, this.projectPath);
111
120
  releaseWorkflow = releaseGen.generate();
112
121
  if (releaseWorkflow) workflows.push(releaseWorkflow);
113
122
  }
@@ -388,19 +397,15 @@ class CIFlow {
388
397
  ensureDir(githubDir);
389
398
 
390
399
  if (exists && !this.force) {
400
+ // dependabot.yml has a fixed schema, simpler to just overwrite or keep if identical
391
401
  const existing = fs.readFileSync(filePath, 'utf8');
392
- const { content: merged, changes } = smartMergeWorkflow(existing, dependabotFile.content);
393
-
394
- if (changes.length === 0) {
402
+ if (existing.trim() === dependabotFile.content.trim()) {
395
403
  console.log(chalk.dim(` ○ No changes: dependabot.yml`));
396
404
  return;
397
405
  }
398
-
399
- writeFile(filePath, merged);
400
- console.log(chalk.yellow(` ↻ Smart-merged: dependabot.yml`));
401
- for (const c of changes) {
402
- console.log(chalk.dim(` • ${c}`));
403
- }
406
+
407
+ writeFile(filePath, dependabotFile.content);
408
+ console.log(chalk.yellow(` ↻ Updated: dependabot.yml (schema mismatch for smart-merge)`));
404
409
  } else {
405
410
  writeFile(filePath, dependabotFile.content);
406
411
  console.log(chalk.green(` ✔ Written: .github/dependabot.yml`));
@@ -129,16 +129,17 @@ function _mergeJob(existJob, genJob, jobId) {
129
129
  }
130
130
  }
131
131
 
132
- // Merge steps by name
132
+ // Merge steps
133
133
  if (genJob.steps) {
134
- const existStepsByName = {};
135
- for (const s of (existJob.steps || [])) {
136
- if (s.name) existStepsByName[s.name] = s;
137
- }
138
-
139
134
  const mergedSteps = [];
140
135
  for (const genStep of genJob.steps) {
141
- const existStep = existStepsByName[genStep.name];
136
+ // Find matches by name, uses, or id
137
+ const existStep = (existJob.steps || []).find(s =>
138
+ (genStep.name && s.name === genStep.name) ||
139
+ (genStep.id && s.id === genStep.id) ||
140
+ (genStep.uses && s.uses === genStep.uses)
141
+ );
142
+
142
143
  if (!existStep) {
143
144
  mergedSteps.push(genStep);
144
145
  jobChanges.push(` job "${jobId}" → added step "${genStep.name}"`);
@@ -153,6 +154,19 @@ function _mergeJob(existJob, genJob, jobId) {
153
154
  }
154
155
  }
155
156
  }
157
+ // Append any existing steps that were NOT matched by a generated step
158
+ // This ensures user customizations are preserved.
159
+ for (const existStep of (existJob.steps || [])) {
160
+ const isMatched = genJob.steps.some((genStep) =>
161
+ (genStep.name && existStep.name === genStep.name) ||
162
+ (genStep.id && existStep.id === genStep.id) ||
163
+ (genStep.uses && existStep.uses === genStep.uses)
164
+ );
165
+ if (!isMatched) {
166
+ mergedSteps.push(existStep);
167
+ }
168
+ }
169
+
156
170
  merged.steps = mergedSteps;
157
171
  }
158
172