mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-12 22:13:05 +00:00
- issue-done/plan-issue-ready: env FORGEJO_API_TOKEN (GITHUB_TOKEN 403 em Issues) + fork guard (checkout de fork roda script do fork com o PAT — RCE) - forgejo-issue-transition: falha de flip vira exit 1 (job vermelho, nunca skip silencioso) - waitForChecks: exige o rollup CI (PR) / checks presente+verde (raça PR #52: snapshot com jobs não-agendados parecia verde); mergeable=false só conta como conflito após a cascata assentar; timeouts 30→45min (CLI) e 40→55min (workflow) - configure-branch-protection: contexto real CI (PR) / checks* (Forgejo casa por glob contra 'CI (PR) / checks (pull_request)'; literal 'checks' nunca casaria), idempotente GET→POST/PATCH, verificação pós-aplicação; decisão pura em scripts/lib/branch-protection.mjs - docs honestas (AGENT-OPS, agent-pr-workflow.mdc, CUTOVER-MAIN-ONLY, README) - testes: raça do rollup/rollup failure/mergeable pré-settle + branchProtection create/update/noop + glob real
53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import {
|
|
DESIRED_RULE,
|
|
planBranchProtectionRule,
|
|
ruleMatches,
|
|
} from '../../scripts/lib/branch-protection.mjs'
|
|
|
|
describe('branch-protection rule planning (OPS61)', () => {
|
|
it('plans create when no rule exists', () => {
|
|
expect(planBranchProtectionRule(null).action).toBe('create')
|
|
})
|
|
|
|
it('plans noop when the rule already matches', () => {
|
|
const compliant = { ...DESIRED_RULE, branch_name: 'main' }
|
|
expect(planBranchProtectionRule(compliant).action).toBe('noop')
|
|
expect(ruleMatches(compliant)).toBe(true)
|
|
})
|
|
|
|
it('plans update when the rule drifts', () => {
|
|
const drift = { ...DESIRED_RULE, status_check_contexts: ['checks'] }
|
|
expect(planBranchProtectionRule(drift).action).toBe('update')
|
|
expect(planBranchProtectionRule(drift).action).not.toBe('noop')
|
|
})
|
|
|
|
it('detects drift in the contexts list (extra context)', () => {
|
|
const extra = {
|
|
...DESIRED_RULE,
|
|
status_check_contexts: ['CI (PR) / checks*', 'migration-lock'],
|
|
}
|
|
expect(planBranchProtectionRule(extra).action).toBe('update')
|
|
})
|
|
|
|
it('compares status_check_contexts as a set (order does not matter)', () => {
|
|
const desired = { ...DESIRED_RULE, status_check_contexts: ['a', 'b'] }
|
|
const existing = { ...desired, status_check_contexts: ['b', 'a'] }
|
|
expect(ruleMatches(existing, desired)).toBe(true)
|
|
expect(ruleMatches({ ...desired, status_check_contexts: ['a'] }, desired)).toBe(false)
|
|
})
|
|
|
|
it('the desired glob matches the real observed rollup context, not the push rollup', () => {
|
|
// Forgejo matches rule contexts as gobwas globs against the full context
|
|
// string — including the ` (event)` suffix — so the observed rollup is
|
|
// `CI (PR) / checks (pull_request)`. A literal `checks` would never match.
|
|
const glob = DESIRED_RULE.status_check_contexts[0]
|
|
const toRegex = (pattern: string) =>
|
|
new RegExp('^' + pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace('*', '.*') + '$')
|
|
const match = toRegex(glob)
|
|
expect(match.test('CI (PR) / checks (pull_request)')).toBe(true)
|
|
expect(match.test('CI / checks (push)')).toBe(false)
|
|
expect(match.test('CI (PR) / checks')).toBe(true)
|
|
})
|
|
})
|