mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
669c9f4d8b
Keep ubuntu selftest for fork→canonical PRs; leave iOS build policy alone. Co-authored-by: Cursor <cursoragent@cursor.com>
173 lines
8.7 KiB
Lua
173 lines
8.7 KiB
Lua
-- Content gate for Switch CI iOS-parity (SWCI-01..09).
|
|
-- Self-contained: luajit tests/switch_ci_workflows_test.lua
|
|
|
|
local T = require("tests.harness")
|
|
local check = T.check
|
|
|
|
local function read(path)
|
|
local f, err = io.open(path, "r")
|
|
if not f then error("cannot read " .. path .. ": " .. tostring(err)) end
|
|
local s = f:read("*a")
|
|
f:close()
|
|
return s
|
|
end
|
|
|
|
local function mustContain(body, needle, label)
|
|
check(body:find(needle, 1, true) ~= nil,
|
|
label .. " must contain " .. string.format("%q", needle))
|
|
end
|
|
|
|
local function mustNotContain(body, needle, label)
|
|
check(body:find(needle, 1, true) == nil,
|
|
label .. " must not contain " .. string.format("%q", needle))
|
|
end
|
|
|
|
-- Exact path regex contract (SWCI-01 / 4A + SWFIX-03 test path).
|
|
local SWITCH_PATH_REGEX =
|
|
[[^(scripts/build_switch\.sh$|scripts/switch/|docs/switch-build\.md$|tests/switch_ci_workflows_test\.lua$|\.github/workflows/(ci|release|switch-artifact-comment)\.yml$)]]
|
|
|
|
local ci = read(".github/workflows/ci.yml")
|
|
local release = read(".github/workflows/release.yml")
|
|
local comment_wf = read(".github/workflows/switch-artifact-comment.yml")
|
|
local ios_comment_wf = read(".github/workflows/ios-artifact-comment.yml")
|
|
|
|
-- --- SWCI-01: path detector ---
|
|
mustContain(ci, "switch-changes:", "ci.yml")
|
|
mustContain(ci, "detect Switch changes", "ci.yml")
|
|
mustContain(ci, SWITCH_PATH_REGEX, "ci.yml path regex")
|
|
mustContain(ci, 'echo "changed=true"', "ci.yml BASE_SHA fallback")
|
|
mustContain(ci, "0000000000000000000000000000000000000000", "ci.yml all-zero BASE_SHA")
|
|
|
|
-- --- SWCI-02 / SWCI-03: offline selftest job ---
|
|
mustContain(ci, "switch-selftest:", "ci.yml")
|
|
mustContain(ci, "needs: switch-changes", "ci.yml")
|
|
mustContain(ci, "needs.switch-changes.outputs.changed == 'true'", "ci.yml")
|
|
mustContain(ci, "scripts/switch/selftest_build_switch.sh", "ci.yml")
|
|
mustContain(ci, "scripts/switch/verify_payload.sh --self-test", "ci.yml")
|
|
mustContain(ci, "luajit tests/switch_ci_workflows_test.lua", "ci.yml")
|
|
|
|
-- switch-selftest must be ubuntu-latest (fork-safe); pin via job block scan
|
|
do
|
|
local start = ci:find("switch-selftest:", 1, true)
|
|
check(start ~= nil, "switch-selftest job present")
|
|
local rest = ci:sub(start)
|
|
local nextJob = rest:find("\n [%w_-]+:", 2)
|
|
local block = nextJob and rest:sub(1, nextJob - 1) or rest
|
|
mustContain(block, "runs-on: ubuntu-latest", "switch-selftest")
|
|
mustContain(block, "selftest_build_switch.sh", "switch-selftest")
|
|
mustContain(block, "verify_payload.sh --self-test", "switch-selftest")
|
|
mustContain(block, "tests/switch_ci_workflows_test.lua", "switch-selftest")
|
|
mustNotContain(block, "continue-on-error:", "switch-selftest")
|
|
end
|
|
|
|
-- --- SWCI-04 / SWCI-05: canonical fused build + artifact ---
|
|
mustContain(ci, "switch-build:", "ci.yml")
|
|
mustContain(ci, "gen1recomp-switch-nro", "ci.yml")
|
|
mustContain(ci, "github.repository == 'bryanthaboi/gen1recomp'", "ci.yml canonical gate")
|
|
mustContain(ci, 'runs-on: ["self-hosted", "macOS"]', "ci.yml switch-build runner")
|
|
mustContain(ci, "scripts/build_switch.sh --fetch --fused", "ci.yml fused command")
|
|
mustContain(ci, "if-no-files-found: error", "ci.yml artifact")
|
|
mustContain(ci, "retention-days: 7", "ci.yml artifact retention")
|
|
do
|
|
local start = ci:find("switch-build:", 1, true)
|
|
check(start ~= nil, "switch-build job present")
|
|
local rest = ci:sub(start)
|
|
local nextJob = rest:find("\n [%w_-]+:", 2)
|
|
local block = nextJob and rest:sub(1, nextJob - 1) or rest
|
|
mustContain(block, "needs.switch-changes.outputs.changed == 'true'", "switch-build")
|
|
mustContain(block, "bryanthaboi/gen1recomp", "switch-build canonical")
|
|
mustContain(block, '["self-hosted", "macOS"]', "switch-build runner")
|
|
mustContain(block, "gen1recomp-switch-nro", "switch-build artifact name")
|
|
mustContain(block, "gen1recomp-${{ env.SWITCH_VER }}-switch.nro", "switch-build explicit fused path")
|
|
mustContain(block, "gen1recomp-${{ env.SWITCH_VER }}-switch.nro.sha256", "switch-build sha256 sidecar")
|
|
mustContain(block, "if-no-files-found: error", "switch-build")
|
|
mustContain(block, "retention-days: 7", "switch-build")
|
|
mustNotContain(block, "continue-on-error:", "switch-build")
|
|
-- SWFIX-04: same-repo head only (skip fork→canonical PRs on self-hosted)
|
|
mustContain(block, "pull_request.head.repo.full_name", "switch-build fork-PR skip")
|
|
mustContain(block, "github.event_name != 'pull_request'", "switch-build non-PR allow")
|
|
check(block:find("bryanthaboi/gen1recomp", 1, true) ~= nil
|
|
and block:find("changed == 'true'", 1, true) ~= nil,
|
|
"switch-build requires changed=true AND canonical repository")
|
|
end
|
|
|
|
-- SWFIX-04 / M7: iOS build must NOT gain the Switch fork-PR head.repo guard
|
|
do
|
|
local start = ci:find("ios-build:", 1, true)
|
|
check(start ~= nil, "ios-build job present")
|
|
local rest = ci:sub(start)
|
|
local nextJob = rest:find("\n [%w_-]+:", 2)
|
|
local block = nextJob and rest:sub(1, nextJob - 1) or rest
|
|
mustNotContain(block, "pull_request.head.repo.full_name", "ios-build")
|
|
end
|
|
|
|
-- --- SWCI-06 / SWCI-07 / SWFIX-01: PR artifact comment (no delete-all clobber) ---
|
|
mustContain(comment_wf, "workflows: [ci]", "switch-artifact-comment")
|
|
mustContain(comment_wf, "gen1recomp-switch-nro", "switch-artifact-comment")
|
|
mustContain(comment_wf, "comment-tag: switch-build-result", "switch-artifact-comment")
|
|
mustContain(comment_wf, "pull_request", "switch-artifact-comment")
|
|
mustContain(comment_wf, "conclusion == 'success'", "switch-artifact-comment")
|
|
mustContain(comment_wf, 'exit 0', "switch-artifact-comment no-op")
|
|
mustContain(comment_wf, "**Commit**:", "switch-artifact-comment")
|
|
mustContain(comment_wf, "**Build Time**:", "switch-artifact-comment")
|
|
mustContain(comment_wf, "View workflow run", "switch-artifact-comment")
|
|
mustContain(comment_wf, "thollander/actions-comment-pull-request@v3", "switch-artifact-comment")
|
|
mustNotContain(comment_wf, "delete-comment", "switch-artifact-comment")
|
|
mustNotContain(comment_wf, "izhangzhihao/delete-comment", "switch-artifact-comment")
|
|
|
|
mustContain(ios_comment_wf, "comment-tag: ios-build-result", "ios-artifact-comment")
|
|
mustContain(ios_comment_wf, "thollander/actions-comment-pull-request@v3", "ios-artifact-comment")
|
|
mustNotContain(ios_comment_wf, "delete-comment", "ios-artifact-comment")
|
|
mustNotContain(ios_comment_wf, "izhangzhihao/delete-comment", "ios-artifact-comment")
|
|
-- Distinct tags so both commenters can coexist on the same PR
|
|
check(comment_wf:find("comment-tag: switch-build-result", 1, true)
|
|
and ios_comment_wf:find("comment-tag: ios-build-result", 1, true)
|
|
and comment_wf:find("comment-tag: ios-build-result", 1, true) == nil,
|
|
"iOS and Switch comment-tags must be distinct and present")
|
|
|
|
-- --- SWCI-08 / SWCI-09: docs CI vs release ---
|
|
local build_doc = read("docs/switch-build.md")
|
|
local development = read("docs/switch-development.md")
|
|
local readme = read("README.md")
|
|
|
|
mustContain(build_doc, "Path-gated", "switch-build.md")
|
|
mustContain(build_doc, "ubuntu-latest", "switch-build.md")
|
|
mustContain(build_doc, "selftest_build_switch.sh", "switch-build.md")
|
|
mustContain(build_doc, "canonical", "switch-build.md")
|
|
mustContain(build_doc, "gen1recomp-switch-nro", "switch-build.md")
|
|
mustContain(build_doc, "switch-build-result", "switch-build.md")
|
|
mustContain(build_doc, "hard gate", "switch-build.md")
|
|
mustContain(build_doc, "continue-on-error", "switch-build.md")
|
|
mustContain(build_doc, "nacptool", "switch-build.md")
|
|
mustContain(build_doc, "Docker", "switch-build.md")
|
|
mustContain(build_doc, "Fork → canonical", "switch-build.md")
|
|
mustContain(build_doc, "skip Switch fused", "switch-build.md")
|
|
|
|
mustContain(development, "Switch CI", "switch-development.md")
|
|
mustContain(development, "selftest_build_switch.sh", "switch-development.md")
|
|
|
|
mustContain(readme, "CI vs release", "README.md")
|
|
mustContain(readme, "switch-build.md", "README.md")
|
|
|
|
-- --- SWFIX-03: headless suite also runs the content gate ---
|
|
local test_sh = read("scripts/test.sh")
|
|
mustContain(test_sh, "tests/switch_ci_workflows_test.lua", "scripts/test.sh")
|
|
mustContain(test_sh, "T0 switch CI workflow content gate", "scripts/test.sh")
|
|
mustContain(build_doc, "tests/switch_ci_workflows_test.lua", "switch-build.md path list")
|
|
|
|
-- --- SWCI-08: release Switch hard-fail (no continue-on-error on build/stage) ---
|
|
do
|
|
local start = release:find("- name: Build Switch", 1, true)
|
|
check(start ~= nil, "release Build Switch step present")
|
|
local rest = release:sub(start)
|
|
local nextStep = rest:find("\n - name:", 2)
|
|
local block = nextStep and rest:sub(1, nextStep - 1) or rest
|
|
mustContain(block, "scripts/build_switch.sh --fetch --fused", "release Build Switch")
|
|
-- YAML key must be absent (comment prose may discuss soft-fail policy)
|
|
mustNotContain(block, "continue-on-error:", "release Build Switch")
|
|
mustContain(block, "path-gated", "release Build Switch comment")
|
|
mustContain(block, "Hard-fail", "release Build Switch comment")
|
|
end
|
|
|
|
T.finish("switch_ci_workflows_test")
|