@aspruyt/xfg 4.0.2 → 4.0.4
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/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +0 -6
- package/dist/cli/program.js +3 -2
- package/dist/cli/settings-report-builder.js +4 -4
- package/dist/cli/sync-command.js +72 -36
- package/dist/cli/sync-report-builder.d.ts +2 -6
- package/dist/cli/types.d.ts +2 -14
- package/dist/cli/types.js +1 -9
- package/dist/config/file-reference-resolver.js +13 -23
- package/dist/config/formatter.d.ts +0 -6
- package/dist/config/formatter.js +0 -9
- package/dist/config/index.d.ts +1 -2
- package/dist/config/index.js +0 -2
- package/dist/config/loader.d.ts +1 -1
- package/dist/config/loader.js +3 -3
- package/dist/config/normalizer.d.ts +1 -1
- package/dist/config/normalizer.js +44 -57
- package/dist/config/validator.d.ts +1 -1
- package/dist/config/validator.js +120 -121
- package/dist/config/validators/file-validator.d.ts +2 -4
- package/dist/config/validators/file-validator.js +3 -7
- package/dist/config/validators/repo-settings-validator.js +1 -1
- package/dist/config/validators/ruleset-validator.js +28 -12
- package/dist/index.d.ts +3 -1
- package/dist/index.js +0 -1
- package/dist/lifecycle/ado-migration-source.d.ts +2 -1
- package/dist/lifecycle/ado-migration-source.js +7 -5
- package/dist/lifecycle/github-lifecycle-provider.d.ts +6 -3
- package/dist/lifecycle/github-lifecycle-provider.js +29 -19
- package/dist/lifecycle/lifecycle-formatter.js +2 -1
- package/dist/lifecycle/lifecycle-helpers.d.ts +5 -1
- package/dist/lifecycle/lifecycle-helpers.js +4 -4
- package/dist/lifecycle/repo-lifecycle-factory.d.ts +4 -4
- package/dist/lifecycle/repo-lifecycle-factory.js +12 -9
- package/dist/lifecycle/repo-lifecycle-manager.d.ts +4 -1
- package/dist/lifecycle/repo-lifecycle-manager.js +11 -7
- package/dist/lifecycle/types.d.ts +0 -15
- package/dist/output/github-summary.d.ts +6 -5
- package/dist/output/github-summary.js +36 -52
- package/dist/output/index.d.ts +2 -2
- package/dist/output/index.js +1 -1
- package/dist/output/lifecycle-report.d.ts +2 -12
- package/dist/output/lifecycle-report.js +18 -35
- package/dist/output/settings-report.d.ts +4 -4
- package/dist/output/settings-report.js +6 -6
- package/dist/output/sync-report.d.ts +4 -6
- package/dist/output/sync-report.js +2 -2
- package/dist/output/unified-summary.d.ts +1 -0
- package/dist/output/unified-summary.js +8 -8
- package/dist/settings/base-processor.d.ts +1 -1
- package/dist/settings/base-processor.js +1 -1
- package/dist/settings/index.d.ts +3 -3
- package/dist/settings/index.js +3 -3
- package/dist/settings/labels/diff.js +3 -2
- package/dist/settings/labels/formatter.js +3 -3
- package/dist/settings/labels/github-labels-strategy.d.ts +2 -23
- package/dist/settings/labels/github-labels-strategy.js +8 -28
- package/dist/settings/labels/index.d.ts +1 -0
- package/dist/settings/labels/index.js +2 -0
- package/dist/settings/labels/processor.d.ts +2 -2
- package/dist/settings/labels/processor.js +3 -4
- package/dist/settings/labels/types.d.ts +0 -3
- package/dist/settings/repo-settings/diff.d.ts +1 -1
- package/dist/settings/repo-settings/diff.js +2 -2
- package/dist/settings/repo-settings/formatter.d.ts +1 -1
- package/dist/settings/repo-settings/formatter.js +4 -4
- package/dist/settings/repo-settings/github-repo-settings-strategy.d.ts +2 -7
- package/dist/settings/repo-settings/github-repo-settings-strategy.js +9 -17
- package/dist/settings/repo-settings/index.d.ts +1 -0
- package/dist/settings/repo-settings/index.js +2 -0
- package/dist/settings/repo-settings/processor.d.ts +2 -2
- package/dist/settings/repo-settings/processor.js +5 -6
- package/dist/settings/repo-settings/types.d.ts +9 -13
- package/dist/settings/repo-settings/types.js +1 -14
- package/dist/settings/rulesets/diff-algorithm.d.ts +0 -1
- package/dist/settings/rulesets/diff-algorithm.js +6 -8
- package/dist/settings/rulesets/formatter.js +15 -51
- package/dist/settings/rulesets/github-ruleset-strategy.d.ts +2 -20
- package/dist/settings/rulesets/github-ruleset-strategy.js +6 -30
- package/dist/settings/rulesets/index.d.ts +2 -1
- package/dist/settings/rulesets/index.js +3 -1
- package/dist/settings/rulesets/processor.d.ts +2 -2
- package/dist/settings/rulesets/processor.js +3 -4
- package/dist/{vcs → shared}/branch-utils.js +5 -4
- package/dist/shared/command-executor.d.ts +2 -1
- package/dist/shared/command-executor.js +9 -5
- package/dist/shared/env.d.ts +6 -6
- package/dist/shared/env.js +10 -17
- package/dist/shared/errors.d.ts +26 -0
- package/dist/shared/errors.js +34 -0
- package/dist/shared/gh-api-utils.d.ts +21 -14
- package/dist/shared/gh-api-utils.js +33 -22
- package/dist/shared/index.d.ts +9 -2
- package/dist/shared/index.js +16 -2
- package/dist/shared/logger.d.ts +24 -1
- package/dist/shared/logger.js +8 -3
- package/dist/shared/repo-detector.js +9 -11
- package/dist/shared/retry-utils.d.ts +5 -7
- package/dist/shared/retry-utils.js +3 -10
- package/dist/shared/shell-utils.d.ts +0 -3
- package/dist/shared/shell-utils.js +2 -4
- package/dist/shared/type-guards.d.ts +2 -9
- package/dist/shared/type-guards.js +0 -6
- package/dist/shared/xfg-template.d.ts +2 -2
- package/dist/shared/xfg-template.js +2 -1
- package/dist/sync/auth-options-builder.d.ts +3 -2
- package/dist/sync/auth-options-builder.js +14 -10
- package/dist/sync/branch-manager.d.ts +12 -7
- package/dist/sync/branch-manager.js +4 -7
- package/dist/sync/commit-message.d.ts +1 -1
- package/dist/sync/commit-push-manager.d.ts +8 -2
- package/dist/sync/commit-push-manager.js +6 -5
- package/dist/sync/file-sync-orchestrator.js +17 -21
- package/dist/sync/file-writer.js +3 -5
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/manifest-manager.d.ts +1 -0
- package/dist/sync/manifest.d.ts +4 -7
- package/dist/sync/manifest.js +42 -45
- package/dist/sync/repository-processor.d.ts +5 -2
- package/dist/sync/repository-processor.js +11 -17
- package/dist/sync/repository-session.js +2 -1
- package/dist/sync/sync-workflow.d.ts +2 -2
- package/dist/sync/sync-workflow.js +16 -23
- package/dist/sync/types.d.ts +20 -25
- package/dist/vcs/authenticated-git-ops.d.ts +3 -4
- package/dist/vcs/authenticated-git-ops.js +5 -1
- package/dist/vcs/azure-pr-strategy.d.ts +6 -1
- package/dist/vcs/azure-pr-strategy.js +38 -31
- package/dist/vcs/commit-strategy-selector.d.ts +10 -19
- package/dist/vcs/commit-strategy-selector.js +8 -24
- package/dist/vcs/git-commit-strategy.d.ts +1 -1
- package/dist/vcs/git-commit-strategy.js +1 -3
- package/dist/vcs/git-ops.d.ts +4 -8
- package/dist/vcs/git-ops.js +18 -22
- package/dist/vcs/github-app-token-manager.js +9 -8
- package/dist/vcs/github-pr-strategy.js +18 -11
- package/dist/vcs/gitlab-pr-strategy.d.ts +1 -1
- package/dist/vcs/gitlab-pr-strategy.js +14 -7
- package/dist/vcs/graphql-commit-strategy.d.ts +1 -7
- package/dist/vcs/graphql-commit-strategy.js +24 -32
- package/dist/vcs/index.d.ts +2 -1
- package/dist/vcs/pr-creator.d.ts +6 -9
- package/dist/vcs/pr-strategy-factory.d.ts +1 -1
- package/dist/vcs/pr-strategy-factory.js +2 -1
- package/dist/vcs/pr-strategy.d.ts +1 -1
- package/dist/vcs/pr-strategy.js +2 -3
- package/dist/vcs/types.d.ts +6 -10
- package/package.json +2 -2
- package/dist/config/errors.d.ts +0 -9
- package/dist/config/errors.js +0 -11
- /package/dist/{vcs → shared}/branch-utils.d.ts +0 -0
|
@@ -37,23 +37,23 @@ function formatLifecycleSummary(totals) {
|
|
|
37
37
|
export function hasLifecycleChanges(report) {
|
|
38
38
|
return report.actions.some((a) => a.action !== "existed");
|
|
39
39
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Render action diff lines from lifecycle actions (shared between CLI and Markdown).
|
|
42
|
+
*/
|
|
43
|
+
function renderActionDiffLines(actions) {
|
|
44
44
|
const lines = [];
|
|
45
|
-
for (const action of
|
|
45
|
+
for (const action of actions) {
|
|
46
46
|
if (action.action === "existed")
|
|
47
47
|
continue;
|
|
48
48
|
switch (action.action) {
|
|
49
49
|
case "created":
|
|
50
|
-
lines.push(
|
|
50
|
+
lines.push(`+ CREATE ${action.repoName}`);
|
|
51
51
|
break;
|
|
52
52
|
case "forked":
|
|
53
|
-
lines.push(
|
|
53
|
+
lines.push(`+ FORK ${action.upstream ?? "upstream"} -> ${action.repoName}`);
|
|
54
54
|
break;
|
|
55
55
|
case "migrated":
|
|
56
|
-
lines.push(
|
|
56
|
+
lines.push(`+ MIGRATE ${action.source ?? "source"} -> ${action.repoName}`);
|
|
57
57
|
break;
|
|
58
58
|
}
|
|
59
59
|
if (action.settings) {
|
|
@@ -65,8 +65,14 @@ export function formatLifecycleReportCLI(report) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
+
return lines;
|
|
69
|
+
}
|
|
70
|
+
export function formatLifecycleReportCLI(report) {
|
|
71
|
+
if (!hasLifecycleChanges(report)) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const lines = renderActionDiffLines(report.actions).map((line) => line.startsWith("+") ? chalk.green(line) : line);
|
|
68
75
|
lines.push("");
|
|
69
|
-
// Summary
|
|
70
76
|
lines.push(formatLifecycleSummary(report.totals));
|
|
71
77
|
return lines;
|
|
72
78
|
}
|
|
@@ -86,30 +92,7 @@ export function formatLifecycleReportMarkdown(report, dryRun) {
|
|
|
86
92
|
lines.push("");
|
|
87
93
|
}
|
|
88
94
|
// Diff block
|
|
89
|
-
const diffLines =
|
|
90
|
-
for (const action of report.actions) {
|
|
91
|
-
if (action.action === "existed")
|
|
92
|
-
continue;
|
|
93
|
-
switch (action.action) {
|
|
94
|
-
case "created":
|
|
95
|
-
diffLines.push(`+ CREATE ${action.repoName}`);
|
|
96
|
-
break;
|
|
97
|
-
case "forked":
|
|
98
|
-
diffLines.push(`+ FORK ${action.upstream ?? "upstream"} -> ${action.repoName}`);
|
|
99
|
-
break;
|
|
100
|
-
case "migrated":
|
|
101
|
-
diffLines.push(`+ MIGRATE ${action.source ?? "source"} -> ${action.repoName}`);
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
if (action.settings) {
|
|
105
|
-
if (action.settings.visibility) {
|
|
106
|
-
diffLines.push(` visibility: ${action.settings.visibility}`);
|
|
107
|
-
}
|
|
108
|
-
if (action.settings.description) {
|
|
109
|
-
diffLines.push(` description: "${action.settings.description}"`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
95
|
+
const diffLines = renderActionDiffLines(report.actions);
|
|
113
96
|
if (diffLines.length > 0) {
|
|
114
97
|
lines.push("```diff");
|
|
115
98
|
lines.push(...diffLines);
|
|
@@ -120,9 +103,9 @@ export function formatLifecycleReportMarkdown(report, dryRun) {
|
|
|
120
103
|
lines.push(`**${formatLifecycleSummary(report.totals)}**`);
|
|
121
104
|
return lines.join("\n");
|
|
122
105
|
}
|
|
123
|
-
export function writeLifecycleReportSummary(report, dryRun) {
|
|
106
|
+
export function writeLifecycleReportSummary(report, dryRun, summaryPath) {
|
|
124
107
|
const markdown = formatLifecycleReportMarkdown(report, dryRun);
|
|
125
108
|
if (!markdown)
|
|
126
109
|
return;
|
|
127
|
-
writeGitHubStepSummary(markdown);
|
|
110
|
+
writeGitHubStepSummary(markdown, summaryPath);
|
|
128
111
|
}
|
|
@@ -4,8 +4,8 @@ export interface SettingsReport {
|
|
|
4
4
|
repos: RepoChanges[];
|
|
5
5
|
totals: {
|
|
6
6
|
settings: {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
create: number;
|
|
8
|
+
update: number;
|
|
9
9
|
};
|
|
10
10
|
rulesets: {
|
|
11
11
|
create: number;
|
|
@@ -28,7 +28,7 @@ export interface RepoChanges {
|
|
|
28
28
|
}
|
|
29
29
|
export interface SettingChange {
|
|
30
30
|
name: string;
|
|
31
|
-
action: "
|
|
31
|
+
action: "create" | "update";
|
|
32
32
|
oldValue?: unknown;
|
|
33
33
|
newValue: unknown;
|
|
34
34
|
}
|
|
@@ -64,4 +64,4 @@ export declare function formatSettingsReportCLI(report: SettingsReport): string[
|
|
|
64
64
|
*/
|
|
65
65
|
export declare function renderRepoSettingsDiffLines(repo: RepoChanges, diffLines: string[]): void;
|
|
66
66
|
export declare function formatSettingsReportMarkdown(report: SettingsReport, dryRun: boolean): string;
|
|
67
|
-
export declare function writeSettingsReportSummary(report: SettingsReport, dryRun: boolean): void;
|
|
67
|
+
export declare function writeSettingsReportSummary(report: SettingsReport, dryRun: boolean, summaryPath: string | undefined): void;
|
|
@@ -74,8 +74,8 @@ export function formatCountEntry(noun, pluralNoun, counts) {
|
|
|
74
74
|
function formatSettingsSummary(totals) {
|
|
75
75
|
const parts = [];
|
|
76
76
|
const settingsEntry = formatCountEntry("setting", "settings", [
|
|
77
|
-
{ label: "to
|
|
78
|
-
{ label: "to
|
|
77
|
+
{ label: "to create", value: totals.settings.create },
|
|
78
|
+
{ label: "to update", value: totals.settings.update },
|
|
79
79
|
]);
|
|
80
80
|
if (settingsEntry)
|
|
81
81
|
parts.push(settingsEntry);
|
|
@@ -115,7 +115,7 @@ export function formatSettingsReportCLI(report) {
|
|
|
115
115
|
if (setting.oldValue === undefined && setting.newValue === undefined) {
|
|
116
116
|
continue;
|
|
117
117
|
}
|
|
118
|
-
if (setting.action === "
|
|
118
|
+
if (setting.action === "create") {
|
|
119
119
|
lines.push(chalk.green(` + ${setting.name}: ${formatValuePlain(setting.newValue)}`));
|
|
120
120
|
}
|
|
121
121
|
else {
|
|
@@ -211,7 +211,7 @@ export function renderRepoSettingsDiffLines(repo, diffLines) {
|
|
|
211
211
|
if (setting.oldValue === undefined && setting.newValue === undefined) {
|
|
212
212
|
continue;
|
|
213
213
|
}
|
|
214
|
-
if (setting.action === "
|
|
214
|
+
if (setting.action === "create") {
|
|
215
215
|
diffLines.push(`+ ${setting.name}: ${formatValuePlain(setting.newValue)}`);
|
|
216
216
|
}
|
|
217
217
|
else {
|
|
@@ -318,7 +318,7 @@ export function formatSettingsReportMarkdown(report, dryRun) {
|
|
|
318
318
|
lines.push(`**${formatSettingsSummary(report.totals)}**`);
|
|
319
319
|
return lines.join("\n");
|
|
320
320
|
}
|
|
321
|
-
export function writeSettingsReportSummary(report, dryRun) {
|
|
321
|
+
export function writeSettingsReportSummary(report, dryRun, summaryPath) {
|
|
322
322
|
const markdown = formatSettingsReportMarkdown(report, dryRun);
|
|
323
|
-
writeGitHubStepSummary(markdown);
|
|
323
|
+
writeGitHubStepSummary(markdown, summaryPath);
|
|
324
324
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { FileChangeDetail } from "../sync/types.js";
|
|
2
|
+
export type ReportFileChange = FileChangeDetail;
|
|
1
3
|
export interface SyncReport {
|
|
2
4
|
repos: RepoFileChanges[];
|
|
3
5
|
totals: {
|
|
@@ -10,15 +12,11 @@ export interface SyncReport {
|
|
|
10
12
|
}
|
|
11
13
|
export interface RepoFileChanges {
|
|
12
14
|
repoName: string;
|
|
13
|
-
files:
|
|
15
|
+
files: ReportFileChange[];
|
|
14
16
|
prUrl?: string;
|
|
15
17
|
mergeOutcome?: "manual" | "auto" | "force" | "direct";
|
|
16
18
|
error?: string;
|
|
17
19
|
}
|
|
18
|
-
export interface FileChange {
|
|
19
|
-
path: string;
|
|
20
|
-
action: "create" | "update" | "delete";
|
|
21
|
-
}
|
|
22
20
|
export declare function formatSyncReportCLI(report: SyncReport): string[];
|
|
23
21
|
export declare function formatSyncReportMarkdown(report: SyncReport, dryRun: boolean): string;
|
|
24
|
-
export declare function writeSyncReportSummary(report: SyncReport, dryRun: boolean): void;
|
|
22
|
+
export declare function writeSyncReportSummary(report: SyncReport, dryRun: boolean, summaryPath: string | undefined): void;
|
|
@@ -90,7 +90,7 @@ export function formatSyncReportMarkdown(report, dryRun) {
|
|
|
90
90
|
lines.push(`**${formatSyncSummary(report.totals)}**`);
|
|
91
91
|
return lines.join("\n");
|
|
92
92
|
}
|
|
93
|
-
export function writeSyncReportSummary(report, dryRun) {
|
|
93
|
+
export function writeSyncReportSummary(report, dryRun, summaryPath) {
|
|
94
94
|
const markdown = formatSyncReportMarkdown(report, dryRun);
|
|
95
|
-
writeGitHubStepSummary(markdown);
|
|
95
|
+
writeGitHubStepSummary(markdown, summaryPath);
|
|
96
96
|
}
|
|
@@ -6,6 +6,7 @@ interface UnifiedSummaryInput {
|
|
|
6
6
|
sync?: SyncReport;
|
|
7
7
|
settings?: SettingsReport;
|
|
8
8
|
dryRun: boolean;
|
|
9
|
+
summaryPath?: string | undefined;
|
|
9
10
|
}
|
|
10
11
|
export declare function formatUnifiedSummaryMarkdown(input: UnifiedSummaryInput): string;
|
|
11
12
|
export declare function writeUnifiedSummary(input: UnifiedSummaryInput): void;
|
|
@@ -42,10 +42,13 @@ function formatCombinedSummary(input) {
|
|
|
42
42
|
if (input.settings) {
|
|
43
43
|
const t = input.settings.totals;
|
|
44
44
|
const settingsEntry = formatCountEntry("setting", "settings", [
|
|
45
|
-
{ label: selectLabel(dry, "added", "to add"), value: t.settings.add },
|
|
46
45
|
{
|
|
47
|
-
label: selectLabel(dry, "
|
|
48
|
-
value: t.settings.
|
|
46
|
+
label: selectLabel(dry, "created", "to create"),
|
|
47
|
+
value: t.settings.create,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: selectLabel(dry, "updated", "to update"),
|
|
51
|
+
value: t.settings.update,
|
|
49
52
|
},
|
|
50
53
|
]);
|
|
51
54
|
if (settingsEntry)
|
|
@@ -143,9 +146,6 @@ function renderSyncLines(syncRepo, diffLines) {
|
|
|
143
146
|
diffLines.push(`- Error: ${syncRepo.error}`);
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
|
-
function renderSettingsLines(settingsRepo, diffLines) {
|
|
147
|
-
renderRepoSettingsDiffLines(settingsRepo, diffLines);
|
|
148
|
-
}
|
|
149
149
|
// =============================================================================
|
|
150
150
|
// Markdown Formatter
|
|
151
151
|
// =============================================================================
|
|
@@ -201,7 +201,7 @@ export function formatUnifiedSummaryMarkdown(input) {
|
|
|
201
201
|
if (syncRepo)
|
|
202
202
|
renderSyncLines(syncRepo, diffLines);
|
|
203
203
|
if (settingsRepo)
|
|
204
|
-
|
|
204
|
+
renderRepoSettingsDiffLines(settingsRepo, diffLines);
|
|
205
205
|
}
|
|
206
206
|
if (diffLines.length > 0) {
|
|
207
207
|
lines.push("```diff");
|
|
@@ -220,5 +220,5 @@ export function writeUnifiedSummary(input) {
|
|
|
220
220
|
const markdown = formatUnifiedSummaryMarkdown(input);
|
|
221
221
|
if (!markdown)
|
|
222
222
|
return;
|
|
223
|
-
writeGitHubStepSummary(markdown);
|
|
223
|
+
writeGitHubStepSummary(markdown, input.summaryPath);
|
|
224
224
|
}
|
|
@@ -26,7 +26,7 @@ export interface ISettingsProcessor<TOptions extends BaseProcessorOptions = Base
|
|
|
26
26
|
interface SettingsGuards<TOptions extends BaseProcessorOptions, TResult extends BaseProcessorResult> {
|
|
27
27
|
hasDesiredSettings(repoConfig: RepoConfig): boolean;
|
|
28
28
|
emptySettingsMessage: string;
|
|
29
|
-
|
|
29
|
+
applySettings(githubRepo: GitHubRepoInfo, repoConfig: RepoConfig, options: TOptions, effectiveToken: string | undefined, repoName: string): Promise<TResult>;
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Common boilerplate for GitHub settings processors: GitHub-only gating,
|
|
@@ -23,7 +23,7 @@ export async function withGitHubGuards(repoConfig, repoInfo, options, guards) {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
try {
|
|
26
|
-
return await guards.
|
|
26
|
+
return await guards.applySettings(repoInfo, repoConfig, options, options.token, repoName);
|
|
27
27
|
}
|
|
28
28
|
catch (error) {
|
|
29
29
|
const message = toErrorMessage(error);
|
package/dist/settings/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { type ISettingsProcessor } from "./base-processor.js";
|
|
2
|
-
export { type PropertyDiff, formatPropertyTree, type RulesetPlanEntry, RulesetProcessor, type IRulesetProcessor, } from "./rulesets/index.js";
|
|
3
|
-
export { RepoSettingsProcessor, type IRepoSettingsProcessor, type RepoSettingsPlanEntry, } from "./repo-settings/index.js";
|
|
4
|
-
export { type LabelsPlanEntry, LabelsProcessor, type ILabelsProcessor, } from "./labels/index.js";
|
|
2
|
+
export { type PropertyDiff, formatPropertyTree, type RulesetPlanEntry, RulesetProcessor, type IRulesetProcessor, GitHubRulesetStrategy, } from "./rulesets/index.js";
|
|
3
|
+
export { RepoSettingsProcessor, type IRepoSettingsProcessor, type RepoSettingsPlanEntry, GitHubRepoSettingsStrategy, } from "./repo-settings/index.js";
|
|
4
|
+
export { type LabelsPlanEntry, LabelsProcessor, type ILabelsProcessor, GitHubLabelsStrategy, } from "./labels/index.js";
|
package/dist/settings/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Rulesets
|
|
2
|
-
export { formatPropertyTree, RulesetProcessor, } from "./rulesets/index.js";
|
|
2
|
+
export { formatPropertyTree, RulesetProcessor, GitHubRulesetStrategy, } from "./rulesets/index.js";
|
|
3
3
|
// Repo settings
|
|
4
|
-
export { RepoSettingsProcessor, } from "./repo-settings/index.js";
|
|
4
|
+
export { RepoSettingsProcessor, GitHubRepoSettingsStrategy, } from "./repo-settings/index.js";
|
|
5
5
|
// Labels
|
|
6
|
-
export { LabelsProcessor, } from "./labels/index.js";
|
|
6
|
+
export { LabelsProcessor, GitHubLabelsStrategy, } from "./labels/index.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { normalizeColor } from "./converter.js";
|
|
2
|
+
import { ValidationError } from "../../shared/errors.js";
|
|
2
3
|
/**
|
|
3
4
|
* Compares current labels (from GitHub) with desired labels (from config).
|
|
4
5
|
*
|
|
@@ -29,7 +30,7 @@ export function diffLabels(current, desired, deleteOrphaned, noDelete) {
|
|
|
29
30
|
if (label.new_name) {
|
|
30
31
|
const targetLower = label.new_name.toLowerCase();
|
|
31
32
|
if (renameTargets.has(targetLower)) {
|
|
32
|
-
throw new
|
|
33
|
+
throw new ValidationError(`Rename collision: both '${renameTargets.get(targetLower)}' and '${name}' rename to '${label.new_name}'`);
|
|
33
34
|
}
|
|
34
35
|
renameTargets.set(targetLower, name);
|
|
35
36
|
}
|
|
@@ -64,7 +65,7 @@ export function diffLabels(current, desired, deleteOrphaned, noDelete) {
|
|
|
64
65
|
!deletedNames.has(targetLower)) {
|
|
65
66
|
const collidingDesired = Object.entries(desired).find(([n]) => n.toLowerCase() === targetLower);
|
|
66
67
|
if (!collidingDesired || !collidingDesired[1].new_name) {
|
|
67
|
-
throw new
|
|
68
|
+
throw new ValidationError(`Rename collision: '${name}' would rename to '${label.new_name}', but that label already exists`);
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
}
|
|
@@ -8,11 +8,11 @@ export function formatLabelsPlan(changes) {
|
|
|
8
8
|
const createChanges = changes.filter((c) => c.action === "create");
|
|
9
9
|
const updateChanges = changes.filter((c) => c.action === "update");
|
|
10
10
|
const deleteChanges = changes.filter((c) => c.action === "delete");
|
|
11
|
-
const
|
|
11
|
+
const unchangedItems = changes.filter((c) => c.action === "unchanged");
|
|
12
12
|
const creates = createChanges.length;
|
|
13
13
|
const updates = updateChanges.length;
|
|
14
14
|
const deletes = deleteChanges.length;
|
|
15
|
-
const unchanged =
|
|
15
|
+
const unchanged = unchangedItems.length;
|
|
16
16
|
// Format creates
|
|
17
17
|
if (createChanges.length > 0) {
|
|
18
18
|
lines.push(chalk.bold(" Create:"));
|
|
@@ -73,7 +73,7 @@ export function formatLabelsPlan(changes) {
|
|
|
73
73
|
lines.push("");
|
|
74
74
|
}
|
|
75
75
|
// Unchanged (entries only, no output lines)
|
|
76
|
-
for (const change of
|
|
76
|
+
for (const change of unchangedItems) {
|
|
77
77
|
entries.push({ name: change.name, action: "unchanged" });
|
|
78
78
|
}
|
|
79
79
|
// Summary line
|
|
@@ -4,43 +4,22 @@ import { type GhApiOptions } from "../../shared/gh-api-utils.js";
|
|
|
4
4
|
import type { ILabelsStrategy, GitHubLabel } from "./types.js";
|
|
5
5
|
interface GitHubLabelsStrategyOptions {
|
|
6
6
|
retries?: number;
|
|
7
|
+
cwd: string;
|
|
7
8
|
}
|
|
8
|
-
/**
|
|
9
|
-
* GitHub Labels Strategy for managing repository labels via GitHub REST API.
|
|
10
|
-
* Uses `gh api` CLI for authentication and API calls.
|
|
11
|
-
*
|
|
12
|
-
* Note: Uses ICommandExecutor (the project's safe executor pattern) with
|
|
13
|
-
* escapeShellArg for input sanitization, matching the rulesets strategy pattern.
|
|
14
|
-
*/
|
|
15
9
|
export declare class GitHubLabelsStrategy implements ILabelsStrategy {
|
|
16
10
|
private api;
|
|
17
|
-
constructor(executor
|
|
18
|
-
/**
|
|
19
|
-
* Lists all labels for a repository.
|
|
20
|
-
* Uses --paginate to retrieve all labels.
|
|
21
|
-
*/
|
|
11
|
+
constructor(executor: ICommandExecutor, options: GitHubLabelsStrategyOptions);
|
|
22
12
|
list(repoInfo: RepoInfo, options?: GhApiOptions): Promise<GitHubLabel[]>;
|
|
23
|
-
/**
|
|
24
|
-
* Creates a new label.
|
|
25
|
-
*/
|
|
26
13
|
create(repoInfo: RepoInfo, label: {
|
|
27
14
|
name: string;
|
|
28
15
|
color: string;
|
|
29
16
|
description?: string;
|
|
30
17
|
}, options?: GhApiOptions): Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
* Updates an existing label.
|
|
33
|
-
* Uses encodeURIComponent for label name in URL path.
|
|
34
|
-
*/
|
|
35
18
|
update(repoInfo: RepoInfo, currentName: string, label: {
|
|
36
19
|
new_name?: string;
|
|
37
20
|
color?: string;
|
|
38
21
|
description?: string;
|
|
39
22
|
}, options?: GhApiOptions): Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
* Deletes a label.
|
|
42
|
-
* Uses encodeURIComponent for label name in URL path.
|
|
43
|
-
*/
|
|
44
23
|
delete(repoInfo: RepoInfo, name: string, options?: GhApiOptions): Promise<void>;
|
|
45
24
|
}
|
|
46
25
|
export {};
|
|
@@ -1,52 +1,32 @@
|
|
|
1
|
-
import { defaultExecutor, } from "../../shared/command-executor.js";
|
|
2
1
|
import { assertGitHubRepo } from "../../shared/repo-detector.js";
|
|
3
2
|
import { GhApiClient, parseApiJson, } from "../../shared/gh-api-utils.js";
|
|
4
|
-
/**
|
|
5
|
-
* GitHub Labels Strategy for managing repository labels via GitHub REST API.
|
|
6
|
-
* Uses `gh api` CLI for authentication and API calls.
|
|
7
|
-
*
|
|
8
|
-
* Note: Uses ICommandExecutor (the project's safe executor pattern) with
|
|
9
|
-
* escapeShellArg for input sanitization, matching the rulesets strategy pattern.
|
|
10
|
-
*/
|
|
11
3
|
export class GitHubLabelsStrategy {
|
|
12
4
|
api;
|
|
13
5
|
constructor(executor, options) {
|
|
14
|
-
this.api = new GhApiClient(executor
|
|
6
|
+
this.api = new GhApiClient(executor, options.retries ?? 3, options.cwd);
|
|
15
7
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Lists all labels for a repository.
|
|
18
|
-
* Uses --paginate to retrieve all labels.
|
|
19
|
-
*/
|
|
20
8
|
async list(repoInfo, options) {
|
|
21
9
|
assertGitHubRepo(repoInfo, "GitHub Labels strategy");
|
|
22
10
|
const endpoint = `/repos/${repoInfo.owner}/${repoInfo.repo}/labels`;
|
|
23
|
-
const result = await this.api.call("GET", endpoint,
|
|
11
|
+
const result = await this.api.call("GET", endpoint, {
|
|
12
|
+
options,
|
|
13
|
+
paginate: true,
|
|
14
|
+
});
|
|
24
15
|
return parseApiJson(result, "labels response");
|
|
25
16
|
}
|
|
26
|
-
/**
|
|
27
|
-
* Creates a new label.
|
|
28
|
-
*/
|
|
29
17
|
async create(repoInfo, label, options) {
|
|
30
18
|
assertGitHubRepo(repoInfo, "GitHub Labels strategy");
|
|
31
19
|
const endpoint = `/repos/${repoInfo.owner}/${repoInfo.repo}/labels`;
|
|
32
|
-
await this.api.call("POST", endpoint, label, options);
|
|
20
|
+
await this.api.call("POST", endpoint, { payload: label, options });
|
|
33
21
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Updates an existing label.
|
|
36
|
-
* Uses encodeURIComponent for label name in URL path.
|
|
37
|
-
*/
|
|
38
22
|
async update(repoInfo, currentName, label, options) {
|
|
39
23
|
assertGitHubRepo(repoInfo, "GitHub Labels strategy");
|
|
40
24
|
const endpoint = `/repos/${repoInfo.owner}/${repoInfo.repo}/labels/${encodeURIComponent(currentName)}`;
|
|
41
|
-
await this.api.call("PATCH", endpoint, label, options);
|
|
25
|
+
await this.api.call("PATCH", endpoint, { payload: label, options });
|
|
42
26
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Deletes a label.
|
|
45
|
-
* Uses encodeURIComponent for label name in URL path.
|
|
46
|
-
*/
|
|
47
27
|
async delete(repoInfo, name, options) {
|
|
48
28
|
assertGitHubRepo(repoInfo, "GitHub Labels strategy");
|
|
49
29
|
const endpoint = `/repos/${repoInfo.owner}/${repoInfo.repo}/labels/${encodeURIComponent(name)}`;
|
|
50
|
-
await this.api.call("DELETE", endpoint,
|
|
30
|
+
await this.api.call("DELETE", endpoint, { options });
|
|
51
31
|
}
|
|
52
32
|
}
|
|
@@ -17,7 +17,7 @@ export interface LabelsProcessorResult extends BaseProcessorResult {
|
|
|
17
17
|
*/
|
|
18
18
|
export declare class LabelsProcessor implements ILabelsProcessor {
|
|
19
19
|
private readonly strategy;
|
|
20
|
-
constructor(strategy
|
|
20
|
+
constructor(strategy: ILabelsStrategy);
|
|
21
21
|
process(repoConfig: RepoConfig, repoInfo: RepoInfo, options: LabelsProcessorOptions): Promise<LabelsProcessorResult>;
|
|
22
|
-
private
|
|
22
|
+
private applySettings;
|
|
23
23
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { GitHubLabelsStrategy } from "./github-labels-strategy.js";
|
|
2
1
|
import { diffLabels } from "./diff.js";
|
|
3
2
|
import { formatLabelsPlan } from "./formatter.js";
|
|
4
3
|
import { labelConfigToPayload } from "./converter.js";
|
|
@@ -10,16 +9,16 @@ import { withGitHubGuards, countActions, buildDryRunResult, buildApplyResult, }
|
|
|
10
9
|
export class LabelsProcessor {
|
|
11
10
|
strategy;
|
|
12
11
|
constructor(strategy) {
|
|
13
|
-
this.strategy = strategy
|
|
12
|
+
this.strategy = strategy;
|
|
14
13
|
}
|
|
15
14
|
async process(repoConfig, repoInfo, options) {
|
|
16
15
|
return withGitHubGuards(repoConfig, repoInfo, options, {
|
|
17
16
|
hasDesiredSettings: (rc) => Object.keys(rc.settings?.labels ?? {}).length > 0,
|
|
18
17
|
emptySettingsMessage: "No labels configured",
|
|
19
|
-
|
|
18
|
+
applySettings: (githubRepo, rc, opts, token, repoName) => this.applySettings(githubRepo, rc, opts, token, repoName),
|
|
20
19
|
});
|
|
21
20
|
}
|
|
22
|
-
async
|
|
21
|
+
async applySettings(githubRepo, repoConfig, options, effectiveToken, repoName) {
|
|
23
22
|
const { dryRun, noDelete } = options;
|
|
24
23
|
const settings = repoConfig.settings;
|
|
25
24
|
const desiredLabels = settings?.labels ?? {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { GitHubRepoSettings } from "../../config/index.js";
|
|
2
2
|
import type { CurrentRepoSettings } from "./types.js";
|
|
3
|
-
export type RepoSettingsAction = "
|
|
3
|
+
export type RepoSettingsAction = "create" | "update" | "unchanged";
|
|
4
4
|
export interface RepoSettingsChange {
|
|
5
5
|
property: keyof GitHubRepoSettings;
|
|
6
6
|
action: RepoSettingsAction;
|
|
@@ -63,14 +63,14 @@ export function diffRepoSettings(current, desired) {
|
|
|
63
63
|
// Property not currently set or unknown
|
|
64
64
|
changes.push({
|
|
65
65
|
property,
|
|
66
|
-
action: "
|
|
66
|
+
action: "create",
|
|
67
67
|
newValue: desiredValue,
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
else if (currentValue !== desiredValue) {
|
|
71
71
|
changes.push({
|
|
72
72
|
property,
|
|
73
|
-
action: "
|
|
73
|
+
action: "update",
|
|
74
74
|
oldValue: currentValue,
|
|
75
75
|
newValue: desiredValue,
|
|
76
76
|
});
|
|
@@ -51,21 +51,21 @@ export function formatRepoSettingsPlan(changes) {
|
|
|
51
51
|
if (warning) {
|
|
52
52
|
warnings.push(warning);
|
|
53
53
|
}
|
|
54
|
-
if (change.action === "
|
|
54
|
+
if (change.action === "create") {
|
|
55
55
|
lines.push(chalk.green(` + ${change.property}: ${formatValue(change.newValue)}`));
|
|
56
56
|
creates++;
|
|
57
57
|
entries.push({
|
|
58
58
|
property: change.property,
|
|
59
|
-
action: "
|
|
59
|
+
action: "create",
|
|
60
60
|
newValue: change.newValue,
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
-
else if (change.action === "
|
|
63
|
+
else if (change.action === "update") {
|
|
64
64
|
lines.push(chalk.yellow(` ~ ${change.property}: ${formatValue(change.oldValue)} → ${formatValue(change.newValue)}`));
|
|
65
65
|
updates++;
|
|
66
66
|
entries.push({
|
|
67
67
|
property: change.property,
|
|
68
|
-
action: "
|
|
68
|
+
action: "update",
|
|
69
69
|
oldValue: change.oldValue,
|
|
70
70
|
newValue: change.newValue,
|
|
71
71
|
});
|
|
@@ -5,16 +5,11 @@ import type { GitHubRepoSettings } from "../../config/index.js";
|
|
|
5
5
|
import type { IRepoSettingsStrategy, CurrentRepoSettings } from "./types.js";
|
|
6
6
|
interface GitHubRepoSettingsStrategyOptions {
|
|
7
7
|
retries?: number;
|
|
8
|
+
cwd: string;
|
|
8
9
|
}
|
|
9
|
-
/**
|
|
10
|
-
* GitHub Repository Settings Strategy.
|
|
11
|
-
* Manages repository settings via GitHub REST API using `gh api` CLI.
|
|
12
|
-
* Note: Uses exec via ICommandExecutor for gh CLI integration, consistent
|
|
13
|
-
* with other strategies in this codebase. Inputs are escaped via escapeShellArg.
|
|
14
|
-
*/
|
|
15
10
|
export declare class GitHubRepoSettingsStrategy implements IRepoSettingsStrategy {
|
|
16
11
|
private api;
|
|
17
|
-
constructor(executor
|
|
12
|
+
constructor(executor: ICommandExecutor, options: GitHubRepoSettingsStrategyOptions);
|
|
18
13
|
getSettings(repoInfo: RepoInfo, options?: GhApiOptions): Promise<CurrentRepoSettings>;
|
|
19
14
|
updateSettings(repoInfo: RepoInfo, settings: GitHubRepoSettings, options?: GhApiOptions): Promise<void>;
|
|
20
15
|
setVulnerabilityAlerts(repoInfo: RepoInfo, enable: boolean, options?: GhApiOptions): Promise<void>;
|