mirror of
https://github.com/dtzp555-max/clawkeeper.git
synced 2026-07-21 21:15:06 +00:00
repo-rule-detector: summarize rulesets PR parameters
This commit is contained in:
@@ -20,7 +20,18 @@
|
||||
import { execFileSync } from 'node:child_process';
|
||||
|
||||
function sh(args) {
|
||||
return execFileSync('gh', args, { encoding: 'utf8' }).trim();
|
||||
// Keep stdout machine-readable: never let gh chatter leak into our output.
|
||||
return execFileSync('gh', args, {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'pipe']
|
||||
}).trim();
|
||||
}
|
||||
|
||||
function pick(obj, keys) {
|
||||
if (!obj) return null;
|
||||
const out = {};
|
||||
for (const k of keys) out[k] = obj?.[k] ?? null;
|
||||
return out;
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
@@ -57,18 +68,58 @@ function main() {
|
||||
rulesets = [];
|
||||
}
|
||||
|
||||
const PULL_REQUEST_PARAM_KEYS = [
|
||||
'required_review_thread_resolution',
|
||||
'allowed_merge_methods',
|
||||
'required_approving_review_count',
|
||||
'require_code_owner_review',
|
||||
'dismiss_stale_reviews_on_push',
|
||||
'require_last_push_approval'
|
||||
];
|
||||
|
||||
function fetchRulesetDetails(rulesetId) {
|
||||
try {
|
||||
return JSON.parse(sh(['api', `repos/${repo}/rulesets/${rulesetId}`]));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function hasRuleType(rules, type) {
|
||||
return Array.isArray(rules) && rules.some(r => r?.type === type);
|
||||
}
|
||||
|
||||
function summarizeRulesetRules(rules) {
|
||||
const prRule = Array.isArray(rules) ? rules.find(r => r?.type === 'pull_request') : null;
|
||||
const prParams = prRule?.parameters ? pick(prRule.parameters, PULL_REQUEST_PARAM_KEYS) : null;
|
||||
|
||||
return {
|
||||
pull_request: prParams
|
||||
? { present: true, parameters: prParams }
|
||||
: { present: false, parameters: null },
|
||||
required_linear_history: { present: hasRuleType(rules, 'required_linear_history') },
|
||||
non_fast_forward: { present: hasRuleType(rules, 'non_fast_forward') },
|
||||
deletion: { present: hasRuleType(rules, 'deletion') }
|
||||
};
|
||||
}
|
||||
|
||||
const relevantRulesets = rulesets
|
||||
.filter(rs => rs?.enforcement && rs.enforcement !== 'disabled')
|
||||
.filter(rs => {
|
||||
const targets = rs?.conditions?.ref_name?.include ?? [];
|
||||
return targets.length === 0 || targets.includes('~DEFAULT_BRANCH') || targets.includes(branch) || targets.includes(`refs/heads/${branch}`);
|
||||
})
|
||||
.map(rs => ({
|
||||
id: rs.id,
|
||||
name: rs.name,
|
||||
enforcement: rs.enforcement,
|
||||
target: rs?.conditions?.ref_name ?? null
|
||||
}));
|
||||
.map(rs => {
|
||||
const details = fetchRulesetDetails(rs.id);
|
||||
const rulesSummary = summarizeRulesetRules(details?.rules ?? []);
|
||||
return {
|
||||
id: rs.id,
|
||||
name: rs.name,
|
||||
enforcement: rs.enforcement,
|
||||
target: rs?.conditions?.ref_name ?? null,
|
||||
rules: rulesSummary
|
||||
};
|
||||
});
|
||||
|
||||
const allowedMergeMethods = {
|
||||
mergeCommit: !!repoInfo.allow_merge_commit,
|
||||
@@ -76,12 +127,19 @@ function main() {
|
||||
rebase: !!repoInfo.allow_rebase_merge
|
||||
};
|
||||
|
||||
const rulesetsRulePresence = {
|
||||
required_linear_history: relevantRulesets.some(rs => rs?.rules?.required_linear_history?.present),
|
||||
non_fast_forward: relevantRulesets.some(rs => rs?.rules?.non_fast_forward?.present),
|
||||
deletion: relevantRulesets.some(rs => rs?.rules?.deletion?.present)
|
||||
};
|
||||
|
||||
const out = {
|
||||
repo: repoInfo.full_name,
|
||||
url: repoInfo.html_url,
|
||||
defaultBranch: repoInfo.default_branch,
|
||||
branch,
|
||||
allowedMergeMethods,
|
||||
rulesetsRulePresence,
|
||||
branchProtection: bp ? {
|
||||
enabled: true,
|
||||
requiredStatusChecks: bp.required_status_checks ? {
|
||||
|
||||
Reference in New Issue
Block a user