@aspruyt/xfg 4.0.0 → 4.0.2

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.
Files changed (174) hide show
  1. package/README.md +1 -2
  2. package/dist/cli/index.d.ts +1 -2
  3. package/dist/cli/index.js +0 -1
  4. package/dist/cli/program.js +7 -2
  5. package/dist/cli/{settings/results-collector.d.ts → results-collector.d.ts} +1 -1
  6. package/dist/cli/{settings/results-collector.js → results-collector.js} +2 -1
  7. package/dist/cli/settings-report-builder.d.ts +1 -3
  8. package/dist/cli/sync-command.d.ts +2 -24
  9. package/dist/cli/sync-command.js +295 -301
  10. package/dist/cli/types.d.ts +60 -40
  11. package/dist/cli/types.js +1 -12
  12. package/dist/config/errors.d.ts +9 -0
  13. package/dist/config/errors.js +11 -0
  14. package/dist/config/file-reference-resolver.d.ts +2 -1
  15. package/dist/config/file-reference-resolver.js +10 -8
  16. package/dist/config/formatter.d.ts +3 -2
  17. package/dist/config/index.d.ts +4 -6
  18. package/dist/config/index.js +4 -8
  19. package/dist/config/loader.js +4 -2
  20. package/dist/config/merge.d.ts +0 -9
  21. package/dist/config/merge.js +2 -7
  22. package/dist/config/normalizer.d.ts +4 -0
  23. package/dist/config/normalizer.js +61 -110
  24. package/dist/config/types.d.ts +15 -19
  25. package/dist/config/types.js +1 -1
  26. package/dist/config/validator.d.ts +0 -4
  27. package/dist/config/validator.js +286 -363
  28. package/dist/config/validators/file-validator.d.ts +2 -8
  29. package/dist/config/validators/file-validator.js +6 -17
  30. package/dist/config/validators/index.d.ts +3 -3
  31. package/dist/config/validators/index.js +3 -3
  32. package/dist/config/validators/repo-settings-validator.d.ts +0 -6
  33. package/dist/config/validators/repo-settings-validator.js +9 -9
  34. package/dist/config/validators/ruleset-validator.d.ts +0 -14
  35. package/dist/config/validators/ruleset-validator.js +28 -28
  36. package/dist/lifecycle/ado-migration-source.js +2 -1
  37. package/dist/lifecycle/github-lifecycle-provider.d.ts +6 -5
  38. package/dist/lifecycle/github-lifecycle-provider.js +79 -90
  39. package/dist/lifecycle/index.d.ts +2 -6
  40. package/dist/lifecycle/index.js +0 -4
  41. package/dist/lifecycle/lifecycle-formatter.d.ts +2 -1
  42. package/dist/lifecycle/lifecycle-formatter.js +4 -0
  43. package/dist/lifecycle/lifecycle-helpers.d.ts +3 -2
  44. package/dist/lifecycle/repo-lifecycle-manager.js +4 -11
  45. package/dist/lifecycle/types.d.ts +0 -8
  46. package/dist/output/github-summary.d.ts +5 -0
  47. package/dist/output/github-summary.js +9 -2
  48. package/dist/output/index.d.ts +2 -2
  49. package/dist/output/index.js +1 -1
  50. package/dist/output/lifecycle-report.js +5 -23
  51. package/dist/output/settings-report.d.ts +14 -3
  52. package/dist/output/settings-report.js +137 -197
  53. package/dist/output/summary-utils.d.ts +1 -1
  54. package/dist/output/summary-utils.js +2 -1
  55. package/dist/output/sync-report.js +5 -8
  56. package/dist/output/unified-summary.d.ts +2 -1
  57. package/dist/output/unified-summary.js +71 -133
  58. package/dist/settings/base-processor.d.ts +67 -0
  59. package/dist/settings/base-processor.js +91 -0
  60. package/dist/settings/index.d.ts +4 -3
  61. package/dist/settings/index.js +3 -3
  62. package/dist/settings/labels/converter.d.ts +2 -1
  63. package/dist/settings/labels/github-labels-strategy.d.ts +9 -18
  64. package/dist/settings/labels/github-labels-strategy.js +17 -73
  65. package/dist/settings/labels/index.d.ts +2 -6
  66. package/dist/settings/labels/index.js +1 -9
  67. package/dist/settings/labels/processor.d.ts +6 -30
  68. package/dist/settings/labels/processor.js +62 -152
  69. package/dist/settings/labels/types.d.ts +5 -8
  70. package/dist/settings/repo-settings/formatter.d.ts +2 -2
  71. package/dist/settings/repo-settings/formatter.js +6 -6
  72. package/dist/settings/repo-settings/github-repo-settings-strategy.d.ts +11 -12
  73. package/dist/settings/repo-settings/github-repo-settings-strategy.js +32 -79
  74. package/dist/settings/repo-settings/index.d.ts +2 -5
  75. package/dist/settings/repo-settings/index.js +1 -9
  76. package/dist/settings/repo-settings/processor.d.ts +6 -27
  77. package/dist/settings/repo-settings/processor.js +51 -104
  78. package/dist/settings/repo-settings/types.d.ts +7 -9
  79. package/dist/settings/rulesets/diff-algorithm.d.ts +0 -4
  80. package/dist/settings/rulesets/diff-algorithm.js +1 -10
  81. package/dist/settings/rulesets/diff.d.ts +1 -1
  82. package/dist/settings/rulesets/diff.js +2 -21
  83. package/dist/settings/rulesets/formatter.d.ts +1 -3
  84. package/dist/settings/rulesets/formatter.js +1 -8
  85. package/dist/settings/rulesets/github-ruleset-strategy.d.ts +11 -51
  86. package/dist/settings/rulesets/github-ruleset-strategy.js +24 -85
  87. package/dist/settings/rulesets/index.d.ts +3 -6
  88. package/dist/settings/rulesets/index.js +5 -9
  89. package/dist/settings/rulesets/processor.d.ts +8 -33
  90. package/dist/settings/rulesets/processor.js +58 -151
  91. package/dist/settings/rulesets/types.d.ts +35 -6
  92. package/dist/shared/command-executor.d.ts +2 -22
  93. package/dist/shared/command-executor.js +8 -7
  94. package/dist/shared/env.d.ts +0 -8
  95. package/dist/shared/env.js +14 -70
  96. package/dist/shared/file-status.d.ts +2 -0
  97. package/dist/shared/file-status.js +13 -0
  98. package/dist/shared/gh-api-utils.d.ts +46 -0
  99. package/dist/shared/gh-api-utils.js +107 -0
  100. package/dist/shared/index.d.ts +5 -5
  101. package/dist/shared/index.js +3 -3
  102. package/dist/shared/interpolation-engine.d.ts +31 -0
  103. package/dist/shared/interpolation-engine.js +50 -0
  104. package/dist/shared/logger.d.ts +3 -7
  105. package/dist/shared/logger.js +4 -1
  106. package/dist/shared/repo-detector.d.ts +17 -2
  107. package/dist/shared/repo-detector.js +27 -0
  108. package/dist/shared/retry-utils.d.ts +9 -17
  109. package/dist/shared/retry-utils.js +22 -28
  110. package/dist/shared/sanitize-utils.d.ts +0 -7
  111. package/dist/shared/sanitize-utils.js +0 -7
  112. package/dist/shared/shell-utils.d.ts +1 -0
  113. package/dist/shared/shell-utils.js +3 -0
  114. package/dist/shared/string-utils.d.ts +4 -0
  115. package/dist/shared/string-utils.js +6 -0
  116. package/dist/shared/type-guards.d.ts +17 -0
  117. package/dist/shared/type-guards.js +26 -0
  118. package/dist/shared/workspace-utils.d.ts +0 -4
  119. package/dist/shared/workspace-utils.js +0 -4
  120. package/dist/{sync → shared}/xfg-template.d.ts +3 -2
  121. package/dist/{sync → shared}/xfg-template.js +13 -54
  122. package/dist/sync/auth-options-builder.d.ts +4 -5
  123. package/dist/sync/auth-options-builder.js +15 -26
  124. package/dist/sync/branch-manager.d.ts +5 -0
  125. package/dist/sync/branch-manager.js +12 -10
  126. package/dist/sync/commit-push-manager.d.ts +1 -1
  127. package/dist/sync/commit-push-manager.js +22 -18
  128. package/dist/sync/diff-utils.d.ts +4 -9
  129. package/dist/sync/diff-utils.js +2 -19
  130. package/dist/sync/file-sync-orchestrator.js +9 -8
  131. package/dist/sync/file-writer.d.ts +2 -1
  132. package/dist/sync/file-writer.js +3 -6
  133. package/dist/sync/index.d.ts +2 -15
  134. package/dist/sync/index.js +0 -19
  135. package/dist/sync/manifest-manager.d.ts +4 -0
  136. package/dist/sync/manifest-manager.js +5 -1
  137. package/dist/sync/manifest.d.ts +10 -41
  138. package/dist/sync/manifest.js +11 -56
  139. package/dist/sync/pr-merge-handler.d.ts +2 -6
  140. package/dist/sync/pr-merge-handler.js +6 -3
  141. package/dist/sync/repository-processor.d.ts +1 -2
  142. package/dist/sync/repository-processor.js +20 -12
  143. package/dist/sync/repository-session.js +5 -14
  144. package/dist/sync/sync-workflow.js +31 -38
  145. package/dist/sync/types.d.ts +43 -178
  146. package/dist/vcs/authenticated-git-ops.d.ts +27 -70
  147. package/dist/vcs/authenticated-git-ops.js +70 -96
  148. package/dist/vcs/azure-pr-strategy.d.ts +6 -4
  149. package/dist/vcs/azure-pr-strategy.js +34 -82
  150. package/dist/vcs/branch-utils.d.ts +6 -0
  151. package/dist/vcs/branch-utils.js +29 -0
  152. package/dist/vcs/commit-strategy-selector.d.ts +5 -0
  153. package/dist/vcs/commit-strategy-selector.js +10 -0
  154. package/dist/vcs/git-commit-strategy.js +1 -2
  155. package/dist/vcs/git-ops.d.ts +15 -59
  156. package/dist/vcs/git-ops.js +46 -110
  157. package/dist/vcs/github-app-token-manager.d.ts +0 -6
  158. package/dist/vcs/github-app-token-manager.js +5 -12
  159. package/dist/vcs/github-pr-strategy.d.ts +5 -5
  160. package/dist/vcs/github-pr-strategy.js +44 -122
  161. package/dist/vcs/gitlab-pr-strategy.d.ts +6 -4
  162. package/dist/vcs/gitlab-pr-strategy.js +39 -87
  163. package/dist/vcs/graphql-commit-strategy.d.ts +3 -4
  164. package/dist/vcs/graphql-commit-strategy.js +31 -63
  165. package/dist/vcs/index.d.ts +3 -16
  166. package/dist/vcs/index.js +2 -33
  167. package/dist/vcs/pr-creator.d.ts +9 -9
  168. package/dist/vcs/pr-creator.js +11 -10
  169. package/dist/vcs/pr-strategy-factory.d.ts +5 -0
  170. package/dist/vcs/pr-strategy-factory.js +17 -0
  171. package/dist/vcs/pr-strategy.d.ts +13 -26
  172. package/dist/vcs/pr-strategy.js +20 -25
  173. package/dist/vcs/types.d.ts +87 -21
  174. package/package.json +2 -1
