@aspruyt/xfg 5.1.4 → 5.1.6

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.
@@ -135,6 +135,8 @@ function formatValuePlain(val) {
135
135
  return `"${val}"`;
136
136
  if (typeof val === "boolean")
137
137
  return val ? "true" : "false";
138
+ if (typeof val === "object")
139
+ return JSON.stringify(val);
138
140
  return String(val);
139
141
  }
140
142
  function formatRulesetConfigPlain(config) {
@@ -145,6 +147,7 @@ function formatRulesetConfigPlain(config) {
145
147
  * Shared between formatSettingsReportMarkdown and unified-summary's renderSettingsLines.
146
148
  */
147
149
  export function renderRepoSettingsDiffLines(repo, diffLines) {
150
+ const startLength = diffLines.length;
148
151
  for (const setting of repo.settings) {
149
152
  if (setting.oldValue === undefined && setting.newValue === undefined) {
150
153
  continue;
@@ -156,7 +159,15 @@ export function renderRepoSettingsDiffLines(repo, diffLines) {
156
159
  diffLines.push(`! ${setting.name}: ${formatValuePlain(setting.oldValue)} → ${formatValuePlain(setting.newValue)}`);
157
160
  }
158
161
  }
159
- for (const ruleset of repo.rulesets) {
162
+ // Blank line before rulesets if there was content above
163
+ if (repo.rulesets.length > 0 && diffLines.length > startLength) {
164
+ diffLines.push("");
165
+ }
166
+ for (let i = 0; i < repo.rulesets.length; i++) {
167
+ const ruleset = repo.rulesets[i];
168
+ // Blank line between rulesets
169
+ if (i > 0)
170
+ diffLines.push("");
160
171
  if (ruleset.action === "create") {
161
172
  diffLines.push(`+ ruleset "${ruleset.name}"`);
162
173
  if (ruleset.config) {
@@ -175,7 +186,9 @@ export function renderRepoSettingsDiffLines(repo, diffLines) {
175
186
  diffLines.push(`! ${path}: ${formatValuePlain(diff.oldValue)} → ${formatValuePlain(diff.newValue)}`);
176
187
  }
177
188
  else if (diff.action === "remove") {
178
- diffLines.push(`- ${path}`);
189
+ diffLines.push(diff.oldValue !== undefined
190
+ ? `- ${path}: ${formatValuePlain(diff.oldValue)}`
191
+ : `- ${path}`);
179
192
  }
180
193
  }
181
194
  }
@@ -184,6 +197,10 @@ export function renderRepoSettingsDiffLines(repo, diffLines) {
184
197
  diffLines.push(`- ruleset "${ruleset.name}"`);
185
198
  }
186
199
  }
200
+ // Blank line before labels if there was content above
201
+ if (repo.labels.length > 0 && diffLines.length > startLength) {
202
+ diffLines.push("");
203
+ }
187
204
  for (const label of repo.labels) {
188
205
  if (label.action === "create") {
189
206
  diffLines.push(`+ label "${label.name}"`);
@@ -234,8 +251,7 @@ export function formatSettingsReportMarkdown(report, dryRun) {
234
251
  lines.push("> This was a dry run — no changes were applied");
235
252
  lines.push("");
236
253
  }
237
- // Diff block
238
- const diffLines = [];
254
+ // Per-repo sections: heading + diff block
239
255
  for (const repo of report.repos) {
240
256
  if (repo.settings.length === 0 &&
241
257
  repo.rulesets.length === 0 &&
@@ -243,14 +259,16 @@ export function formatSettingsReportMarkdown(report, dryRun) {
243
259
  !repo.error) {
244
260
  continue;
245
261
  }
246
- diffLines.push(`@@ ${repo.repoName} @@`);
247
- renderRepoSettingsDiffLines(repo, diffLines);
248
- }
249
- if (diffLines.length > 0) {
250
- lines.push("```diff");
251
- lines.push(...diffLines);
252
- lines.push("```");
262
+ lines.push(`### ${repo.repoName}`);
253
263
  lines.push("");
264
+ const diffLines = [];
265
+ renderRepoSettingsDiffLines(repo, diffLines);
266
+ if (diffLines.length > 0) {
267
+ lines.push("```diff");
268
+ lines.push(...diffLines);
269
+ lines.push("```");
270
+ lines.push("");
271
+ }
254
272
  }
255
273
  // Summary
256
274
  lines.push(`**${formatSettingsSummary(report.totals)}**`);
@@ -58,27 +58,32 @@ export function formatSyncReportMarkdown(report, dryRun) {
58
58
  lines.push("> This was a dry run — no changes were applied");
59
59
  lines.push("");
60
60
  }
61
- // Diff block
62
- const diffLines = [];
61
+ // Per-repo sections: heading + diff block
63
62
  for (const repo of report.repos) {
64
63
  if (repo.files.length === 0 && !repo.error) {
65
64
  continue;
66
65
  }
67
- diffLines.push(`@@ ${repo.repoName} @@`);
68
- renderSyncLines(repo, diffLines);
69
- }
70
- if (diffLines.length > 0) {
71
- lines.push("```diff");
72
- lines.push(...diffLines);
73
- lines.push("```");
66
+ lines.push(`### ${repo.repoName}`);
74
67
  lines.push("");
68
+ const diffLines = [];
69
+ renderSyncLines(repo, diffLines);
70
+ if (diffLines.length > 0) {
71
+ lines.push("```diff");
72
+ lines.push(...diffLines);
73
+ lines.push("```");
74
+ lines.push("");
75
+ }
75
76
  }
76
77
  // Summary
77
78
  lines.push(`**${formatSyncSummary(report.totals)}**`);
78
79
  return lines.join("\n");
79
80
  }
80
81
  export function renderSyncLines(syncRepo, diffLines) {
81
- for (const file of syncRepo.files) {
82
+ for (let i = 0; i < syncRepo.files.length; i++) {
83
+ const file = syncRepo.files[i];
84
+ // Blank line between files for readability
85
+ if (i > 0)
86
+ diffLines.push("");
82
87
  if (file.action === "create") {
83
88
  diffLines.push(`+ ${file.path}`);
84
89
  }
@@ -165,8 +165,7 @@ export function formatUnifiedSummaryMarkdown(input) {
165
165
  addRepo(r.repoName);
166
166
  for (const r of input.settings?.repos ?? [])
167
167
  addRepo(r.repoName);
168
- // Diff block
169
- const diffLines = [];
168
+ // Per-repo sections: heading + diff block
170
169
  for (const repoName of allRepos) {
171
170
  const lcAction = lifecycleByRepo.get(repoName);
172
171
  const syncRepo = syncByRepo.get(repoName);
@@ -180,19 +179,27 @@ export function formatUnifiedSummaryMarkdown(input) {
180
179
  settingsRepo.error);
181
180
  if (!hasLcChange && !hasSyncChanges && !hasSettingsChanges)
182
181
  continue;
183
- diffLines.push(`@@ ${repoName} @@`);
182
+ lines.push(`### ${repoName}`);
183
+ lines.push("");
184
+ const diffLines = [];
184
185
  if (lcAction)
185
186
  renderLifecycleLines(lcAction, diffLines);
187
+ // Blank line between lifecycle and sync sections
188
+ if (hasLcChange && hasSyncChanges)
189
+ diffLines.push("");
186
190
  if (syncRepo)
187
191
  renderSyncLines(syncRepo, diffLines);
192
+ // Blank line between files and settings sections
193
+ if (hasSyncChanges && hasSettingsChanges)
194
+ diffLines.push("");
188
195
  if (settingsRepo)
189
196
  renderRepoSettingsDiffLines(settingsRepo, diffLines);
190
- }
191
- if (diffLines.length > 0) {
192
- lines.push("```diff");
193
- lines.push(...diffLines);
194
- lines.push("```");
195
- lines.push("");
197
+ if (diffLines.length > 0) {
198
+ lines.push("```diff");
199
+ lines.push(...diffLines);
200
+ lines.push("```");
201
+ lines.push("");
202
+ }
196
203
  }
197
204
  // Combined summary
198
205
  lines.push(`**${formatCombinedSummary(input)}**`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aspruyt/xfg",
3
- "version": "5.1.4",
3
+ "version": "5.1.6",
4
4
  "description": "Manage files, settings, and repositories across GitHub, Azure DevOps, and GitLab — declaratively, from a single YAML config",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",