@aspruyt/xfg 6.0.3 → 6.2.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/dist/cli/lifecycle-report-builder.d.ts +2 -2
- package/dist/cli/lifecycle-report-builder.js +3 -11
- package/dist/cli/program.d.ts +2 -1
- package/dist/cli/program.js +2 -3
- package/dist/cli/repo-sync-runner.d.ts +24 -0
- package/dist/cli/repo-sync-runner.js +156 -0
- package/dist/cli/results-collector.d.ts +1 -1
- package/dist/cli/results-collector.js +2 -2
- package/dist/cli/settings-factories.d.ts +7 -0
- package/dist/cli/settings-factories.js +27 -0
- package/dist/cli/settings-report-builder.d.ts +1 -1
- package/dist/cli/settings-report-builder.js +12 -23
- package/dist/cli/settings-runner.d.ts +2 -0
- package/dist/cli/settings-runner.js +87 -0
- package/dist/cli/sync-command.d.ts +1 -1
- package/dist/cli/sync-command.js +31 -372
- package/dist/cli/sync-report-builder.d.ts +1 -1
- package/dist/cli/sync-utils.d.ts +8 -0
- package/dist/cli/sync-utils.js +36 -0
- package/dist/cli/types.d.ts +5 -7
- package/dist/cli/unified-summary.d.ts +1 -3
- package/dist/cli/unified-summary.js +7 -5
- package/dist/cli.js +2 -1
- package/dist/{shared → config}/env.js +2 -2
- package/dist/config/extends-resolver.js +4 -3
- package/dist/config/file-reference-resolver.js +4 -2
- package/dist/config/formatter.js +18 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/loader.js +30 -6
- package/dist/config/merge.d.ts +11 -1
- package/dist/config/merge.js +78 -6
- package/dist/config/normalizer.js +53 -38
- package/dist/config/validator.d.ts +1 -4
- package/dist/config/validator.js +13 -599
- package/dist/config/validators/file-validator.d.ts +2 -1
- package/dist/config/validators/file-validator.js +9 -1
- package/dist/config/validators/group-validator.d.ts +3 -0
- package/dist/config/validators/group-validator.js +167 -0
- package/dist/config/validators/repo-entry-validator.d.ts +2 -0
- package/dist/config/validators/repo-entry-validator.js +165 -0
- package/dist/config/validators/repo-settings-validator.js +18 -7
- package/dist/config/validators/ruleset-validator.js +2 -5
- package/dist/config/validators/shared.d.ts +11 -0
- package/dist/config/validators/shared.js +242 -0
- package/dist/lifecycle/ado-migration-source.js +2 -4
- package/dist/lifecycle/github-lifecycle-provider.d.ts +7 -11
- package/dist/lifecycle/github-lifecycle-provider.js +125 -136
- package/dist/lifecycle/{lifecycle-helpers.d.ts → helpers.d.ts} +5 -1
- package/dist/lifecycle/{lifecycle-helpers.js → helpers.js} +9 -8
- package/dist/lifecycle/index.d.ts +2 -2
- package/dist/lifecycle/index.js +1 -1
- package/dist/lifecycle/repo-lifecycle-factory.d.ts +2 -2
- package/dist/output/github-summary.js +2 -3
- package/dist/output/index.d.ts +4 -0
- package/dist/output/index.js +4 -0
- package/dist/output/lifecycle-report.d.ts +1 -1
- package/dist/output/lifecycle-report.js +5 -0
- package/dist/output/sync-report.d.ts +25 -3
- package/dist/output/sync-report.js +11 -11
- package/dist/settings/base-processor.d.ts +18 -7
- package/dist/settings/base-processor.js +26 -5
- package/dist/settings/code-scanning/diff.js +2 -2
- package/dist/settings/code-scanning/formatter.d.ts +2 -6
- package/dist/settings/code-scanning/formatter.js +2 -25
- package/dist/settings/code-scanning/github-code-scanning-strategy.d.ts +3 -7
- package/dist/settings/code-scanning/github-code-scanning-strategy.js +2 -2
- package/dist/settings/code-scanning/processor.js +6 -4
- package/dist/settings/code-scanning/types.d.ts +10 -8
- package/dist/settings/labels/github-labels-strategy.d.ts +3 -11
- package/dist/settings/labels/types.d.ts +12 -10
- package/dist/settings/repo-settings/diff.d.ts +1 -1
- package/dist/settings/repo-settings/diff.js +1 -1
- package/dist/settings/repo-settings/formatter.d.ts +2 -6
- package/dist/settings/repo-settings/formatter.js +4 -23
- package/dist/settings/repo-settings/github-repo-settings-strategy.d.ts +2 -2
- package/dist/settings/repo-settings/github-repo-settings-strategy.js +8 -7
- package/dist/settings/repo-settings/processor.js +11 -11
- package/dist/settings/repo-settings/types.d.ts +2 -2
- package/dist/settings/rulesets/diff-algorithm.js +4 -2
- package/dist/settings/rulesets/diff.js +2 -51
- package/dist/settings/rulesets/formatter.js +4 -0
- package/dist/settings/rulesets/github-ruleset-strategy.d.ts +3 -3
- package/dist/settings/rulesets/github-ruleset-strategy.js +4 -6
- package/dist/settings/rulesets/index.d.ts +1 -1
- package/dist/settings/rulesets/index.js +0 -2
- package/dist/settings/rulesets/processor.js +1 -1
- package/dist/settings/rulesets/types.d.ts +6 -2
- package/dist/shared/command-executor.d.ts +4 -4
- package/dist/shared/command-executor.js +9 -7
- package/dist/shared/diff-format.d.ts +1 -0
- package/dist/shared/diff-format.js +10 -0
- package/dist/shared/errors.d.ts +7 -4
- package/dist/shared/errors.js +8 -8
- package/dist/shared/gh-api-utils.d.ts +3 -34
- package/dist/shared/gh-api-utils.js +23 -53
- package/dist/shared/gh-token-utils.d.ts +26 -0
- package/dist/shared/gh-token-utils.js +32 -0
- package/dist/shared/json-utils.js +1 -1
- package/dist/shared/regex-utils.d.ts +1 -0
- package/dist/shared/regex-utils.js +3 -0
- package/dist/shared/retry-utils.d.ts +1 -0
- package/dist/shared/retry-utils.js +13 -7
- package/dist/sync/auth-options-builder.js +1 -1
- package/dist/sync/branch-manager.js +5 -3
- package/dist/sync/commit-push-manager.js +2 -3
- package/dist/sync/diff-utils.d.ts +0 -1
- package/dist/sync/diff-utils.js +5 -10
- package/dist/sync/file-sync-orchestrator.js +0 -2
- package/dist/sync/file-writer.d.ts +3 -0
- package/dist/sync/file-writer.js +84 -81
- package/dist/sync/index.d.ts +0 -1
- package/dist/sync/index.js +0 -1
- package/dist/sync/manifest.js +1 -1
- package/dist/sync/pr-merge-handler.js +6 -6
- package/dist/sync/sync-workflow.js +1 -1
- package/dist/sync/types.d.ts +2 -2
- package/dist/vcs/ado-pr-strategy.d.ts +3 -5
- package/dist/vcs/ado-pr-strategy.js +131 -33
- package/dist/vcs/authenticated-git-ops.js +45 -23
- package/dist/vcs/git-commit-strategy.js +10 -6
- package/dist/vcs/git-ops.js +30 -24
- package/dist/vcs/github-pr-strategy.d.ts +3 -2
- package/dist/vcs/github-pr-strategy.js +80 -30
- package/dist/vcs/gitlab-pr-strategy.d.ts +2 -5
- package/dist/vcs/gitlab-pr-strategy.js +88 -87
- package/dist/vcs/graphql-commit-strategy.d.ts +1 -5
- package/dist/vcs/graphql-commit-strategy.js +21 -37
- package/dist/vcs/pr-creator.js +9 -2
- package/dist/vcs/pr-strategy.d.ts +2 -3
- package/dist/vcs/pr-strategy.js +0 -1
- package/dist/vcs/types.d.ts +9 -5
- package/package.json +5 -5
- package/dist/config/validators/index.d.ts +0 -3
- package/dist/config/validators/index.js +0 -6
- package/dist/output/types.d.ts +0 -20
- package/dist/output/types.js +0 -1
- package/dist/shared/shell-utils.d.ts +0 -6
- package/dist/shared/shell-utils.js +0 -17
- /package/dist/{shared → config}/env.d.ts +0 -0
- /package/dist/lifecycle/{lifecycle-formatter.d.ts → formatter.d.ts} +0 -0
- /package/dist/lifecycle/{lifecycle-formatter.js → formatter.js} +0 -0
- /package/dist/{vcs → shared}/sanitize-utils.d.ts +0 -0
- /package/dist/{vcs → shared}/sanitize-utils.js +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { LifecycleReport, LifecycleAction } from "../output/
|
|
2
|
-
export declare function buildLifecycleReport(
|
|
1
|
+
import type { LifecycleReport, LifecycleAction } from "../output/index.js";
|
|
2
|
+
export declare function buildLifecycleReport(actions: LifecycleAction[]): LifecycleReport;
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
export function buildLifecycleReport(
|
|
2
|
-
const actions = [];
|
|
1
|
+
export function buildLifecycleReport(actions) {
|
|
3
2
|
const totals = { created: 0, forked: 0, migrated: 0, existed: 0 };
|
|
4
|
-
for (const
|
|
5
|
-
|
|
6
|
-
repoName: result.repoName,
|
|
7
|
-
action: result.action,
|
|
8
|
-
upstream: result.upstream,
|
|
9
|
-
source: result.source,
|
|
10
|
-
settings: result.settings,
|
|
11
|
-
});
|
|
12
|
-
totals[result.action]++;
|
|
3
|
+
for (const action of actions) {
|
|
4
|
+
totals[action.action]++;
|
|
13
5
|
}
|
|
14
6
|
return { actions, totals };
|
|
15
7
|
}
|
package/dist/cli/program.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { program } from "commander";
|
|
2
2
|
import { MergeMode, MergeStrategy } from "../config/index.js";
|
|
3
|
+
declare function getVersion(): string;
|
|
3
4
|
export declare function parseMergeMode(value: string): MergeMode;
|
|
4
5
|
export declare function parseMergeStrategy(value: string): MergeStrategy;
|
|
5
|
-
export { program };
|
|
6
|
+
export { program, getVersion };
|
package/dist/cli/program.js
CHANGED
|
@@ -51,8 +51,7 @@ export function parseMergeStrategy(value) {
|
|
|
51
51
|
// =============================================================================
|
|
52
52
|
program
|
|
53
53
|
.name("xfg")
|
|
54
|
-
.description("Manage files, settings, and repositories across GitHub, Azure DevOps, and GitLab")
|
|
55
|
-
.version(getVersion());
|
|
54
|
+
.description("Manage files, settings, and repositories across GitHub, Azure DevOps, and GitLab");
|
|
56
55
|
// Sync command (file synchronization)
|
|
57
56
|
const syncCommand = new Command("sync")
|
|
58
57
|
.description("Sync configuration files across repositories")
|
|
@@ -71,4 +70,4 @@ const syncCommand = new Command("sync")
|
|
|
71
70
|
});
|
|
72
71
|
addSharedOptions(syncCommand);
|
|
73
72
|
program.addCommand(syncCommand);
|
|
74
|
-
export { program };
|
|
73
|
+
export { program, getVersion };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Config, RepoConfig } from "../config/index.js";
|
|
2
|
+
import type { createTokenManager } from "../vcs/index.js";
|
|
3
|
+
import type { IRepositoryProcessor } from "../sync/index.js";
|
|
4
|
+
import type { ProcessExecutor } from "../shared/command-executor.js";
|
|
5
|
+
import type { Logger } from "../shared/logger.js";
|
|
6
|
+
import { type IRepoLifecycleManager } from "../lifecycle/index.js";
|
|
7
|
+
import type { SyncOptions, SyncResultEntry, SettingsProcessorFactories } from "./types.js";
|
|
8
|
+
import type { ResultsCollector } from "./results-collector.js";
|
|
9
|
+
import type { LifecycleAction } from "../output/index.js";
|
|
10
|
+
export interface RepoIterationContext {
|
|
11
|
+
config: Config;
|
|
12
|
+
options: SyncOptions;
|
|
13
|
+
branchName: string;
|
|
14
|
+
processor: IRepositoryProcessor;
|
|
15
|
+
lifecycleManager: IRepoLifecycleManager;
|
|
16
|
+
tokenManager: ReturnType<typeof createTokenManager>;
|
|
17
|
+
reportResults: SyncResultEntry[];
|
|
18
|
+
lifecycleReportInputs: LifecycleAction[];
|
|
19
|
+
settingsCollector: ResultsCollector;
|
|
20
|
+
factories: SettingsProcessorFactories;
|
|
21
|
+
logger: Logger;
|
|
22
|
+
executor: ProcessExecutor;
|
|
23
|
+
}
|
|
24
|
+
export declare function runSingleRepo(repoConfig: RepoConfig, index: number, ctx: RepoIterationContext): Promise<void>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { resolve, join } from "node:path";
|
|
2
|
+
import { parseGitUrl, getRepoDisplayName, isGitHubRepo, } from "../repo/index.js";
|
|
3
|
+
import { generateWorkspaceName } from "../shared/workspace-utils.js";
|
|
4
|
+
import { toErrorMessage } from "../shared/type-guards.js";
|
|
5
|
+
import { resolveGitHubToken } from "../shared/gh-token-utils.js";
|
|
6
|
+
import { runLifecycleCheck, } from "../lifecycle/index.js";
|
|
7
|
+
import { applyRepoSettings } from "./settings-runner.js";
|
|
8
|
+
import { determineMergeOutcome } from "./sync-utils.js";
|
|
9
|
+
function pushFailure(results, repoName, error) {
|
|
10
|
+
results.push({
|
|
11
|
+
repoName,
|
|
12
|
+
success: false,
|
|
13
|
+
fileChanges: [],
|
|
14
|
+
error: toErrorMessage(error),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async function runLifecyclePhase(repo, ctx) {
|
|
18
|
+
const repoNumber = repo.index + 1;
|
|
19
|
+
try {
|
|
20
|
+
const { outputLines, lifecycleResult, reportSettings } = await runLifecycleCheck(repo.repoConfig, repo.repoInfo, {
|
|
21
|
+
dryRun: ctx.options.dryRun ?? false,
|
|
22
|
+
resolvedWorkDir: repo.workDir,
|
|
23
|
+
githubHosts: ctx.config.githubHosts,
|
|
24
|
+
token: repo.token,
|
|
25
|
+
repoIndex: repo.index,
|
|
26
|
+
lifecycleManager: ctx.lifecycleManager,
|
|
27
|
+
repoSettings: ctx.config.settings?.repo,
|
|
28
|
+
});
|
|
29
|
+
for (const line of outputLines) {
|
|
30
|
+
ctx.logger.info(line);
|
|
31
|
+
}
|
|
32
|
+
ctx.lifecycleReportInputs.push({
|
|
33
|
+
repoName: repo.repoName,
|
|
34
|
+
action: lifecycleResult.action,
|
|
35
|
+
upstream: repo.repoConfig.upstream,
|
|
36
|
+
source: repo.repoConfig.source,
|
|
37
|
+
settings: reportSettings,
|
|
38
|
+
});
|
|
39
|
+
if (ctx.options.dryRun && lifecycleResult.action !== "existed") {
|
|
40
|
+
ctx.reportResults.push({
|
|
41
|
+
repoName: repo.repoName,
|
|
42
|
+
success: true,
|
|
43
|
+
fileChanges: [],
|
|
44
|
+
});
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
ctx.logger.error(repoNumber, repo.repoName, `Lifecycle error: ${toErrorMessage(error)}`);
|
|
51
|
+
pushFailure(ctx.reportResults, repo.repoName, error);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function runFileSyncPhase(repo, ctx) {
|
|
56
|
+
const repoNumber = repo.index + 1;
|
|
57
|
+
try {
|
|
58
|
+
ctx.logger.progress(repoNumber, repo.repoName, "Processing...");
|
|
59
|
+
const result = await ctx.processor.process(repo.repoConfig, repo.repoInfo, {
|
|
60
|
+
branchName: ctx.branchName,
|
|
61
|
+
workDir: repo.workDir,
|
|
62
|
+
configId: ctx.config.id,
|
|
63
|
+
dryRun: ctx.options.dryRun,
|
|
64
|
+
retries: ctx.options.retries,
|
|
65
|
+
executor: ctx.executor,
|
|
66
|
+
prTemplate: ctx.config.prTemplate,
|
|
67
|
+
noDelete: ctx.options.noDelete,
|
|
68
|
+
token: repo.token,
|
|
69
|
+
hasAppCredentials: isGitHubRepo(repo.repoInfo) && ctx.tokenManager !== null,
|
|
70
|
+
});
|
|
71
|
+
const mergeOutcome = determineMergeOutcome(result);
|
|
72
|
+
ctx.reportResults.push({
|
|
73
|
+
repoName: repo.repoName,
|
|
74
|
+
success: result.success,
|
|
75
|
+
fileChanges: result.fileChanges ?? [],
|
|
76
|
+
prUrl: result.prUrl,
|
|
77
|
+
mergeOutcome,
|
|
78
|
+
error: result.success ? undefined : result.message,
|
|
79
|
+
});
|
|
80
|
+
if (result.skipped) {
|
|
81
|
+
ctx.logger.skip(repoNumber, repo.repoName, result.message);
|
|
82
|
+
}
|
|
83
|
+
else if (result.success) {
|
|
84
|
+
ctx.logger.success(repoNumber, repo.repoName, result.message);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
ctx.logger.error(repoNumber, repo.repoName, result.message);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
ctx.logger.error(repoNumber, repo.repoName, toErrorMessage(error));
|
|
92
|
+
pushFailure(ctx.reportResults, repo.repoName, error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export async function runSingleRepo(repoConfig, index, ctx) {
|
|
96
|
+
const { config, options, logger } = ctx;
|
|
97
|
+
const repoNumber = index + 1;
|
|
98
|
+
const effectivePrOptions = options.merge || options.mergeStrategy || options.deleteBranch
|
|
99
|
+
? {
|
|
100
|
+
...repoConfig.prOptions,
|
|
101
|
+
merge: options.merge ?? repoConfig.prOptions?.merge,
|
|
102
|
+
mergeStrategy: options.mergeStrategy ?? repoConfig.prOptions?.mergeStrategy,
|
|
103
|
+
deleteBranch: options.deleteBranch ?? repoConfig.prOptions?.deleteBranch,
|
|
104
|
+
}
|
|
105
|
+
: repoConfig.prOptions;
|
|
106
|
+
const effectiveRepoConfig = { ...repoConfig, prOptions: effectivePrOptions };
|
|
107
|
+
const mergeMode = effectivePrOptions?.merge ?? "auto";
|
|
108
|
+
if (mergeMode === "direct" && effectivePrOptions?.mergeStrategy) {
|
|
109
|
+
logger.warn(`mergeStrategy '${effectivePrOptions.mergeStrategy}' is ignored in direct mode for ${repoConfig.git}`);
|
|
110
|
+
}
|
|
111
|
+
let repoInfo;
|
|
112
|
+
try {
|
|
113
|
+
repoInfo = parseGitUrl(repoConfig.git, {
|
|
114
|
+
githubHosts: config.githubHosts,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
logger.error(repoNumber, repoConfig.git, toErrorMessage(error));
|
|
119
|
+
pushFailure(ctx.reportResults, repoConfig.git, error);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const repoName = getRepoDisplayName(repoInfo);
|
|
123
|
+
const workDir = resolve(join(options.workDir ?? "./tmp", generateWorkspaceName(index)));
|
|
124
|
+
const repoToken = isGitHubRepo(repoInfo)
|
|
125
|
+
? (await resolveGitHubToken({
|
|
126
|
+
repoInfo: repoInfo,
|
|
127
|
+
tokenManager: ctx.tokenManager,
|
|
128
|
+
context: repoName,
|
|
129
|
+
log: logger,
|
|
130
|
+
envToken: process.env.GH_TOKEN,
|
|
131
|
+
})).token
|
|
132
|
+
: undefined;
|
|
133
|
+
const repo = {
|
|
134
|
+
repoConfig: effectiveRepoConfig,
|
|
135
|
+
repoInfo,
|
|
136
|
+
repoName,
|
|
137
|
+
index,
|
|
138
|
+
workDir,
|
|
139
|
+
token: repoToken,
|
|
140
|
+
};
|
|
141
|
+
const skipFileSync = await runLifecyclePhase(repo, ctx);
|
|
142
|
+
if (skipFileSync)
|
|
143
|
+
return;
|
|
144
|
+
await runFileSyncPhase(repo, ctx);
|
|
145
|
+
await applyRepoSettings({
|
|
146
|
+
repoConfig: effectiveRepoConfig,
|
|
147
|
+
repoInfo,
|
|
148
|
+
repoName,
|
|
149
|
+
repoNumber,
|
|
150
|
+
options,
|
|
151
|
+
token: repoToken,
|
|
152
|
+
settingsCollector: ctx.settingsCollector,
|
|
153
|
+
factories: ctx.factories,
|
|
154
|
+
logger,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
@@ -5,7 +5,7 @@ import type { ProcessorResults } from "./settings-report-builder.js";
|
|
|
5
5
|
*/
|
|
6
6
|
export declare class ResultsCollector {
|
|
7
7
|
private readonly results;
|
|
8
|
-
|
|
8
|
+
findOrCreate(repoName: string): ProcessorResults;
|
|
9
9
|
appendError(repoName: string, error: unknown): void;
|
|
10
10
|
getAll(): ProcessorResults[];
|
|
11
11
|
}
|
|
@@ -5,7 +5,7 @@ import { toErrorMessage } from "../shared/type-guards.js";
|
|
|
5
5
|
*/
|
|
6
6
|
export class ResultsCollector {
|
|
7
7
|
results = [];
|
|
8
|
-
|
|
8
|
+
findOrCreate(repoName) {
|
|
9
9
|
let result = this.results.find((r) => r.repoName === repoName);
|
|
10
10
|
if (!result) {
|
|
11
11
|
result = { repoName };
|
|
@@ -14,7 +14,7 @@ export class ResultsCollector {
|
|
|
14
14
|
return result;
|
|
15
15
|
}
|
|
16
16
|
appendError(repoName, error) {
|
|
17
|
-
const existing = this.
|
|
17
|
+
const existing = this.findOrCreate(repoName);
|
|
18
18
|
const errorMsg = toErrorMessage(error);
|
|
19
19
|
if (existing.error) {
|
|
20
20
|
existing.error += `; ${errorMsg}`;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ProcessExecutor } from "../shared/command-executor.js";
|
|
2
|
+
import type { RulesetProcessorFactory, RepoSettingsProcessorFactory, LabelsProcessorFactory, CodeScanningProcessorFactory, SettingsProcessorFactories } from "./types.js";
|
|
3
|
+
export declare function createDefaultRulesetProcessorFactory(executor: ProcessExecutor): RulesetProcessorFactory;
|
|
4
|
+
export declare function createDefaultRepoSettingsProcessorFactory(executor: ProcessExecutor): RepoSettingsProcessorFactory;
|
|
5
|
+
export declare function createDefaultLabelsProcessorFactory(executor: ProcessExecutor): LabelsProcessorFactory;
|
|
6
|
+
export declare function createDefaultCodeScanningProcessorFactory(executor: ProcessExecutor): CodeScanningProcessorFactory;
|
|
7
|
+
export declare function createDefaultFactories(executor: ProcessExecutor, overrides?: Partial<SettingsProcessorFactories>): SettingsProcessorFactories;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { RulesetProcessor, RepoSettingsProcessor, LabelsProcessor, CodeScanningProcessor, GitHubRulesetStrategy, GitHubRepoSettingsStrategy, GitHubLabelsStrategy, GitHubCodeScanningStrategy, } from "../settings/index.js";
|
|
2
|
+
import { GitHubRepoMetadataProvider } from "../repo/index.js";
|
|
3
|
+
export function createDefaultRulesetProcessorFactory(executor) {
|
|
4
|
+
const cwd = process.cwd();
|
|
5
|
+
return () => new RulesetProcessor(new GitHubRulesetStrategy(executor, { cwd }));
|
|
6
|
+
}
|
|
7
|
+
export function createDefaultRepoSettingsProcessorFactory(executor) {
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
return () => new RepoSettingsProcessor(new GitHubRepoSettingsStrategy(executor, { cwd }), new GitHubRepoMetadataProvider(executor, { cwd }));
|
|
10
|
+
}
|
|
11
|
+
export function createDefaultLabelsProcessorFactory(executor) {
|
|
12
|
+
const cwd = process.cwd();
|
|
13
|
+
return () => new LabelsProcessor(new GitHubLabelsStrategy(executor, { cwd }));
|
|
14
|
+
}
|
|
15
|
+
export function createDefaultCodeScanningProcessorFactory(executor) {
|
|
16
|
+
const cwd = process.cwd();
|
|
17
|
+
return () => new CodeScanningProcessor(new GitHubCodeScanningStrategy(executor, { cwd }), new GitHubRepoMetadataProvider(executor, { cwd }));
|
|
18
|
+
}
|
|
19
|
+
export function createDefaultFactories(executor, overrides) {
|
|
20
|
+
return {
|
|
21
|
+
rulesets: overrides?.rulesets ?? createDefaultRulesetProcessorFactory(executor),
|
|
22
|
+
labels: overrides?.labels ?? createDefaultLabelsProcessorFactory(executor),
|
|
23
|
+
repo: overrides?.repo ?? createDefaultRepoSettingsProcessorFactory(executor),
|
|
24
|
+
codeScanning: overrides?.codeScanning ??
|
|
25
|
+
createDefaultCodeScanningProcessorFactory(executor),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SettingsReport } from "../output/
|
|
1
|
+
import type { SettingsReport } from "../output/index.js";
|
|
2
2
|
import { type RepoSettingsPlanEntry, type RulesetPlanEntry, type LabelsPlanEntry, type CodeScanningPlanEntry } from "../settings/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Result from processing a repository's settings and rulesets.
|
|
@@ -13,10 +13,8 @@ export function buildSettingsReport(results) {
|
|
|
13
13
|
rulesets: [],
|
|
14
14
|
labels: [],
|
|
15
15
|
};
|
|
16
|
-
// Convert settings processor output
|
|
17
16
|
if (result.settingsResult?.planOutput?.entries) {
|
|
18
17
|
for (const entry of result.settingsResult.planOutput.entries) {
|
|
19
|
-
// Skip settings where both values are undefined (no actual change)
|
|
20
18
|
if (entry.oldValue === undefined && entry.newValue === undefined) {
|
|
21
19
|
continue;
|
|
22
20
|
}
|
|
@@ -27,11 +25,22 @@ export function buildSettingsReport(results) {
|
|
|
27
25
|
newValue: entry.newValue,
|
|
28
26
|
});
|
|
29
27
|
}
|
|
28
|
+
}
|
|
29
|
+
if (result.codeScanningResult?.planOutput?.entries) {
|
|
30
|
+
for (const entry of result.codeScanningResult.planOutput.entries) {
|
|
31
|
+
repoChanges.settings.push({
|
|
32
|
+
name: `codeScanning.${entry.property}`,
|
|
33
|
+
action: entry.action,
|
|
34
|
+
oldValue: entry.oldValue,
|
|
35
|
+
newValue: entry.newValue ?? null,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (repoChanges.settings.length > 0) {
|
|
30
40
|
const counts = countActions(repoChanges.settings);
|
|
31
41
|
totals.settings.create += counts.create;
|
|
32
42
|
totals.settings.update += counts.update;
|
|
33
43
|
}
|
|
34
|
-
// Convert ruleset processor output
|
|
35
44
|
if (result.rulesetResult?.planOutput?.entries) {
|
|
36
45
|
for (const entry of result.rulesetResult.planOutput.entries) {
|
|
37
46
|
if (!isActiveAction(entry))
|
|
@@ -48,7 +57,6 @@ export function buildSettingsReport(results) {
|
|
|
48
57
|
totals.rulesets.update += counts.update;
|
|
49
58
|
totals.rulesets.delete += counts.delete;
|
|
50
59
|
}
|
|
51
|
-
// Convert labels processor output
|
|
52
60
|
if (result.labelsResult?.planOutput?.entries) {
|
|
53
61
|
for (const entry of result.labelsResult.planOutput.entries) {
|
|
54
62
|
if (!isActiveAction(entry))
|
|
@@ -66,25 +74,6 @@ export function buildSettingsReport(results) {
|
|
|
66
74
|
totals.labels.update += counts.update;
|
|
67
75
|
totals.labels.delete += counts.delete;
|
|
68
76
|
}
|
|
69
|
-
// Convert code scanning processor output
|
|
70
|
-
if (result.codeScanningResult?.planOutput?.entries) {
|
|
71
|
-
let csCreates = 0;
|
|
72
|
-
let csUpdates = 0;
|
|
73
|
-
for (const entry of result.codeScanningResult.planOutput.entries) {
|
|
74
|
-
repoChanges.settings.push({
|
|
75
|
-
name: `codeScanning.${entry.property}`,
|
|
76
|
-
action: entry.action,
|
|
77
|
-
oldValue: entry.oldValue,
|
|
78
|
-
newValue: entry.newValue ?? null,
|
|
79
|
-
});
|
|
80
|
-
if (entry.action === "create")
|
|
81
|
-
csCreates++;
|
|
82
|
-
if (entry.action === "update")
|
|
83
|
-
csUpdates++;
|
|
84
|
-
}
|
|
85
|
-
totals.settings.create += csCreates;
|
|
86
|
-
totals.settings.update += csUpdates;
|
|
87
|
-
}
|
|
88
77
|
if (result.error) {
|
|
89
78
|
repoChanges.error = result.error;
|
|
90
79
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { isGitHubRepo } from "../repo/index.js";
|
|
2
|
+
import { toErrorMessage } from "../shared/type-guards.js";
|
|
3
|
+
function logSettingsResult(logger, result, label, repoNumber, repoName, settingsCollector) {
|
|
4
|
+
if (result.planOutput?.lines?.length) {
|
|
5
|
+
logger.info("");
|
|
6
|
+
logger.info(`${repoName} - ${label}:`);
|
|
7
|
+
for (const line of result.planOutput.lines) {
|
|
8
|
+
logger.info(line);
|
|
9
|
+
}
|
|
10
|
+
if (result.warnings?.length) {
|
|
11
|
+
for (const warning of result.warnings) {
|
|
12
|
+
logger.warn(warning);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else if (!result.skipped && result.success) {
|
|
17
|
+
logger.success(repoNumber, repoName, `${label}: ${result.message}`);
|
|
18
|
+
}
|
|
19
|
+
if (!result.success && !result.skipped) {
|
|
20
|
+
logger.error(repoNumber, repoName, `${label}: ${result.message}`);
|
|
21
|
+
settingsCollector.appendError(repoName, result.message);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function runAndStoreResult(factory, repoConfig, repoInfo, opts, repoName, settingsCollector, assign) {
|
|
25
|
+
const result = await factory().process(repoConfig, repoInfo, opts);
|
|
26
|
+
if (!result.skipped) {
|
|
27
|
+
assign(settingsCollector.findOrCreate(repoName), result);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
function buildSettingsDescriptors(ctx) {
|
|
32
|
+
const { repoConfig, repoInfo, options, token, repoName, settingsCollector } = ctx;
|
|
33
|
+
const { factories } = ctx;
|
|
34
|
+
const sharedOpts = {
|
|
35
|
+
dryRun: options.dryRun,
|
|
36
|
+
noDelete: options.noDelete,
|
|
37
|
+
token,
|
|
38
|
+
};
|
|
39
|
+
return [
|
|
40
|
+
{
|
|
41
|
+
key: "rulesets",
|
|
42
|
+
label: "Rulesets",
|
|
43
|
+
run: () => runAndStoreResult(factories.rulesets, repoConfig, repoInfo, sharedOpts, repoName, settingsCollector, (e, r) => {
|
|
44
|
+
e.rulesetResult = r;
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: "labels",
|
|
49
|
+
label: "Labels",
|
|
50
|
+
run: () => runAndStoreResult(factories.labels, repoConfig, repoInfo, sharedOpts, repoName, settingsCollector, (e, r) => {
|
|
51
|
+
e.labelsResult = r;
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
key: "repo",
|
|
56
|
+
label: "Repo Settings",
|
|
57
|
+
run: () => runAndStoreResult(factories.repo, repoConfig, repoInfo, { dryRun: options.dryRun, token }, repoName, settingsCollector, (e, r) => {
|
|
58
|
+
e.settingsResult = r;
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
key: "codeScanning",
|
|
63
|
+
label: "Code Scanning",
|
|
64
|
+
run: () => runAndStoreResult(factories.codeScanning, repoConfig, repoInfo, sharedOpts, repoName, settingsCollector, (e, r) => {
|
|
65
|
+
e.codeScanningResult = r;
|
|
66
|
+
}),
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
export async function applyRepoSettings(ctx) {
|
|
71
|
+
const { repoConfig, repoInfo, repoName, repoNumber, settingsCollector, logger, } = ctx;
|
|
72
|
+
if (!repoConfig.settings || !isGitHubRepo(repoInfo))
|
|
73
|
+
return;
|
|
74
|
+
for (const desc of buildSettingsDescriptors(ctx)) {
|
|
75
|
+
const settingsValue = repoConfig.settings[desc.key];
|
|
76
|
+
if (!settingsValue || Object.keys(settingsValue).length === 0)
|
|
77
|
+
continue;
|
|
78
|
+
try {
|
|
79
|
+
const result = await desc.run();
|
|
80
|
+
logSettingsResult(logger, result, desc.label, repoNumber, repoName, settingsCollector);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
logger.error(repoNumber, repoName, `${desc.label}: ${toErrorMessage(error)}`);
|
|
84
|
+
settingsCollector.appendError(repoName, error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { SyncDependencies, SyncOptions } from "./types.js";
|
|
2
2
|
export type { SharedOptions, SyncOptions } from "./types.js";
|
|
3
3
|
export declare function runSync(options: SyncOptions, deps?: SyncDependencies): Promise<void>;
|