@aspruyt/xfg 3.9.14 → 3.10.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/config/index.d.ts +1 -1
- package/dist/config/normalizer.d.ts +2 -2
- package/dist/config/normalizer.js +3 -0
- package/dist/config/types.d.ts +8 -1
- package/dist/config/validator.d.ts +2 -2
- package/dist/config/validator.js +11 -0
- package/dist/lifecycle/github-lifecycle-provider.js +12 -3
- package/dist/sync/pr-merge-handler.js +1 -0
- package/dist/vcs/github-pr-strategy.js +8 -2
- package/dist/vcs/pr-creator.d.ts +2 -0
- package/dist/vcs/pr-creator.js +2 -1
- package/dist/vcs/types.d.ts +2 -0
- package/package.json +1 -1
package/dist/config/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { MergeMode, MergeStrategy, PRMergeOptions, RulesetTarget, RulesetEnforcement, BypassActorType, BypassMode, PatternOperator, MergeMethod, AlertsThreshold, SecurityAlertsThreshold, BypassActor, RefNameCondition, RulesetConditions, StatusCheckConfig, RequiredReviewer, CodeScanningTool, WorkflowConfig, PullRequestRuleParameters, RequiredStatusChecksParameters, UpdateRuleParameters, RequiredDeploymentsParameters, CodeScanningParameters, CodeQualityParameters, WorkflowsParameters, PatternRuleParameters, FilePathRestrictionParameters, FileExtensionRestrictionParameters, MaxFilePathLengthParameters, MaxFileSizeParameters, PullRequestRule, RequiredStatusChecksRule, RequiredSignaturesRule, RequiredLinearHistoryRule, NonFastForwardRule, CreationRule, UpdateRule, DeletionRule, RequiredDeploymentsRule, CodeScanningRule, CodeQualityRule, WorkflowsRule, CommitAuthorEmailPatternRule, CommitMessagePatternRule, CommitterEmailPatternRule, BranchNamePatternRule, TagNamePatternRule, FilePathRestrictionRule, FileExtensionRestrictionRule, MaxFilePathLengthRule, MaxFileSizeRule, RulesetRule, Ruleset, SquashMergeCommitTitle, SquashMergeCommitMessage, MergeCommitTitle, MergeCommitMessage, RepoVisibility, GitHubRepoSettings, Label, RepoSettings, ContentValue, RawFileConfig, RawRepoFileOverride, RawRepoSettings, RawRepoConfig, RawConfig, FileContent, RepoConfig, Config, } from "./types.js";
|
|
1
|
+
export type { MergeMode, MergeStrategy, PRMergeOptions, RulesetTarget, RulesetEnforcement, BypassActorType, BypassMode, PatternOperator, MergeMethod, AlertsThreshold, SecurityAlertsThreshold, BypassActor, RefNameCondition, RulesetConditions, StatusCheckConfig, RequiredReviewer, CodeScanningTool, WorkflowConfig, PullRequestRuleParameters, RequiredStatusChecksParameters, UpdateRuleParameters, RequiredDeploymentsParameters, CodeScanningParameters, CodeQualityParameters, WorkflowsParameters, PatternRuleParameters, FilePathRestrictionParameters, FileExtensionRestrictionParameters, MaxFilePathLengthParameters, MaxFileSizeParameters, PullRequestRule, RequiredStatusChecksRule, RequiredSignaturesRule, RequiredLinearHistoryRule, NonFastForwardRule, CreationRule, UpdateRule, DeletionRule, RequiredDeploymentsRule, CodeScanningRule, CodeQualityRule, WorkflowsRule, CommitAuthorEmailPatternRule, CommitMessagePatternRule, CommitterEmailPatternRule, BranchNamePatternRule, TagNamePatternRule, FilePathRestrictionRule, FileExtensionRestrictionRule, MaxFilePathLengthRule, MaxFileSizeRule, RulesetRule, Ruleset, SquashMergeCommitTitle, SquashMergeCommitMessage, MergeCommitTitle, MergeCommitMessage, RepoVisibility, GitHubRepoSettings, Label, RepoSettings, ContentValue, RawFileConfig, RawRepoFileOverride, RawRootSettings, RawRepoSettings, RawRepoConfig, RawConfig, FileContent, RepoConfig, Config, } from "./types.js";
|
|
2
2
|
export { RULESET_FIELD_MAP, RULESET_COMPARABLE_FIELDS } from "./types.js";
|
|
3
3
|
export { loadRawConfig, loadConfig, normalizeConfig } from "./loader.js";
|
|
4
4
|
export { convertContentToString, detectOutputFormat, type OutputFormat, type ConvertOptions, } from "./formatter.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { RawConfig, Config, RepoSettings, RawRepoSettings } from "./types.js";
|
|
2
|
-
export declare function mergeSettings(root:
|
|
1
|
+
import type { RawConfig, Config, RepoSettings, RawRootSettings, RawRepoSettings } from "./types.js";
|
|
2
|
+
export declare function mergeSettings(root: RawRootSettings | undefined, perRepo: RawRepoSettings | undefined): RepoSettings | undefined;
|
|
3
3
|
/**
|
|
4
4
|
* Normalizes raw config into expanded, merged config.
|
|
5
5
|
* Pipeline: expand git arrays -> merge content -> interpolate env vars
|
|
@@ -26,6 +26,7 @@ function mergePROptions(global, perRepo) {
|
|
|
26
26
|
const mergeStrategy = perRepo.mergeStrategy ?? global.mergeStrategy;
|
|
27
27
|
const deleteBranch = perRepo.deleteBranch ?? global.deleteBranch;
|
|
28
28
|
const bypassReason = perRepo.bypassReason ?? global.bypassReason;
|
|
29
|
+
const labels = perRepo.labels ?? global.labels;
|
|
29
30
|
if (merge !== undefined)
|
|
30
31
|
result.merge = merge;
|
|
31
32
|
if (mergeStrategy !== undefined)
|
|
@@ -34,6 +35,8 @@ function mergePROptions(global, perRepo) {
|
|
|
34
35
|
result.deleteBranch = deleteBranch;
|
|
35
36
|
if (bypassReason !== undefined)
|
|
36
37
|
result.bypassReason = bypassReason;
|
|
38
|
+
if (labels !== undefined)
|
|
39
|
+
result.labels = labels;
|
|
37
40
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
38
41
|
}
|
|
39
42
|
/**
|
package/dist/config/types.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface PRMergeOptions {
|
|
|
6
6
|
mergeStrategy?: MergeStrategy;
|
|
7
7
|
deleteBranch?: boolean;
|
|
8
8
|
bypassReason?: string;
|
|
9
|
+
labels?: string[];
|
|
9
10
|
}
|
|
10
11
|
/** Ruleset target type */
|
|
11
12
|
export type RulesetTarget = "branch" | "tag";
|
|
@@ -304,6 +305,12 @@ export interface RawRepoFileOverride {
|
|
|
304
305
|
vars?: Record<string, string>;
|
|
305
306
|
deleteOrphaned?: boolean;
|
|
306
307
|
}
|
|
308
|
+
export interface RawRootSettings {
|
|
309
|
+
rulesets?: Record<string, Ruleset | false>;
|
|
310
|
+
repo?: GitHubRepoSettings | false;
|
|
311
|
+
labels?: Record<string, Label | false>;
|
|
312
|
+
deleteOrphaned?: boolean;
|
|
313
|
+
}
|
|
307
314
|
export interface RawRepoSettings {
|
|
308
315
|
rulesets?: Record<string, Ruleset | false> & {
|
|
309
316
|
inherit?: boolean;
|
|
@@ -334,7 +341,7 @@ export interface RawConfig {
|
|
|
334
341
|
prTemplate?: string;
|
|
335
342
|
githubHosts?: string[];
|
|
336
343
|
deleteOrphaned?: boolean;
|
|
337
|
-
settings?:
|
|
344
|
+
settings?: RawRootSettings;
|
|
338
345
|
}
|
|
339
346
|
export interface FileContent {
|
|
340
347
|
fileName: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RawConfig, RawRepoSettings } from "./types.js";
|
|
1
|
+
import type { RawConfig, RawRepoSettings, RawRootSettings } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Validates settings object containing rulesets, labels, and repo settings.
|
|
4
4
|
*/
|
|
@@ -16,7 +16,7 @@ export declare function validateForSync(config: RawConfig): void;
|
|
|
16
16
|
/**
|
|
17
17
|
* Checks if settings contain actionable configuration.
|
|
18
18
|
*/
|
|
19
|
-
export declare function hasActionableSettings(settings: RawRepoSettings | undefined): boolean;
|
|
19
|
+
export declare function hasActionableSettings(settings: RawRootSettings | RawRepoSettings | undefined): boolean;
|
|
20
20
|
/**
|
|
21
21
|
* Validates that config is suitable for the settings command.
|
|
22
22
|
* @throws Error if no settings are defined or no actionable settings exist
|
package/dist/config/validator.js
CHANGED
|
@@ -274,6 +274,17 @@ export function validateRawConfig(config) {
|
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
|
+
// Validate prOptions.labels if present
|
|
278
|
+
if (config.prOptions?.labels !== undefined) {
|
|
279
|
+
if (!Array.isArray(config.prOptions.labels)) {
|
|
280
|
+
throw new Error("prOptions.labels must be an array of strings");
|
|
281
|
+
}
|
|
282
|
+
for (const label of config.prOptions.labels) {
|
|
283
|
+
if (typeof label !== "string" || label.length === 0) {
|
|
284
|
+
throw new Error("prOptions.labels entries must be non-empty strings");
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
277
288
|
// Validate each repo
|
|
278
289
|
for (let i = 0; i < config.repos.length; i++) {
|
|
279
290
|
const repo = config.repos[i];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { escapeShellArg } from "../shared/shell-utils.js";
|
|
2
2
|
import { defaultExecutor, } from "../shared/command-executor.js";
|
|
3
|
-
import { withRetry } from "../shared/retry-utils.js";
|
|
3
|
+
import { withRetry, DEFAULT_PERMANENT_ERROR_PATTERNS, } from "../shared/retry-utils.js";
|
|
4
4
|
import { isGitHubRepo, } from "../shared/repo-detector.js";
|
|
5
5
|
import { logger } from "../shared/logger.js";
|
|
6
6
|
/**
|
|
@@ -304,11 +304,20 @@ export class GitHubLifecycleProvider {
|
|
|
304
304
|
const hostnameFlag = getHostnameFlag(repoInfo);
|
|
305
305
|
const hostnamePart = hostnameFlag ? `${hostnameFlag} ` : "";
|
|
306
306
|
const apiPath = `repos/${escapeShellArg(repoInfo.owner)}/${escapeShellArg(repoInfo.repo)}`;
|
|
307
|
+
// After repo creation, GitHub may return 404 due to eventual consistency.
|
|
308
|
+
// Exclude 404/not-found from permanent errors so withRetry retries them.
|
|
309
|
+
const postCreatePermanentPatterns = DEFAULT_PERMANENT_ERROR_PATTERNS.filter((p) => !p.test("404 Not Found"));
|
|
307
310
|
// Get the SHA of the README.md created by --add-readme
|
|
308
|
-
const fileInfo = await withRetry(() => this.executor.exec(`${tokenPrefix}gh api ${hostnamePart}${apiPath}/contents/README.md --jq '.sha'`, this.cwd), {
|
|
311
|
+
const fileInfo = await withRetry(() => this.executor.exec(`${tokenPrefix}gh api ${hostnamePart}${apiPath}/contents/README.md --jq '.sha'`, this.cwd), {
|
|
312
|
+
retries: this.retries,
|
|
313
|
+
permanentErrorPatterns: postCreatePermanentPatterns,
|
|
314
|
+
});
|
|
309
315
|
const sha = fileInfo.trim();
|
|
310
316
|
// Delete the README.md to leave the repo clean
|
|
311
317
|
await withRetry(() => this.executor.exec(`${tokenPrefix}gh api ${hostnamePart}${apiPath}/contents/README.md ` +
|
|
312
|
-
`--method DELETE -f message='Remove initialization file' -f sha=${escapeShellArg(sha)}`, this.cwd), {
|
|
318
|
+
`--method DELETE -f message='Remove initialization file' -f sha=${escapeShellArg(sha)}`, this.cwd), {
|
|
319
|
+
retries: this.retries,
|
|
320
|
+
permanentErrorPatterns: postCreatePermanentPatterns,
|
|
321
|
+
});
|
|
313
322
|
}
|
|
314
323
|
}
|
|
@@ -114,7 +114,7 @@ export class GitHubPRStrategy extends BasePRStrategy {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
async create(options) {
|
|
117
|
-
const { repoInfo, title, body, branchName, baseBranch, workDir, retries = 3, token, } = options;
|
|
117
|
+
const { repoInfo, title, body, branchName, baseBranch, workDir, retries = 3, token, labels, } = options;
|
|
118
118
|
if (!isGitHubRepo(repoInfo)) {
|
|
119
119
|
throw new Error("Expected GitHub repository");
|
|
120
120
|
}
|
|
@@ -123,7 +123,13 @@ export class GitHubPRStrategy extends BasePRStrategy {
|
|
|
123
123
|
writeFileSync(bodyFile, body, "utf-8");
|
|
124
124
|
// Token is passed via env var to avoid shell injection
|
|
125
125
|
const tokenEnv = buildTokenEnv(token);
|
|
126
|
-
|
|
126
|
+
let command = `gh pr create --title ${escapeShellArg(title)} --body-file ${escapeShellArg(bodyFile)} --base ${escapeShellArg(baseBranch)} --head ${escapeShellArg(branchName)}`;
|
|
127
|
+
// Append label flags
|
|
128
|
+
if (labels && labels.length > 0) {
|
|
129
|
+
for (const label of labels) {
|
|
130
|
+
command += ` --label ${escapeShellArg(label)}`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
127
133
|
try {
|
|
128
134
|
const result = await withRetry(() => this.executor.exec(command, workDir, { env: tokenEnv }), { retries });
|
|
129
135
|
// Extract URL from output - use strict regex for valid PR URLs only
|
package/dist/vcs/pr-creator.d.ts
CHANGED
package/dist/vcs/pr-creator.js
CHANGED
|
@@ -97,7 +97,7 @@ export function formatPRTitle(files) {
|
|
|
97
97
|
return `chore: sync ${changedFiles.length} config files`;
|
|
98
98
|
}
|
|
99
99
|
export async function createPR(options) {
|
|
100
|
-
const { repoInfo, branchName, baseBranch, files, workDir, dryRun, retries, prTemplate, executor, token, } = options;
|
|
100
|
+
const { repoInfo, branchName, baseBranch, files, workDir, dryRun, retries, prTemplate, executor, token, labels, } = options;
|
|
101
101
|
const title = formatPRTitle(files);
|
|
102
102
|
const body = formatPRBody(files, repoInfo, prTemplate);
|
|
103
103
|
if (dryRun) {
|
|
@@ -117,6 +117,7 @@ export async function createPR(options) {
|
|
|
117
117
|
workDir,
|
|
118
118
|
retries,
|
|
119
119
|
token,
|
|
120
|
+
labels,
|
|
120
121
|
});
|
|
121
122
|
}
|
|
122
123
|
export async function mergePR(options) {
|
package/dist/vcs/types.d.ts
CHANGED
package/package.json
CHANGED