@aspruyt/xfg 4.0.0 → 4.0.1
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 -2
- package/dist/cli/index.js +0 -1
- package/dist/cli/program.js +7 -2
- package/dist/cli/{settings/results-collector.d.ts → results-collector.d.ts} +1 -1
- package/dist/cli/{settings/results-collector.js → results-collector.js} +2 -1
- package/dist/cli/settings-report-builder.d.ts +1 -3
- package/dist/cli/sync-command.d.ts +2 -24
- package/dist/cli/sync-command.js +295 -301
- package/dist/cli/types.d.ts +60 -40
- package/dist/cli/types.js +1 -12
- package/dist/config/errors.d.ts +9 -0
- package/dist/config/errors.js +11 -0
- package/dist/config/file-reference-resolver.d.ts +2 -1
- package/dist/config/file-reference-resolver.js +10 -8
- package/dist/config/formatter.d.ts +3 -2
- package/dist/config/index.d.ts +4 -6
- package/dist/config/index.js +4 -8
- package/dist/config/loader.js +4 -2
- package/dist/config/merge.d.ts +0 -9
- package/dist/config/merge.js +2 -7
- package/dist/config/normalizer.d.ts +4 -0
- package/dist/config/normalizer.js +61 -110
- package/dist/config/types.d.ts +15 -19
- package/dist/config/types.js +1 -1
- package/dist/config/validator.d.ts +0 -4
- package/dist/config/validator.js +286 -363
- package/dist/config/validators/file-validator.d.ts +2 -8
- package/dist/config/validators/file-validator.js +6 -17
- package/dist/config/validators/index.d.ts +3 -3
- package/dist/config/validators/index.js +3 -3
- package/dist/config/validators/repo-settings-validator.d.ts +0 -6
- package/dist/config/validators/repo-settings-validator.js +9 -9
- package/dist/config/validators/ruleset-validator.d.ts +0 -14
- package/dist/config/validators/ruleset-validator.js +28 -28
- package/dist/lifecycle/ado-migration-source.js +2 -1
- package/dist/lifecycle/github-lifecycle-provider.d.ts +6 -5
- package/dist/lifecycle/github-lifecycle-provider.js +79 -90
- package/dist/lifecycle/index.d.ts +2 -6
- package/dist/lifecycle/index.js +0 -4
- package/dist/lifecycle/lifecycle-formatter.d.ts +2 -1
- package/dist/lifecycle/lifecycle-formatter.js +4 -0
- package/dist/lifecycle/lifecycle-helpers.d.ts +3 -2
- package/dist/lifecycle/repo-lifecycle-manager.js +4 -11
- package/dist/lifecycle/types.d.ts +0 -8
- package/dist/output/github-summary.d.ts +5 -0
- package/dist/output/github-summary.js +9 -2
- package/dist/output/index.d.ts +2 -2
- package/dist/output/index.js +1 -1
- package/dist/output/lifecycle-report.js +5 -23
- package/dist/output/settings-report.d.ts +14 -3
- package/dist/output/settings-report.js +137 -197
- package/dist/output/summary-utils.d.ts +1 -1
- package/dist/output/summary-utils.js +2 -1
- package/dist/output/sync-report.js +5 -8
- package/dist/output/unified-summary.d.ts +2 -1
- package/dist/output/unified-summary.js +71 -133
- package/dist/settings/base-processor.d.ts +67 -0
- package/dist/settings/base-processor.js +91 -0
- package/dist/settings/index.d.ts +4 -3
- package/dist/settings/index.js +3 -3
- package/dist/settings/labels/converter.d.ts +2 -1
- package/dist/settings/labels/github-labels-strategy.d.ts +9 -18
- package/dist/settings/labels/github-labels-strategy.js +17 -73
- package/dist/settings/labels/index.d.ts +2 -6
- package/dist/settings/labels/index.js +1 -9
- package/dist/settings/labels/processor.d.ts +6 -30
- package/dist/settings/labels/processor.js +62 -152
- package/dist/settings/labels/types.d.ts +5 -8
- package/dist/settings/repo-settings/formatter.d.ts +2 -2
- package/dist/settings/repo-settings/formatter.js +6 -6
- package/dist/settings/repo-settings/github-repo-settings-strategy.d.ts +11 -12
- package/dist/settings/repo-settings/github-repo-settings-strategy.js +32 -79
- package/dist/settings/repo-settings/index.d.ts +2 -5
- package/dist/settings/repo-settings/index.js +1 -9
- package/dist/settings/repo-settings/processor.d.ts +6 -27
- package/dist/settings/repo-settings/processor.js +51 -104
- package/dist/settings/repo-settings/types.d.ts +7 -9
- package/dist/settings/rulesets/diff-algorithm.d.ts +0 -4
- package/dist/settings/rulesets/diff-algorithm.js +1 -10
- package/dist/settings/rulesets/diff.d.ts +1 -1
- package/dist/settings/rulesets/diff.js +2 -21
- package/dist/settings/rulesets/formatter.d.ts +1 -3
- package/dist/settings/rulesets/formatter.js +1 -8
- package/dist/settings/rulesets/github-ruleset-strategy.d.ts +11 -51
- package/dist/settings/rulesets/github-ruleset-strategy.js +24 -85
- package/dist/settings/rulesets/index.d.ts +3 -6
- package/dist/settings/rulesets/index.js +5 -9
- package/dist/settings/rulesets/processor.d.ts +8 -33
- package/dist/settings/rulesets/processor.js +58 -151
- package/dist/settings/rulesets/types.d.ts +35 -6
- package/dist/shared/command-executor.d.ts +2 -22
- package/dist/shared/command-executor.js +8 -7
- package/dist/shared/env.d.ts +0 -8
- package/dist/shared/env.js +14 -70
- package/dist/shared/file-status.d.ts +2 -0
- package/dist/shared/file-status.js +13 -0
- package/dist/shared/gh-api-utils.d.ts +46 -0
- package/dist/shared/gh-api-utils.js +107 -0
- package/dist/shared/index.d.ts +5 -5
- package/dist/shared/index.js +3 -3
- package/dist/shared/interpolation-engine.d.ts +31 -0
- package/dist/shared/interpolation-engine.js +50 -0
- package/dist/shared/logger.d.ts +3 -7
- package/dist/shared/logger.js +4 -1
- package/dist/shared/repo-detector.d.ts +17 -2
- package/dist/shared/repo-detector.js +27 -0
- package/dist/shared/retry-utils.d.ts +9 -17
- package/dist/shared/retry-utils.js +22 -28
- package/dist/shared/sanitize-utils.d.ts +0 -7
- package/dist/shared/sanitize-utils.js +0 -7
- package/dist/shared/shell-utils.d.ts +1 -0
- package/dist/shared/shell-utils.js +3 -0
- package/dist/shared/string-utils.d.ts +4 -0
- package/dist/shared/string-utils.js +6 -0
- package/dist/shared/type-guards.d.ts +17 -0
- package/dist/shared/type-guards.js +26 -0
- package/dist/shared/workspace-utils.d.ts +0 -4
- package/dist/shared/workspace-utils.js +0 -4
- package/dist/{sync → shared}/xfg-template.d.ts +3 -2
- package/dist/{sync → shared}/xfg-template.js +13 -54
- package/dist/sync/auth-options-builder.d.ts +4 -5
- package/dist/sync/auth-options-builder.js +15 -26
- package/dist/sync/branch-manager.d.ts +5 -0
- package/dist/sync/branch-manager.js +12 -10
- package/dist/sync/commit-push-manager.d.ts +1 -1
- package/dist/sync/commit-push-manager.js +22 -18
- package/dist/sync/diff-utils.d.ts +4 -9
- package/dist/sync/diff-utils.js +2 -19
- package/dist/sync/file-sync-orchestrator.js +9 -8
- package/dist/sync/file-writer.d.ts +2 -1
- package/dist/sync/file-writer.js +3 -6
- package/dist/sync/index.d.ts +2 -15
- package/dist/sync/index.js +0 -19
- package/dist/sync/manifest-manager.d.ts +4 -0
- package/dist/sync/manifest-manager.js +5 -1
- package/dist/sync/manifest.d.ts +10 -41
- package/dist/sync/manifest.js +11 -56
- package/dist/sync/pr-merge-handler.d.ts +2 -6
- package/dist/sync/pr-merge-handler.js +6 -3
- package/dist/sync/repository-processor.d.ts +1 -2
- package/dist/sync/repository-processor.js +20 -12
- package/dist/sync/repository-session.js +5 -14
- package/dist/sync/sync-workflow.js +31 -38
- package/dist/sync/types.d.ts +43 -178
- package/dist/vcs/authenticated-git-ops.d.ts +27 -70
- package/dist/vcs/authenticated-git-ops.js +70 -96
- package/dist/vcs/azure-pr-strategy.d.ts +6 -4
- package/dist/vcs/azure-pr-strategy.js +34 -82
- package/dist/vcs/branch-utils.d.ts +6 -0
- package/dist/vcs/branch-utils.js +29 -0
- package/dist/vcs/commit-strategy-selector.d.ts +5 -0
- package/dist/vcs/commit-strategy-selector.js +10 -0
- package/dist/vcs/git-commit-strategy.js +1 -2
- package/dist/vcs/git-ops.d.ts +15 -59
- package/dist/vcs/git-ops.js +46 -110
- package/dist/vcs/github-app-token-manager.d.ts +0 -6
- package/dist/vcs/github-app-token-manager.js +5 -12
- package/dist/vcs/github-pr-strategy.d.ts +5 -5
- package/dist/vcs/github-pr-strategy.js +44 -122
- package/dist/vcs/gitlab-pr-strategy.d.ts +6 -4
- package/dist/vcs/gitlab-pr-strategy.js +39 -87
- package/dist/vcs/graphql-commit-strategy.d.ts +3 -4
- package/dist/vcs/graphql-commit-strategy.js +31 -63
- package/dist/vcs/index.d.ts +3 -16
- package/dist/vcs/index.js +2 -33
- package/dist/vcs/pr-creator.d.ts +9 -9
- package/dist/vcs/pr-creator.js +11 -10
- package/dist/vcs/pr-strategy-factory.d.ts +5 -0
- package/dist/vcs/pr-strategy-factory.js +17 -0
- package/dist/vcs/pr-strategy.d.ts +13 -26
- package/dist/vcs/pr-strategy.js +20 -25
- package/dist/vcs/types.d.ts +87 -21
- package/package.json +2 -1
package/dist/sync/index.d.ts
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export { BranchManager } from "./branch-manager.js";
|
|
4
|
-
export { AuthOptionsBuilder } from "./auth-options-builder.js";
|
|
5
|
-
export { RepositorySession } from "./repository-session.js";
|
|
6
|
-
export { CommitPushManager } from "./commit-push-manager.js";
|
|
7
|
-
export { formatCommitMessage } from "./commit-message.js";
|
|
8
|
-
export { FileSyncOrchestrator } from "./file-sync-orchestrator.js";
|
|
9
|
-
export { PRMergeHandler } from "./pr-merge-handler.js";
|
|
10
|
-
export { FileSyncStrategy } from "./file-sync-strategy.js";
|
|
11
|
-
export { SyncWorkflow } from "./sync-workflow.js";
|
|
12
|
-
export type { IFileWriter, FileWriteContext, FileWriterDeps, FileWriteAllResult, FileWriteResult, IManifestManager, OrphanProcessResult, OrphanDeleteOptions, OrphanDeleteDeps, IBranchManager, BranchSetupOptions, IAuthOptionsBuilder, AuthResult, IRepositorySession, SessionOptions, SessionContext, ICommitPushManager, CommitPushOptions, CommitPushResult, GitOpsFactory, IRepositoryProcessor, ProcessorOptions, ProcessorResult, FileChangeDetail, IFileSyncOrchestrator, FileSyncResult, IPRMergeHandler, PRHandlerOptions, WorkResult, IWorkStrategy, ISyncWorkflow, } from "./types.js";
|
|
1
|
+
export type { DiffStats } from "./diff-utils.js";
|
|
2
|
+
export type { GitOpsFactory, IAuthOptionsBuilder, IBranchManager, ICommitPushManager, IFileSyncOrchestrator, IPRMergeHandler, IRepositoryProcessor, IRepositorySession, ISyncWorkflow, IWorkStrategy, ProcessorResult, SessionContext, WorkResult, } from "./types.js";
|
|
13
3
|
export { RepositoryProcessor } from "./repository-processor.js";
|
|
14
|
-
export { createEmptyManifest, loadManifest, saveManifest, getManagedFiles, updateManifest, MANIFEST_FILENAME, type XfgManifest, type XfgManifestConfigEntry, } from "./manifest.js";
|
|
15
|
-
export { getFileStatus, formatStatusBadge, formatDiffLine, generateDiff, createDiffStats, incrementDiffStats, type FileStatus, type DiffStats, } from "./diff-utils.js";
|
|
16
|
-
export { interpolateXfgContent, type XfgTemplateContext, type XfgInterpolationOptions, } from "./xfg-template.js";
|
package/dist/sync/index.js
CHANGED
|
@@ -1,20 +1 @@
|
|
|
1
|
-
export { FileWriter, shouldBeExecutable } from "./file-writer.js";
|
|
2
|
-
export { ManifestManager } from "./manifest-manager.js";
|
|
3
|
-
export { BranchManager } from "./branch-manager.js";
|
|
4
|
-
export { AuthOptionsBuilder } from "./auth-options-builder.js";
|
|
5
|
-
export { RepositorySession } from "./repository-session.js";
|
|
6
|
-
export { CommitPushManager } from "./commit-push-manager.js";
|
|
7
|
-
export { formatCommitMessage } from "./commit-message.js";
|
|
8
|
-
export { FileSyncOrchestrator } from "./file-sync-orchestrator.js";
|
|
9
|
-
export { PRMergeHandler } from "./pr-merge-handler.js";
|
|
10
|
-
// Strategy pattern components
|
|
11
|
-
export { FileSyncStrategy } from "./file-sync-strategy.js";
|
|
12
|
-
export { SyncWorkflow } from "./sync-workflow.js";
|
|
13
|
-
// Repository processor
|
|
14
1
|
export { RepositoryProcessor } from "./repository-processor.js";
|
|
15
|
-
// Manifest handling
|
|
16
|
-
export { createEmptyManifest, loadManifest, saveManifest, getManagedFiles, updateManifest, MANIFEST_FILENAME, } from "./manifest.js";
|
|
17
|
-
// Diff utilities
|
|
18
|
-
export { getFileStatus, formatStatusBadge, formatDiffLine, generateDiff, createDiffStats, incrementDiffStats, } from "./diff-utils.js";
|
|
19
|
-
// XFG templating
|
|
20
|
-
export { interpolateXfgContent, } from "./xfg-template.js";
|
|
@@ -4,6 +4,10 @@ import type { IManifestManager, OrphanProcessResult, OrphanDeleteOptions, Orphan
|
|
|
4
4
|
* Handles manifest loading, saving, and orphan detection.
|
|
5
5
|
*/
|
|
6
6
|
export declare class ManifestManager implements IManifestManager {
|
|
7
|
+
private readonly log?;
|
|
8
|
+
constructor(log?: {
|
|
9
|
+
debug(msg: string): void;
|
|
10
|
+
} | undefined);
|
|
7
11
|
processOrphans(workDir: string, configId: string, filesWithDeleteOrphaned: Map<string, boolean | undefined>): OrphanProcessResult;
|
|
8
12
|
deleteOrphans(filesToDelete: string[], options: OrphanDeleteOptions, deps: OrphanDeleteDeps): Promise<void>;
|
|
9
13
|
saveUpdatedManifest(workDir: string, manifest: XfgManifest, existingManifest: XfgManifest | null, dryRun: boolean, fileChanges: Map<string, FileWriteResult>): void;
|
|
@@ -5,8 +5,12 @@ import { loadManifest, saveManifest, updateManifest, MANIFEST_FILENAME, } from "
|
|
|
5
5
|
* Handles manifest loading, saving, and orphan detection.
|
|
6
6
|
*/
|
|
7
7
|
export class ManifestManager {
|
|
8
|
+
log;
|
|
9
|
+
constructor(log) {
|
|
10
|
+
this.log = log;
|
|
11
|
+
}
|
|
8
12
|
processOrphans(workDir, configId, filesWithDeleteOrphaned) {
|
|
9
|
-
const existingManifest = loadManifest(workDir);
|
|
13
|
+
const existingManifest = loadManifest(workDir, this.log);
|
|
10
14
|
const { manifest, filesToDelete } = updateManifest(existingManifest, configId, filesWithDeleteOrphaned);
|
|
11
15
|
return { manifest, filesToDelete };
|
|
12
16
|
}
|
package/dist/sync/manifest.d.ts
CHANGED
|
@@ -6,57 +6,26 @@ export interface XfgManifest {
|
|
|
6
6
|
version: 4;
|
|
7
7
|
configs: Record<string, XfgManifestConfigEntry>;
|
|
8
8
|
}
|
|
9
|
-
/**
|
|
10
|
-
* Creates an empty manifest with the current version.
|
|
11
|
-
*/
|
|
12
9
|
export declare function createEmptyManifest(): XfgManifest;
|
|
13
10
|
/**
|
|
14
|
-
* Loads
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* V1 manifests are treated as non-existent because they lack the config ID
|
|
18
|
-
* namespace required for multi-config support. The next run will create
|
|
19
|
-
* a fresh v4 manifest.
|
|
20
|
-
*
|
|
21
|
-
* V2/V3 manifests are automatically migrated to V4 format.
|
|
22
|
-
*
|
|
23
|
-
* @param workDir - The repository working directory
|
|
24
|
-
* @returns The manifest or null if not found or incompatible
|
|
11
|
+
* Loads and migrates manifest from workDir. V1 returns null (no config-ID namespace);
|
|
12
|
+
* V2/V3 are auto-migrated to V4.
|
|
25
13
|
*/
|
|
26
|
-
export declare function loadManifest(workDir: string
|
|
14
|
+
export declare function loadManifest(workDir: string, log?: {
|
|
15
|
+
debug(msg: string): void;
|
|
16
|
+
}): XfgManifest | null;
|
|
27
17
|
/**
|
|
28
18
|
* Parses manifest content from a string (e.g., fetched from a remote API).
|
|
29
19
|
* Handles V2→V3 migration, returns null for V1/unknown/invalid formats.
|
|
30
20
|
*/
|
|
31
|
-
export declare function parseManifestContent(content: string
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
* @param workDir - The repository working directory
|
|
36
|
-
* @param manifest - The manifest to save
|
|
37
|
-
*/
|
|
21
|
+
export declare function parseManifestContent(content: string, log?: {
|
|
22
|
+
debug(msg: string): void;
|
|
23
|
+
}): XfgManifest | null;
|
|
38
24
|
export declare function saveManifest(workDir: string, manifest: XfgManifest): void;
|
|
39
|
-
/**
|
|
40
|
-
* Gets the list of managed files for a specific config from a manifest.
|
|
41
|
-
* Returns an empty array if the manifest is null or the config isn't found.
|
|
42
|
-
*
|
|
43
|
-
* @param manifest - The manifest or null
|
|
44
|
-
* @param configId - The config ID to get files for
|
|
45
|
-
* @returns Array of managed file names for the given config
|
|
46
|
-
*/
|
|
47
25
|
export declare function getManagedFiles(manifest: XfgManifest | null, configId: string): string[];
|
|
48
26
|
/**
|
|
49
|
-
* Updates
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* Files with deleteOrphaned: true are added to managedFiles.
|
|
53
|
-
* Files with deleteOrphaned: false (explicit) are removed from managedFiles.
|
|
54
|
-
* Files not in the config but in managedFiles for this configId are candidates for deletion.
|
|
55
|
-
*
|
|
56
|
-
* @param manifest - The existing manifest (or null for new repos)
|
|
57
|
-
* @param configId - The config ID to update
|
|
58
|
-
* @param filesWithDeleteOrphaned - Map of fileName to deleteOrphaned value (true/false/undefined)
|
|
59
|
-
* @returns Updated manifest and list of files to delete
|
|
27
|
+
* Updates manifest tracking for a config. Files with deleteOrphaned: true are tracked;
|
|
28
|
+
* files previously tracked but no longer in config are returned as filesToDelete.
|
|
60
29
|
*/
|
|
61
30
|
export declare function updateManifest(manifest: XfgManifest | null, configId: string, filesWithDeleteOrphaned: Map<string, boolean | undefined>): {
|
|
62
31
|
manifest: XfgManifest;
|
package/dist/sync/manifest.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
export const MANIFEST_FILENAME = ".xfg.json";
|
|
4
|
-
/**
|
|
5
|
-
* Type guard to check if a manifest is v1 format.
|
|
6
|
-
*/
|
|
7
4
|
function isV1Manifest(manifest) {
|
|
8
5
|
return (typeof manifest === "object" &&
|
|
9
6
|
manifest !== null &&
|
|
10
7
|
manifest.version === 1 &&
|
|
11
8
|
Array.isArray(manifest.managedFiles));
|
|
12
9
|
}
|
|
13
|
-
/**
|
|
14
|
-
* Type guard to check if a manifest is v2 format.
|
|
15
|
-
*/
|
|
16
10
|
function isV2Manifest(manifest) {
|
|
17
11
|
return (typeof manifest === "object" &&
|
|
18
12
|
manifest !== null &&
|
|
@@ -20,9 +14,6 @@ function isV2Manifest(manifest) {
|
|
|
20
14
|
typeof manifest.configs === "object" &&
|
|
21
15
|
manifest.configs !== null);
|
|
22
16
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Type guard to check if a manifest is v3 format.
|
|
25
|
-
*/
|
|
26
17
|
function isV3Manifest(manifest) {
|
|
27
18
|
return (typeof manifest === "object" &&
|
|
28
19
|
manifest !== null &&
|
|
@@ -30,9 +21,6 @@ function isV3Manifest(manifest) {
|
|
|
30
21
|
typeof manifest.configs === "object" &&
|
|
31
22
|
manifest.configs !== null);
|
|
32
23
|
}
|
|
33
|
-
/**
|
|
34
|
-
* Type guard to check if a manifest is v4 format.
|
|
35
|
-
*/
|
|
36
24
|
function isV4Manifest(manifest) {
|
|
37
25
|
return (typeof manifest === "object" &&
|
|
38
26
|
manifest !== null &&
|
|
@@ -72,9 +60,6 @@ function migrateV3ToV4(v3) {
|
|
|
72
60
|
}
|
|
73
61
|
return { version: 4, configs: v4Configs };
|
|
74
62
|
}
|
|
75
|
-
/**
|
|
76
|
-
* Creates an empty manifest with the current version.
|
|
77
|
-
*/
|
|
78
63
|
export function createEmptyManifest() {
|
|
79
64
|
return {
|
|
80
65
|
version: 4,
|
|
@@ -82,19 +67,10 @@ export function createEmptyManifest() {
|
|
|
82
67
|
};
|
|
83
68
|
}
|
|
84
69
|
/**
|
|
85
|
-
* Loads
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* V1 manifests are treated as non-existent because they lack the config ID
|
|
89
|
-
* namespace required for multi-config support. The next run will create
|
|
90
|
-
* a fresh v4 manifest.
|
|
91
|
-
*
|
|
92
|
-
* V2/V3 manifests are automatically migrated to V4 format.
|
|
93
|
-
*
|
|
94
|
-
* @param workDir - The repository working directory
|
|
95
|
-
* @returns The manifest or null if not found or incompatible
|
|
70
|
+
* Loads and migrates manifest from workDir. V1 returns null (no config-ID namespace);
|
|
71
|
+
* V2/V3 are auto-migrated to V4.
|
|
96
72
|
*/
|
|
97
|
-
export function loadManifest(workDir) {
|
|
73
|
+
export function loadManifest(workDir, log) {
|
|
98
74
|
const manifestPath = join(workDir, MANIFEST_FILENAME);
|
|
99
75
|
if (!existsSync(manifestPath)) {
|
|
100
76
|
return null;
|
|
@@ -121,7 +97,8 @@ export function loadManifest(workDir) {
|
|
|
121
97
|
// Unknown format - treat as no manifest
|
|
122
98
|
return null;
|
|
123
99
|
}
|
|
124
|
-
catch {
|
|
100
|
+
catch (error) {
|
|
101
|
+
log?.debug(`Failed to load manifest from ${manifestPath}: ${error}`);
|
|
125
102
|
return null;
|
|
126
103
|
}
|
|
127
104
|
}
|
|
@@ -129,7 +106,7 @@ export function loadManifest(workDir) {
|
|
|
129
106
|
* Parses manifest content from a string (e.g., fetched from a remote API).
|
|
130
107
|
* Handles V2→V3 migration, returns null for V1/unknown/invalid formats.
|
|
131
108
|
*/
|
|
132
|
-
export function parseManifestContent(content) {
|
|
109
|
+
export function parseManifestContent(content, log) {
|
|
133
110
|
try {
|
|
134
111
|
const parsed = JSON.parse(content);
|
|
135
112
|
if (isV4Manifest(parsed)) {
|
|
@@ -143,29 +120,16 @@ export function parseManifestContent(content) {
|
|
|
143
120
|
}
|
|
144
121
|
return null;
|
|
145
122
|
}
|
|
146
|
-
catch {
|
|
123
|
+
catch (error) {
|
|
124
|
+
log?.debug(`Failed to parse manifest content: ${error}`);
|
|
147
125
|
return null;
|
|
148
126
|
}
|
|
149
127
|
}
|
|
150
|
-
/**
|
|
151
|
-
* Saves the xfg manifest to a repository's working directory.
|
|
152
|
-
*
|
|
153
|
-
* @param workDir - The repository working directory
|
|
154
|
-
* @param manifest - The manifest to save
|
|
155
|
-
*/
|
|
156
128
|
export function saveManifest(workDir, manifest) {
|
|
157
129
|
const manifestPath = join(workDir, MANIFEST_FILENAME);
|
|
158
130
|
const content = JSON.stringify(manifest, null, 2) + "\n";
|
|
159
131
|
writeFileSync(manifestPath, content, "utf-8");
|
|
160
132
|
}
|
|
161
|
-
/**
|
|
162
|
-
* Gets the list of managed files for a specific config from a manifest.
|
|
163
|
-
* Returns an empty array if the manifest is null or the config isn't found.
|
|
164
|
-
*
|
|
165
|
-
* @param manifest - The manifest or null
|
|
166
|
-
* @param configId - The config ID to get files for
|
|
167
|
-
* @returns Array of managed file names for the given config
|
|
168
|
-
*/
|
|
169
133
|
export function getManagedFiles(manifest, configId) {
|
|
170
134
|
if (!manifest) {
|
|
171
135
|
return [];
|
|
@@ -173,17 +137,8 @@ export function getManagedFiles(manifest, configId) {
|
|
|
173
137
|
return [...(manifest.configs[configId]?.files ?? [])];
|
|
174
138
|
}
|
|
175
139
|
/**
|
|
176
|
-
* Updates
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* Files with deleteOrphaned: true are added to managedFiles.
|
|
180
|
-
* Files with deleteOrphaned: false (explicit) are removed from managedFiles.
|
|
181
|
-
* Files not in the config but in managedFiles for this configId are candidates for deletion.
|
|
182
|
-
*
|
|
183
|
-
* @param manifest - The existing manifest (or null for new repos)
|
|
184
|
-
* @param configId - The config ID to update
|
|
185
|
-
* @param filesWithDeleteOrphaned - Map of fileName to deleteOrphaned value (true/false/undefined)
|
|
186
|
-
* @returns Updated manifest and list of files to delete
|
|
140
|
+
* Updates manifest tracking for a config. Files with deleteOrphaned: true are tracked;
|
|
141
|
+
* files previously tracked but no longer in config are returned as filesToDelete.
|
|
187
142
|
*/
|
|
188
143
|
export function updateManifest(manifest, configId, filesWithDeleteOrphaned) {
|
|
189
144
|
// Get existing managed files for this config only
|
|
@@ -211,7 +166,7 @@ export function updateManifest(manifest, configId, filesWithDeleteOrphaned) {
|
|
|
211
166
|
...(manifest?.configs ?? {}),
|
|
212
167
|
};
|
|
213
168
|
// Update this config's managed files
|
|
214
|
-
const sortedManaged = Array.from(newManaged).sort();
|
|
169
|
+
const sortedManaged = Array.from(newManaged).sort((a, b) => a.localeCompare(b));
|
|
215
170
|
if (sortedManaged.length > 0) {
|
|
216
171
|
updatedConfigs[configId] = { files: sortedManaged };
|
|
217
172
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import type { RepoConfig } from "../config/index.js";
|
|
2
|
-
import type { RepoInfo } from "../shared/repo-detector.js";
|
|
3
1
|
import type { ILogger } from "../shared/logger.js";
|
|
4
|
-
import {
|
|
5
|
-
import type { DiffStats } from "./diff-utils.js";
|
|
6
|
-
import type { ProcessorResult, PRHandlerOptions, IPRMergeHandler, FileChangeDetail } from "./types.js";
|
|
2
|
+
import type { ProcessorResult, IPRMergeHandler, CreateAndMergeInput } from "./types.js";
|
|
7
3
|
export declare class PRMergeHandler implements IPRMergeHandler {
|
|
8
4
|
private readonly log;
|
|
9
5
|
constructor(log: ILogger);
|
|
10
|
-
createAndMerge(
|
|
6
|
+
createAndMerge(input: CreateAndMergeInput): Promise<ProcessorResult>;
|
|
11
7
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { createPR, mergePR
|
|
1
|
+
import { createPR, mergePR } from "../vcs/pr-creator.js";
|
|
2
2
|
export class PRMergeHandler {
|
|
3
3
|
log;
|
|
4
4
|
constructor(log) {
|
|
5
5
|
this.log = log;
|
|
6
6
|
}
|
|
7
|
-
async createAndMerge(
|
|
7
|
+
async createAndMerge(input) {
|
|
8
|
+
const { repoInfo, repoConfig, options, changedFiles, repoName, diffStats, fileChanges, } = input;
|
|
8
9
|
this.log.info("Creating pull request...");
|
|
9
10
|
const prResult = await createPR({
|
|
10
11
|
repoInfo,
|
|
@@ -18,6 +19,7 @@ export class PRMergeHandler {
|
|
|
18
19
|
executor: options.executor,
|
|
19
20
|
token: options.token,
|
|
20
21
|
labels: repoConfig.prOptions?.labels,
|
|
22
|
+
log: this.log,
|
|
21
23
|
});
|
|
22
24
|
const mergeMode = repoConfig.prOptions?.merge ?? "auto";
|
|
23
25
|
let mergeResult;
|
|
@@ -38,6 +40,7 @@ export class PRMergeHandler {
|
|
|
38
40
|
retries: options.retries,
|
|
39
41
|
executor: options.executor,
|
|
40
42
|
token: options.token,
|
|
43
|
+
log: this.log,
|
|
41
44
|
});
|
|
42
45
|
mergeResult = {
|
|
43
46
|
merged: result.merged ?? false,
|
|
@@ -45,7 +48,7 @@ export class PRMergeHandler {
|
|
|
45
48
|
message: result.message,
|
|
46
49
|
};
|
|
47
50
|
if (!result.success) {
|
|
48
|
-
this.log.
|
|
51
|
+
this.log.warn(`Merge operation failed - ${result.message}`);
|
|
49
52
|
}
|
|
50
53
|
else {
|
|
51
54
|
this.log.info(result.message);
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { RepoConfig } from "../config/index.js";
|
|
2
2
|
import type { RepoInfo } from "../shared/repo-detector.js";
|
|
3
3
|
import { ILogger } from "../shared/logger.js";
|
|
4
|
-
import {
|
|
4
|
+
import type { IFileWriter, IManifestManager, IBranchManager, IAuthOptionsBuilder, IRepositorySession, ICommitPushManager, IFileSyncOrchestrator, IPRMergeHandler, ISyncWorkflow, IRepositoryProcessor, GitOpsFactory, ProcessorOptions, ProcessorResult } from "./types.js";
|
|
5
5
|
/**
|
|
6
6
|
* Thin facade that delegates to SyncWorkflow with FileSyncStrategy.
|
|
7
7
|
*/
|
|
8
8
|
export declare class RepositoryProcessor implements IRepositoryProcessor {
|
|
9
9
|
private readonly syncWorkflow;
|
|
10
10
|
private readonly fileSyncOrchestrator;
|
|
11
|
-
private readonly log;
|
|
12
11
|
constructor(gitOpsFactory?: GitOpsFactory, log?: ILogger, components?: {
|
|
13
12
|
fileWriter?: IFileWriter;
|
|
14
13
|
manifestManager?: IManifestManager;
|
|
@@ -1,28 +1,36 @@
|
|
|
1
1
|
import { GitOps } from "../vcs/git-ops.js";
|
|
2
2
|
import { AuthenticatedGitOps } from "../vcs/authenticated-git-ops.js";
|
|
3
|
+
import { defaultExecutor } from "../shared/command-executor.js";
|
|
3
4
|
import { logger } from "../shared/logger.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { createTokenManager } from "../vcs/index.js";
|
|
6
|
+
import { FileWriter } from "./file-writer.js";
|
|
7
|
+
import { ManifestManager } from "./manifest-manager.js";
|
|
8
|
+
import { BranchManager } from "./branch-manager.js";
|
|
9
|
+
import { AuthOptionsBuilder } from "./auth-options-builder.js";
|
|
10
|
+
import { RepositorySession } from "./repository-session.js";
|
|
11
|
+
import { CommitPushManager } from "./commit-push-manager.js";
|
|
12
|
+
import { FileSyncOrchestrator } from "./file-sync-orchestrator.js";
|
|
13
|
+
import { PRMergeHandler } from "./pr-merge-handler.js";
|
|
14
|
+
import { FileSyncStrategy } from "./file-sync-strategy.js";
|
|
15
|
+
import { SyncWorkflow } from "./sync-workflow.js";
|
|
7
16
|
/**
|
|
8
17
|
* Thin facade that delegates to SyncWorkflow with FileSyncStrategy.
|
|
9
18
|
*/
|
|
10
19
|
export class RepositoryProcessor {
|
|
11
20
|
syncWorkflow;
|
|
12
21
|
fileSyncOrchestrator;
|
|
13
|
-
log;
|
|
14
22
|
constructor(gitOpsFactory, log, components) {
|
|
15
|
-
const factory = gitOpsFactory ??
|
|
16
|
-
((opts, auth) => new AuthenticatedGitOps(new GitOps(opts), auth));
|
|
17
23
|
const logInstance = log ?? logger;
|
|
18
|
-
|
|
24
|
+
const factory = gitOpsFactory ??
|
|
25
|
+
((opts, auth, retries) => {
|
|
26
|
+
const gitOps = new GitOps({ ...opts, log: logInstance });
|
|
27
|
+
return new AuthenticatedGitOps(gitOps, opts.executor ?? defaultExecutor, opts.workDir, retries ?? 3, auth, logInstance);
|
|
28
|
+
});
|
|
19
29
|
// Initialize token manager for auth builder
|
|
20
|
-
const tokenManager =
|
|
21
|
-
? new GitHubAppTokenManager(process.env.XFG_GITHUB_APP_ID, process.env.XFG_GITHUB_APP_PRIVATE_KEY)
|
|
22
|
-
: null;
|
|
30
|
+
const tokenManager = createTokenManager();
|
|
23
31
|
const fileWriter = components?.fileWriter ?? new FileWriter();
|
|
24
|
-
const manifestManager = components?.manifestManager ?? new ManifestManager();
|
|
25
|
-
const branchManager = components?.branchManager ?? new BranchManager();
|
|
32
|
+
const manifestManager = components?.manifestManager ?? new ManifestManager(logInstance);
|
|
33
|
+
const branchManager = components?.branchManager ?? new BranchManager(logInstance);
|
|
26
34
|
const authOptionsBuilder = components?.authOptionsBuilder ??
|
|
27
35
|
new AuthOptionsBuilder(tokenManager, logInstance);
|
|
28
36
|
const repositorySession = components?.repositorySession ??
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { safeCleanup } from "../shared/type-guards.js";
|
|
1
2
|
export class RepositorySession {
|
|
2
3
|
gitOpsFactory;
|
|
3
4
|
log;
|
|
@@ -7,28 +8,18 @@ export class RepositorySession {
|
|
|
7
8
|
}
|
|
8
9
|
async setup(repoInfo, options) {
|
|
9
10
|
const { workDir, dryRun, retries, authOptions } = options;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// Clean workspace
|
|
13
|
-
this.log.info("Cleaning workspace...");
|
|
11
|
+
const gitOps = this.gitOpsFactory({ workDir, dryRun }, authOptions, retries);
|
|
12
|
+
this.log.debug("Cleaning workspace...");
|
|
14
13
|
gitOps.cleanWorkspace();
|
|
15
|
-
|
|
16
|
-
this.log.info("Cloning repository...");
|
|
14
|
+
this.log.debug("Cloning repository...");
|
|
17
15
|
await gitOps.clone(repoInfo.gitUrl);
|
|
18
|
-
// Detect default branch
|
|
19
16
|
const { branch: baseBranch, method: detectionMethod } = await gitOps.getDefaultBranch();
|
|
20
17
|
this.log.info(`Default branch: ${baseBranch} (detected via ${detectionMethod})`);
|
|
21
|
-
// Return context with cleanup function
|
|
22
18
|
return {
|
|
23
19
|
gitOps,
|
|
24
20
|
baseBranch,
|
|
25
21
|
cleanup: () => {
|
|
26
|
-
|
|
27
|
-
gitOps.cleanWorkspace();
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
// Ignore cleanup errors - best effort
|
|
31
|
-
}
|
|
22
|
+
safeCleanup(() => gitOps.cleanWorkspace(), "workspace removal failed", this.log);
|
|
32
23
|
},
|
|
33
24
|
};
|
|
34
25
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getRepoDisplayName } from "../shared/repo-detector.js";
|
|
2
|
+
import { safeCleanup } from "../shared/type-guards.js";
|
|
2
3
|
import { defaultExecutor } from "../shared/command-executor.js";
|
|
3
4
|
/**
|
|
4
5
|
* Orchestrates the common sync workflow steps.
|
|
@@ -21,47 +22,37 @@ export class SyncWorkflow {
|
|
|
21
22
|
}
|
|
22
23
|
async execute(repoConfig, repoInfo, options, workStrategy) {
|
|
23
24
|
const repoName = getRepoDisplayName(repoInfo);
|
|
24
|
-
const { branchName, workDir
|
|
25
|
+
const { branchName, workDir } = options;
|
|
26
|
+
const dryRun = options.dryRun ?? false;
|
|
25
27
|
const retries = options.retries ?? 3;
|
|
26
28
|
const executor = options.executor ?? defaultExecutor;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (authResult.skipResult) {
|
|
29
|
+
const authResult = await this.authOptionsBuilder.resolve(repoInfo, repoName, options.token);
|
|
30
|
+
if (!authResult.ok) {
|
|
30
31
|
return authResult.skipResult;
|
|
31
32
|
}
|
|
32
|
-
// Step 2: Determine merge mode
|
|
33
33
|
const mergeMode = repoConfig.prOptions?.merge ?? "auto";
|
|
34
34
|
const isDirectMode = mergeMode === "direct";
|
|
35
|
-
// Warn if mergeStrategy is set but ignored in direct mode
|
|
36
|
-
if (isDirectMode && repoConfig.prOptions?.mergeStrategy) {
|
|
37
|
-
this.log.info(`Warning: mergeStrategy '${repoConfig.prOptions.mergeStrategy}' is ignored in direct mode`);
|
|
38
|
-
}
|
|
39
35
|
let session = null;
|
|
40
36
|
try {
|
|
41
|
-
// Step 3: Setup session
|
|
42
37
|
session = await this.repositorySession.setup(repoInfo, {
|
|
43
38
|
workDir,
|
|
44
|
-
dryRun
|
|
39
|
+
dryRun,
|
|
45
40
|
retries,
|
|
46
41
|
authOptions: authResult.authOptions,
|
|
47
42
|
});
|
|
48
|
-
// Step 4: Setup branch
|
|
49
43
|
await this.branchManager.setupBranch({
|
|
50
44
|
repoInfo,
|
|
51
45
|
branchName,
|
|
52
46
|
baseBranch: session.baseBranch,
|
|
53
47
|
workDir,
|
|
54
48
|
isDirectMode,
|
|
55
|
-
dryRun
|
|
49
|
+
dryRun,
|
|
56
50
|
retries,
|
|
57
51
|
token: authResult.token,
|
|
58
52
|
gitOps: session.gitOps,
|
|
59
|
-
log: this.log,
|
|
60
53
|
executor,
|
|
61
54
|
});
|
|
62
|
-
// Step 5: Execute work strategy
|
|
63
55
|
const workResult = await workStrategy.execute(repoConfig, repoInfo, session, options);
|
|
64
|
-
// Step 6: No changes - skip
|
|
65
56
|
if (!workResult) {
|
|
66
57
|
return {
|
|
67
58
|
success: true,
|
|
@@ -70,7 +61,6 @@ export class SyncWorkflow {
|
|
|
70
61
|
skipped: true,
|
|
71
62
|
};
|
|
72
63
|
}
|
|
73
|
-
// Step 7: Commit and push
|
|
74
64
|
const pushBranch = isDirectMode ? session.baseBranch : branchName;
|
|
75
65
|
const commitResult = await this.commitPushManager.commitAndPush({
|
|
76
66
|
repoInfo,
|
|
@@ -80,13 +70,12 @@ export class SyncWorkflow {
|
|
|
80
70
|
commitMessage: workResult.commitMessage,
|
|
81
71
|
pushBranch,
|
|
82
72
|
isDirectMode,
|
|
83
|
-
dryRun
|
|
73
|
+
dryRun,
|
|
84
74
|
retries,
|
|
85
75
|
token: authResult.token,
|
|
86
76
|
executor,
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!commitResult.success && commitResult.errorResult) {
|
|
77
|
+
});
|
|
78
|
+
if (!commitResult.success) {
|
|
90
79
|
return commitResult.errorResult;
|
|
91
80
|
}
|
|
92
81
|
if (commitResult.skipped) {
|
|
@@ -99,7 +88,6 @@ export class SyncWorkflow {
|
|
|
99
88
|
fileChanges: workResult.fileChangeDetails,
|
|
100
89
|
};
|
|
101
90
|
}
|
|
102
|
-
// Step 9: Direct mode - done
|
|
103
91
|
if (isDirectMode) {
|
|
104
92
|
this.log.info(`Changes pushed directly to ${session.baseBranch}`);
|
|
105
93
|
return {
|
|
@@ -110,24 +98,29 @@ export class SyncWorkflow {
|
|
|
110
98
|
fileChanges: workResult.fileChangeDetails,
|
|
111
99
|
};
|
|
112
100
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
101
|
+
return await this.prMergeHandler.createAndMerge({
|
|
102
|
+
repoInfo,
|
|
103
|
+
repoConfig,
|
|
104
|
+
options: {
|
|
105
|
+
branchName,
|
|
106
|
+
baseBranch: session.baseBranch,
|
|
107
|
+
workDir,
|
|
108
|
+
dryRun,
|
|
109
|
+
retries,
|
|
110
|
+
prTemplate: options.prTemplate,
|
|
111
|
+
token: authResult.token,
|
|
112
|
+
executor,
|
|
113
|
+
},
|
|
114
|
+
changedFiles: workResult.changedFiles,
|
|
115
|
+
repoName,
|
|
116
|
+
diffStats: workResult.diffStats,
|
|
117
|
+
fileChanges: workResult.fileChangeDetails,
|
|
118
|
+
});
|
|
124
119
|
}
|
|
125
120
|
finally {
|
|
126
|
-
|
|
127
|
-
session
|
|
128
|
-
|
|
129
|
-
catch {
|
|
130
|
-
// Ignore cleanup errors - best effort
|
|
121
|
+
if (session) {
|
|
122
|
+
const s = session;
|
|
123
|
+
safeCleanup(() => s.cleanup(), "session teardown failed", this.log);
|
|
131
124
|
}
|
|
132
125
|
}
|
|
133
126
|
}
|