@aspruyt/xfg 3.9.3 → 3.9.5

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/README.md CHANGED
@@ -8,7 +8,9 @@
8
8
  [![docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://anthony-spruyt.github.io/xfg/)
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
10
 
11
- A CLI tool for repository-as-code. Sync files and manage settings across GitHub, Azure DevOps, and GitLab.
11
+ Manage files, settings, and repositories across GitHub, Azure DevOps, and GitLab — declaratively, from a single YAML config.
12
+
13
+ Define your organization's standards once. xfg creates PRs to sync config files, applies repository settings and rulesets via API, and can even create, fork, or migrate repositories — all from one config file.
12
14
 
13
15
  **[Full Documentation](https://anthony-spruyt.github.io/xfg/)**
14
16
 
@@ -48,7 +50,7 @@ gh auth login
48
50
  # Sync files across repos
49
51
  xfg sync --config ./config.yaml
50
52
 
51
- # Apply repository settings
53
+ # Apply repository settings and rulesets
52
54
  xfg settings --config ./config.yaml
53
55
  ```
54
56
 
@@ -56,7 +58,8 @@ xfg settings --config ./config.yaml
56
58
 
57
59
  ```yaml
58
60
  # sync-config.yaml
59
- id: my-org-config
61
+ id: my-org-standards
62
+
60
63
  files:
61
64
  .prettierrc.json:
62
65
  content:
@@ -69,6 +72,7 @@ settings:
69
72
  allowSquashMerge: true
70
73
  deleteBranchOnMerge: true
71
74
  vulnerabilityAlerts: true
75
+ secretScanning: true
72
76
 
73
77
  rulesets:
74
78
  main-protection:
@@ -82,6 +86,10 @@ settings:
82
86
  - type: pull_request
83
87
  parameters:
84
88
  requiredApprovingReviewCount: 1
89
+ - type: required_status_checks
90
+ parameters:
91
+ requiredStatusChecks:
92
+ - context: "ci/build"
85
93
 
86
94
  repos:
87
95
  - git:
@@ -89,8 +97,8 @@ repos:
89
97
  - git@github.com:your-org/backend-api.git
90
98
  ```
91
99
 
92
- **Result:** PRs are created with `.prettierrc.json` files, and repos get standardized merge options, security settings, and branch protection rules.
100
+ **Result:** PRs are created with `.prettierrc.json` files, and repos get standardized merge options, security settings, and branch protection rulesets.
93
101
 
94
102
  ## Documentation
95
103
 
96
- See **[anthony-spruyt.github.io/xfg](https://anthony-spruyt.github.io/xfg/)** for configuration reference, examples, platform setup, and troubleshooting.
104
+ See **[anthony-spruyt.github.io/xfg](https://anthony-spruyt.github.io/xfg/)** for the full feature list, configuration reference, examples, platform setup, and troubleshooting.
@@ -27,7 +27,7 @@ function addSharedOptions(cmd) {
27
27
  // =============================================================================
28
28
  program
29
29
  .name("xfg")
30
- .description("Sync files and manage settings across repositories")
30
+ .description("Manage files, settings, and repositories across GitHub, Azure DevOps, and GitLab")
31
31
  .version(packageJson.version);
32
32
  // Sync command (file synchronization)
33
33
  const syncCommand = new Command("sync")
@@ -192,7 +192,7 @@ async function processRulesets(repos, config, options, processor, repoProcessor,
192
192
  /**
193
193
  * Process repo settings for all configured repositories.
194
194
  */
195
- async function processRepoSettings(repos, config, options, processorFactory, results, collector, lifecycleSkipped) {
195
+ async function processRepoSettings(repos, config, options, processorFactory, results, collector, lifecycleSkipped, indexOffset) {
196
196
  if (repos.length === 0) {
197
197
  return;
198
198
  }
@@ -200,6 +200,7 @@ async function processRepoSettings(repos, config, options, processorFactory, res
200
200
  console.log(`\nProcessing repo settings for ${repos.length} repositories\n`);
201
201
  for (let i = 0; i < repos.length; i++) {
202
202
  const repoConfig = repos[i];
203
+ const current = indexOffset + i + 1;
203
204
  if (lifecycleSkipped.has(repoConfig.git)) {
204
205
  continue;
205
206
  }
@@ -210,7 +211,7 @@ async function processRepoSettings(repos, config, options, processorFactory, res
210
211
  });
211
212
  }
212
213
  catch (error) {
213
- logger.error(i + 1, repoConfig.git, String(error));
214
+ logger.error(current, repoConfig.git, String(error));
214
215
  collector.appendError(repoConfig.git, error);
215
216
  continue;
216
217
  }
@@ -220,14 +221,14 @@ async function processRepoSettings(repos, config, options, processorFactory, res
220
221
  dryRun: options.dryRun,
221
222
  });
222
223
  if (result.planOutput && result.planOutput.lines.length > 0) {
223
- console.log(`\n ${chalk.bold(repoName)}:`);
224
- console.log(" Repo Settings:");
224
+ logger.info("");
225
+ logger.info(chalk.bold(`${repoName} - Repo Settings:`));
225
226
  for (const line of result.planOutput.lines) {
226
- console.log(line);
227
+ logger.info(line);
227
228
  }
228
229
  if (result.warnings && result.warnings.length > 0) {
229
230
  for (const warning of result.warnings) {
230
- console.log(chalk.yellow(` ⚠️ Warning: ${warning}`));
231
+ logger.info(chalk.yellow(`Warning: ${warning}`));
231
232
  }
232
233
  }
233
234
  }
@@ -235,10 +236,10 @@ async function processRepoSettings(repos, config, options, processorFactory, res
235
236
  // Silent skip
236
237
  }
237
238
  else if (result.success) {
238
- console.log(chalk.green(` ✓ ${repoName}: ${result.message}`));
239
+ logger.success(current, repoName, result.message);
239
240
  }
240
241
  else {
241
- console.log(chalk.red(` ✗ ${repoName}: ${result.message}`));
242
+ logger.error(current, repoName, result.message);
242
243
  }
243
244
  if (!result.skipped) {
244
245
  const existing = results.find((r) => r.repoName === repoName);
@@ -259,7 +260,7 @@ async function processRepoSettings(repos, config, options, processorFactory, res
259
260
  }
260
261
  }
261
262
  catch (error) {
262
- logger.error(i + 1, repoName, String(error));
263
+ logger.error(current, repoName, String(error));
263
264
  collector.appendError(repoName, error);
264
265
  }
265
266
  }
@@ -312,7 +313,7 @@ export async function runSettings(options, processorFactory = defaultRulesetProc
312
313
  const allRepos = [...reposWithRulesets, ...reposWithRepoSettings];
313
314
  const lifecycleSkipped = await runLifecycleChecks(allRepos, config, options, lm, results, collector, tokenManager);
314
315
  await processRulesets(reposWithRulesets, config, options, processor, repoProcessor, results, collector, lifecycleSkipped);
315
- await processRepoSettings(reposWithRepoSettings, config, options, repoSettingsProcessorFactory, results, collector, lifecycleSkipped);
316
+ await processRepoSettings(reposWithRepoSettings, config, options, repoSettingsProcessorFactory, results, collector, lifecycleSkipped, reposWithRulesets.length);
316
317
  console.log("");
317
318
  const report = buildSettingsReport(collector.getAll());
318
319
  const lines = formatSettingsReportCLI(report);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@aspruyt/xfg",
3
- "version": "3.9.3",
4
- "description": "CLI tool for repository-as-code: sync files and manage settings across GitHub, Azure DevOps, and GitLab",
3
+ "version": "3.9.5",
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",
7
7
  "bin": {