@@ -1,8 +1,6 @@
1
+ import { isTextContent } from "../merge.js";
2
+ export { isTextContent };
1
3
  declare const VALID_STRATEGIES: string[];
2
- /**
3
- * Check if content is text type (string or string[]).
4
- */
5
- export declare function isTextContent(content: unknown): boolean;
6
4
  /**
7
5
  * Check if content is object type (for JSON/YAML output).
8
6
  */
@@ -15,8 +13,4 @@ export declare function isStructuredFileExtension(fileName: string): boolean;
15
13
  * Validates a file name for security issues
16
14
  */
17
15
  export declare function validateFileName(fileName: string): void;
18
- /**
19
- * Validates that merge strategy is valid
20
- */
21
- export declare function isValidMergeStrategy(strategy: string): boolean;
22
16
  export { VALID_STRATEGIES };
@@ -1,13 +1,8 @@
1
1
  import { extname, isAbsolute } from "node:path";
2
+ import { isTextContent } from "../merge.js";
3
+ import { ValidationError } from "../errors.js";
4
+ export { isTextContent };
2
5
  const VALID_STRATEGIES = ["replace", "append", "prepend"];
3
- /**
4
- * Check if content is text type (string or string[]).
5
- */
6
- export function isTextContent(content) {
7
- return (typeof content === "string" ||
8
- (Array.isArray(content) &&
9
- content.every((item) => typeof item === "string")));
10
- }
11
6
  /**
12
7
  * Check if content is object type (for JSON/YAML output).
13
8
  */
@@ -26,21 +21,15 @@ export function isStructuredFileExtension(fileName) {
26
21
  */
27
22
  export function validateFileName(fileName) {
28
23
  if (!fileName || typeof fileName !== "string") {
29
- throw new Error("File name must be a non-empty string");
24
+ throw new ValidationError("File name must be a non-empty string");
30
25
  }
31
26
  // Validate fileName doesn't allow path traversal
32
27
  if (fileName.includes("..") || isAbsolute(fileName)) {
33
- throw new Error(`Invalid fileName '${fileName}': must be a relative path without '..' components`);
28
+ throw new ValidationError(`Invalid fileName '${fileName}': must be a relative path without '..' components`);
34
29
  }
35
30
  // Validate fileName doesn't contain control characters that could bypass shell escaping
36
31
  if (/[\n\r\0]/.test(fileName)) {
37
- throw new Error(`Invalid fileName '${fileName}': cannot contain newlines or null bytes`);
32
+ throw new ValidationError(`Invalid fileName '${fileName}': cannot contain newlines or null bytes`);
38
33
  }
39
34
  }
40
- /**
41
- * Validates that merge strategy is valid
42
- */
43
- export function isValidMergeStrategy(strategy) {
44
- return VALID_STRATEGIES.includes(strategy);
45
- }
46
35
  export { VALID_STRATEGIES };
@@ -1,3 +1,3 @@
1
- export { isTextContent, isObjectContent, isStructuredFileExtension, validateFileName, isValidMergeStrategy, VALID_STRATEGIES, } from "./file-validator.js";
2
- export { validateRepoSettings, VALID_VISIBILITY, VALID_SQUASH_MERGE_COMMIT_TITLE, VALID_SQUASH_MERGE_COMMIT_MESSAGE, VALID_MERGE_COMMIT_TITLE, VALID_MERGE_COMMIT_MESSAGE, } from "./repo-settings-validator.js";
3
- export { validateRule, validateRuleset, VALID_RULESET_TARGETS, VALID_ENFORCEMENT_LEVELS, VALID_ACTOR_TYPES, VALID_BYPASS_MODES, VALID_PATTERN_OPERATORS, VALID_MERGE_METHODS, VALID_ALERTS_THRESHOLDS, VALID_SECURITY_THRESHOLDS, VALID_RULE_TYPES, } from "./ruleset-validator.js";
1
+ export { isTextContent, isObjectContent, isStructuredFileExtension, validateFileName, VALID_STRATEGIES, } from "./file-validator.js";
2
+ export { validateRepoSettings } from "./repo-settings-validator.js";
3
+ export { validateRuleset } from "./ruleset-validator.js";
@@ -1,6 +1,6 @@
1
1
  // File validation
2
- export { isTextContent, isObjectContent, isStructuredFileExtension, validateFileName, isValidMergeStrategy, VALID_STRATEGIES, } from "./file-validator.js";
2
+ export { isTextContent, isObjectContent, isStructuredFileExtension, validateFileName, VALID_STRATEGIES, } from "./file-validator.js";
3
3
  // Repo settings validation
4
- export { validateRepoSettings, VALID_VISIBILITY, VALID_SQUASH_MERGE_COMMIT_TITLE, VALID_SQUASH_MERGE_COMMIT_MESSAGE, VALID_MERGE_COMMIT_TITLE, VALID_MERGE_COMMIT_MESSAGE, } from "./repo-settings-validator.js";
4
+ export { validateRepoSettings } from "./repo-settings-validator.js";
5
5
  // Ruleset validation
6
- export { validateRule, validateRuleset, VALID_RULESET_TARGETS, VALID_ENFORCEMENT_LEVELS, VALID_ACTOR_TYPES, VALID_BYPASS_MODES, VALID_PATTERN_OPERATORS, VALID_MERGE_METHODS, VALID_ALERTS_THRESHOLDS, VALID_SECURITY_THRESHOLDS, VALID_RULE_TYPES, } from "./ruleset-validator.js";
6
+ export { validateRuleset } from "./ruleset-validator.js";
@@ -1,10 +1,4 @@
1
- declare const VALID_VISIBILITY: string[];
2
- declare const VALID_SQUASH_MERGE_COMMIT_TITLE: string[];
3
- declare const VALID_SQUASH_MERGE_COMMIT_MESSAGE: string[];
4
- declare const VALID_MERGE_COMMIT_TITLE: string[];
5
- declare const VALID_MERGE_COMMIT_MESSAGE: string[];
6
1
  /**
7
2
  * Validates GitHub repository settings.
8
3
  */
9
4
  export declare function validateRepoSettings(repo: unknown, context: string): void;
10
- export { VALID_VISIBILITY, VALID_SQUASH_MERGE_COMMIT_TITLE, VALID_SQUASH_MERGE_COMMIT_MESSAGE, VALID_MERGE_COMMIT_TITLE, VALID_MERGE_COMMIT_MESSAGE, };
@@ -1,3 +1,4 @@
1
+ import { ValidationError } from "../errors.js";
1
2
  const VALID_VISIBILITY = ["public", "private", "internal"];
2
3
  const VALID_SQUASH_MERGE_COMMIT_TITLE = ["PR_TITLE", "COMMIT_OR_PR_TITLE"];
3
4
  const VALID_SQUASH_MERGE_COMMIT_MESSAGE = [
@@ -12,7 +13,7 @@ const VALID_MERGE_COMMIT_MESSAGE = ["PR_BODY", "PR_TITLE", "BLANK"];
12
13
  */
13
14
  export function validateRepoSettings(repo, context) {
14
15
  if (typeof repo !== "object" || repo === null || Array.isArray(repo)) {
15
- throw new Error(`${context}: repo must be an object`);
16
+ throw new ValidationError(`${context}: repo must be an object`);
16
17
  }
17
18
  const r = repo;
18
19
  // Validate boolean fields
@@ -39,33 +40,32 @@ export function validateRepoSettings(repo, context) {
39
40
  ];
40
41
  for (const field of booleanFields) {
41
42
  if (r[field] !== undefined && typeof r[field] !== "boolean") {
42
- throw new Error(`${context}: ${field} must be a boolean`);
43
+ throw new ValidationError(`${context}: ${field} must be a boolean`);
43
44
  }
44
45
  }
45
46
  // Validate string fields
46
47
  if (r.defaultBranch !== undefined && typeof r.defaultBranch !== "string") {
47
- throw new Error(`${context}: defaultBranch must be a string`);
48
+ throw new ValidationError(`${context}: defaultBranch must be a string`);
48
49
  }
49
50
  // Validate enum fields
50
51
  if (r.visibility !== undefined &&
51
52
  !VALID_VISIBILITY.includes(r.visibility)) {
52
- throw new Error(`${context}: visibility must be one of: ${VALID_VISIBILITY.join(", ")}`);
53
+ throw new ValidationError(`${context}: visibility must be one of: ${VALID_VISIBILITY.join(", ")}`);
53
54
  }
54
55
  if (r.squashMergeCommitTitle !== undefined &&
55
56
  !VALID_SQUASH_MERGE_COMMIT_TITLE.includes(r.squashMergeCommitTitle)) {
56
- throw new Error(`${context}: squashMergeCommitTitle must be one of: ${VALID_SQUASH_MERGE_COMMIT_TITLE.join(", ")}`);
57
+ throw new ValidationError(`${context}: squashMergeCommitTitle must be one of: ${VALID_SQUASH_MERGE_COMMIT_TITLE.join(", ")}`);
57
58
  }
58
59
  if (r.squashMergeCommitMessage !== undefined &&
59
60
  !VALID_SQUASH_MERGE_COMMIT_MESSAGE.includes(r.squashMergeCommitMessage)) {
60
- throw new Error(`${context}: squashMergeCommitMessage must be one of: ${VALID_SQUASH_MERGE_COMMIT_MESSAGE.join(", ")}`);
61
+ throw new ValidationError(`${context}: squashMergeCommitMessage must be one of: ${VALID_SQUASH_MERGE_COMMIT_MESSAGE.join(", ")}`);
61
62
  }
62
63
  if (r.mergeCommitTitle !== undefined &&
63
64
  !VALID_MERGE_COMMIT_TITLE.includes(r.mergeCommitTitle)) {
64
- throw new Error(`${context}: mergeCommitTitle must be one of: ${VALID_MERGE_COMMIT_TITLE.join(", ")}`);
65
+ throw new ValidationError(`${context}: mergeCommitTitle must be one of: ${VALID_MERGE_COMMIT_TITLE.join(", ")}`);
65
66
  }
66
67
  if (r.mergeCommitMessage !== undefined &&
67
68
  !VALID_MERGE_COMMIT_MESSAGE.includes(r.mergeCommitMessage)) {
68
- throw new Error(`${context}: mergeCommitMessage must be one of: ${VALID_MERGE_COMMIT_MESSAGE.join(", ")}`);
69
+ throw new ValidationError(`${context}: mergeCommitMessage must be one of: ${VALID_MERGE_COMMIT_MESSAGE.join(", ")}`);
69
70
  }
70
71
  }
71
- export { VALID_VISIBILITY, VALID_SQUASH_MERGE_COMMIT_TITLE, VALID_SQUASH_MERGE_COMMIT_MESSAGE, VALID_MERGE_COMMIT_TITLE, VALID_MERGE_COMMIT_MESSAGE, };
@@ -1,18 +1,4 @@
1
- declare const VALID_RULESET_TARGETS: string[];
2
- declare const VALID_ENFORCEMENT_LEVELS: string[];
3
- declare const VALID_ACTOR_TYPES: string[];
4
- declare const VALID_BYPASS_MODES: string[];
5
- declare const VALID_PATTERN_OPERATORS: string[];
6
- declare const VALID_MERGE_METHODS: string[];
7
- declare const VALID_ALERTS_THRESHOLDS: string[];
8
- declare const VALID_SECURITY_THRESHOLDS: string[];
9
- declare const VALID_RULE_TYPES: string[];
10
- /**
11
- * Validates a single ruleset rule.
12
- */
13
- export declare function validateRule(rule: unknown, context: string): void;
14
1
  /**
15
2
  * Validates a single ruleset.
16
3
  */
17
4
  export declare function validateRuleset(ruleset: unknown, name: string, context: string): void;
18
- export { VALID_RULESET_TARGETS, VALID_ENFORCEMENT_LEVELS, VALID_ACTOR_TYPES, VALID_BYPASS_MODES, VALID_PATTERN_OPERATORS, VALID_MERGE_METHODS, VALID_ALERTS_THRESHOLDS, VALID_SECURITY_THRESHOLDS, VALID_RULE_TYPES, };
@@ -1,3 +1,4 @@
1
+ import { ValidationError } from "../errors.js";
1
2
  const VALID_RULESET_TARGETS = ["branch", "tag"];
2
3
  const VALID_ENFORCEMENT_LEVELS = ["active", "disabled", "evaluate"];
3
4
  const VALID_ACTOR_TYPES = ["Team", "User", "Integration"];
@@ -48,33 +49,33 @@ const VALID_RULE_TYPES = [
48
49
  /**
49
50
  * Validates a single ruleset rule.
50
51
  */
51
- export function validateRule(rule, context) {
52
+ function validateRule(rule, context) {
52
53
  if (typeof rule !== "object" || rule === null || Array.isArray(rule)) {
53
- throw new Error(`${context}: rule must be an object`);
54
+ throw new ValidationError(`${context}: rule must be an object`);
54
55
  }
55
56
  const r = rule;
56
57
  if (!r.type || typeof r.type !== "string") {
57
- throw new Error(`${context}: rule must have a 'type' string field`);
58
+ throw new ValidationError(`${context}: rule must have a 'type' string field`);
58
59
  }
59
60
  if (!VALID_RULE_TYPES.includes(r.type)) {
60
- throw new Error(`${context}: invalid rule type '${r.type}'. Must be one of: ${VALID_RULE_TYPES.join(", ")}`);
61
+ throw new ValidationError(`${context}: invalid rule type '${r.type}'. Must be one of: ${VALID_RULE_TYPES.join(", ")}`);
61
62
  }
62
63
  // Validate parameters based on rule type
63
64
  if (r.parameters !== undefined) {
64
65
  if (typeof r.parameters !== "object" ||
65
66
  r.parameters === null ||
66
67
  Array.isArray(r.parameters)) {
67
- throw new Error(`${context}: rule parameters must be an object`);
68
+ throw new ValidationError(`${context}: rule parameters must be an object`);
68
69
  }
69
70
  const params = r.parameters;
70
71
  // Validate pattern rule parameters
71
72
  if (r.type.toString().endsWith("_pattern")) {
72
73
  if (params.operator !== undefined &&
73
74
  !VALID_PATTERN_OPERATORS.includes(params.operator)) {
74
- throw new Error(`${context}: pattern rule operator must be one of: ${VALID_PATTERN_OPERATORS.join(", ")}`);
75
+ throw new ValidationError(`${context}: pattern rule operator must be one of: ${VALID_PATTERN_OPERATORS.join(", ")}`);
75
76
  }
76
77
  if (params.pattern !== undefined && typeof params.pattern !== "string") {
77
- throw new Error(`${context}: pattern rule pattern must be a string`);
78
+ throw new ValidationError(`${context}: pattern rule pattern must be a string`);
78
79
  }
79
80
  }
80
81
  // Validate pull_request parameters
@@ -85,16 +86,16 @@ export function validateRule(rule, context) {
85
86
  !Number.isInteger(count) ||
86
87
  count < 0 ||
87
88
  count > 10) {
88
- throw new Error(`${context}: requiredApprovingReviewCount must be an integer between 0 and 10`);
89
+ throw new ValidationError(`${context}: requiredApprovingReviewCount must be an integer between 0 and 10`);
89
90
  }
90
91
  }
91
92
  if (params.allowedMergeMethods !== undefined) {
92
93
  if (!Array.isArray(params.allowedMergeMethods)) {
93
- throw new Error(`${context}: allowedMergeMethods must be an array`);
94
+ throw new ValidationError(`${context}: allowedMergeMethods must be an array`);
94
95
  }
95
96
  for (const method of params.allowedMergeMethods) {
96
97
  if (!VALID_MERGE_METHODS.includes(method)) {
97
- throw new Error(`${context}: allowedMergeMethods values must be one of: ${VALID_MERGE_METHODS.join(", ")}`);
98
+ throw new ValidationError(`${context}: allowedMergeMethods values must be one of: ${VALID_MERGE_METHODS.join(", ")}`);
98
99
  }
99
100
  }
100
101
  }
@@ -102,20 +103,20 @@ export function validateRule(rule, context) {
102
103
  // Validate code_scanning parameters
103
104
  if (r.type === "code_scanning" && params.codeScanningTools !== undefined) {
104
105
  if (!Array.isArray(params.codeScanningTools)) {
105
- throw new Error(`${context}: codeScanningTools must be an array`);
106
+ throw new ValidationError(`${context}: codeScanningTools must be an array`);
106
107
  }
107
108
  for (const tool of params.codeScanningTools) {
108
109
  if (typeof tool !== "object" || tool === null) {
109
- throw new Error(`${context}: each codeScanningTool must be an object`);
110
+ throw new ValidationError(`${context}: each codeScanningTool must be an object`);
110
111
  }
111
112
  const t = tool;
112
113
  if (t.alertsThreshold !== undefined &&
113
114
  !VALID_ALERTS_THRESHOLDS.includes(t.alertsThreshold)) {
114
- throw new Error(`${context}: alertsThreshold must be one of: ${VALID_ALERTS_THRESHOLDS.join(", ")}`);
115
+ throw new ValidationError(`${context}: alertsThreshold must be one of: ${VALID_ALERTS_THRESHOLDS.join(", ")}`);
115
116
  }
116
117
  if (t.securityAlertsThreshold !== undefined &&
117
118
  !VALID_SECURITY_THRESHOLDS.includes(t.securityAlertsThreshold)) {
118
- throw new Error(`${context}: securityAlertsThreshold must be one of: ${VALID_SECURITY_THRESHOLDS.join(", ")}`);
119
+ throw new ValidationError(`${context}: securityAlertsThreshold must be one of: ${VALID_SECURITY_THRESHOLDS.join(", ")}`);
119
120
  }
120
121
  }
121
122
  }
@@ -128,36 +129,36 @@ export function validateRuleset(ruleset, name, context) {
128
129
  if (typeof ruleset !== "object" ||
129
130
  ruleset === null ||
130
131
  Array.isArray(ruleset)) {
131
- throw new Error(`${context}: ruleset '${name}' must be an object`);
132
+ throw new ValidationError(`${context}: ruleset '${name}' must be an object`);
132
133
  }
133
134
  const rs = ruleset;
134
135
  if (rs.target !== undefined &&
135
136
  !VALID_RULESET_TARGETS.includes(rs.target)) {
136
- throw new Error(`${context}: ruleset '${name}' target must be one of: ${VALID_RULESET_TARGETS.join(", ")}`);
137
+ throw new ValidationError(`${context}: ruleset '${name}' target must be one of: ${VALID_RULESET_TARGETS.join(", ")}`);
137
138
  }
138
139
  if (rs.enforcement !== undefined &&
139
140
  !VALID_ENFORCEMENT_LEVELS.includes(rs.enforcement)) {
140
- throw new Error(`${context}: ruleset '${name}' enforcement must be one of: ${VALID_ENFORCEMENT_LEVELS.join(", ")}`);
141
+ throw new ValidationError(`${context}: ruleset '${name}' enforcement must be one of: ${VALID_ENFORCEMENT_LEVELS.join(", ")}`);
141
142
  }
142
143
  // Validate bypassActors
143
144
  if (rs.bypassActors !== undefined) {
144
145
  if (!Array.isArray(rs.bypassActors)) {
145
- throw new Error(`${context}: ruleset '${name}' bypassActors must be an array`);
146
+ throw new ValidationError(`${context}: ruleset '${name}' bypassActors must be an array`);
146
147
  }
147
148
  for (let i = 0; i < rs.bypassActors.length; i++) {
148
149
  const actor = rs.bypassActors[i];
149
150
  if (typeof actor !== "object" || actor === null) {
150
- throw new Error(`${context}: ruleset '${name}' bypassActors[${i}] must be an object`);
151
+ throw new ValidationError(`${context}: ruleset '${name}' bypassActors[${i}] must be an object`);
151
152
  }
152
153
  if (typeof actor.actorId !== "number") {
153
- throw new Error(`${context}: ruleset '${name}' bypassActors[${i}].actorId must be a number`);
154
+ throw new ValidationError(`${context}: ruleset '${name}' bypassActors[${i}].actorId must be a number`);
154
155
  }
155
156
  if (!VALID_ACTOR_TYPES.includes(actor.actorType)) {
156
- throw new Error(`${context}: ruleset '${name}' bypassActors[${i}].actorType must be one of: ${VALID_ACTOR_TYPES.join(", ")}`);
157
+ throw new ValidationError(`${context}: ruleset '${name}' bypassActors[${i}].actorType must be one of: ${VALID_ACTOR_TYPES.join(", ")}`);
157
158
  }
158
159
  if (actor.bypassMode !== undefined &&
159
160
  !VALID_BYPASS_MODES.includes(actor.bypassMode)) {
160
- throw new Error(`${context}: ruleset '${name}' bypassActors[${i}].bypassMode must be one of: ${VALID_BYPASS_MODES.join(", ")}`);
161
+ throw new ValidationError(`${context}: ruleset '${name}' bypassActors[${i}].bypassMode must be one of: ${VALID_BYPASS_MODES.join(", ")}`);
161
162
  }
162
163
  }
163
164
  }
@@ -166,7 +167,7 @@ export function validateRuleset(ruleset, name, context) {
166
167
  if (typeof rs.conditions !== "object" ||
167
168
  rs.conditions === null ||
168
169
  Array.isArray(rs.conditions)) {
169
- throw new Error(`${context}: ruleset '${name}' conditions must be an object`);
170
+ throw new ValidationError(`${context}: ruleset '${name}' conditions must be an object`);
170
171
  }
171
172
  const conditions = rs.conditions;
172
173
  if (conditions.refName !== undefined) {
@@ -174,28 +175,27 @@ export function validateRuleset(ruleset, name, context) {
174
175
  if (typeof refName !== "object" ||
175
176
  refName === null ||
176
177
  Array.isArray(refName)) {
177
- throw new Error(`${context}: ruleset '${name}' conditions.refName must be an object`);
178
+ throw new ValidationError(`${context}: ruleset '${name}' conditions.refName must be an object`);
178
179
  }
179
180
  if (refName.include !== undefined &&
180
181
  (!Array.isArray(refName.include) ||
181
182
  !refName.include.every((s) => typeof s === "string"))) {
182
- throw new Error(`${context}: ruleset '${name}' conditions.refName.include must be an array of strings`);
183
+ throw new ValidationError(`${context}: ruleset '${name}' conditions.refName.include must be an array of strings`);
183
184
  }
184
185
  if (refName.exclude !== undefined &&
185
186
  (!Array.isArray(refName.exclude) ||
186
187
  !refName.exclude.every((s) => typeof s === "string"))) {
187
- throw new Error(`${context}: ruleset '${name}' conditions.refName.exclude must be an array of strings`);
188
+ throw new ValidationError(`${context}: ruleset '${name}' conditions.refName.exclude must be an array of strings`);
188
189
  }
189
190
  }
190
191
  }
191
192
  // Validate rules array
192
193
  if (rs.rules !== undefined) {
193
194
  if (!Array.isArray(rs.rules)) {
194
- throw new Error(`${context}: ruleset '${name}' rules must be an array`);
195
+ throw new ValidationError(`${context}: ruleset '${name}' rules must be an array`);
195
196
  }
196
197
  for (let i = 0; i < rs.rules.length; i++) {
197
198
  validateRule(rs.rules[i], `${context}: ruleset '${name}' rules[${i}]`);
198
199
  }
199
200
  }
200
201
  }
201
- export { VALID_RULESET_TARGETS, VALID_ENFORCEMENT_LEVELS, VALID_ACTOR_TYPES, VALID_BYPASS_MODES, VALID_PATTERN_OPERATORS, VALID_MERGE_METHODS, VALID_ALERTS_THRESHOLDS, VALID_SECURITY_THRESHOLDS, VALID_RULE_TYPES, };
@@ -1,6 +1,7 @@
1
1
  import { escapeShellArg } from "../shared/shell-utils.js";
2
2
  import { defaultExecutor, } from "../shared/command-executor.js";
3
3
  import { withRetry } from "../shared/retry-utils.js";
4
+ import { toErrorMessage } from "../shared/type-guards.js";
4
5
  import { isAzureDevOpsRepo, } from "../shared/repo-detector.js";
5
6
  /**
6
7
  * Azure DevOps implementation of IMigrationSource.
@@ -28,7 +29,7 @@ export class AdoMigrationSource {
28
29
  });
29
30
  }
30
31
  catch (error) {
31
- const msg = error instanceof Error ? error.message : String(error);
32
+ const msg = toErrorMessage(error);
32
33
  throw new Error(`Failed to clone migration source ${repoInfo.gitUrl}: ${msg}. ` +
33
34
  `Ensure you have authentication configured for Azure DevOps ` +
34
35
  `(e.g., AZURE_DEVOPS_EXT_PAT or git credential helper).`);
@@ -5,7 +5,7 @@ import type { IRepoLifecycleProvider, LifecyclePlatform, CreateRepoSettings } fr
5
5
  * GitHub implementation of IRepoLifecycleProvider.
6
6
  * Uses gh CLI for all operations.
7
7
  */
8
- export interface GitHubLifecycleProviderOptions {
8
+ interface GitHubLifecycleProviderOptions {
9
9
  executor?: ICommandExecutor;
10
10
  retries?: number;
11
11
  cwd?: string;
@@ -29,11 +29,11 @@ export declare class GitHubLifecycleProvider implements IRepoLifecycleProvider {
29
29
  private isOrganization;
30
30
  private assertGitHub;
31
31
  /**
32
- * Build GH_TOKEN prefix for gh CLI commands.
33
- * Returns "GH_TOKEN=<escaped_token> " when token is provided, "" otherwise.
34
- * Token is escaped via escapeShellArg to prevent injection.
32
+ * Builds the common gh API command prefix parts for a given repo.
33
+ * Returns tokenEnv for exec options, and the command prefix string
34
+ * (e.g., "gh api --hostname host repos/owner/repo").
35
35
  */
36
- private buildTokenPrefix;
36
+ private buildGhApiPrefix;
37
37
  exists(repoInfo: RepoInfo, token?: string): Promise<boolean>;
38
38
  create(repoInfo: RepoInfo, settings?: CreateRepoSettings, token?: string): Promise<void>;
39
39
  fork(upstream: RepoInfo, target: RepoInfo, settings?: CreateRepoSettings, token?: string): Promise<void>;
@@ -68,3 +68,4 @@ export declare class GitHubLifecycleProvider implements IRepoLifecycleProvider {
68
68
  */
69
69
  private deleteReadme;
70
70
  }
71
+ export {};