Files
psysonic/.github/workflows/validate-main-green-ci.yml
T
cucadmuh bf38288feb ci(release): split channel pipelines and automate version transitions (#345)
* ci(release): split channel pipelines and automate version transitions

Introduce dedicated next/release orchestration workflows backed by a reusable publish pipeline with RC/final package version updates and post-release main dev bump PRs. Add a strict release process SOP with RC freeze, hotfix override, and mandatory backport rules.

* ci(release): gate main-to-next promotion on green CI

Add a dedicated workflow that validates main branch checks/statuses and block the promote-main-to-next flow unless main is green. Update the release SOP to reflect the enforced pre-promotion validation.

* ci(release): fix channel promotion edge cases and policy gaps

Switch channel promotions to reset-based snapshots with force-with-lease pushes, stop auto-merging channel nix-refresh PRs, and guard main dev bump against version downgrades. Add RC changelog fallback, require AUR release updates in SOP, and extend npmDepsHash sync to main/next/release pushes.

* docs(release): clarify backport and nix refresh survivability rules

Require RC fix backports to reach main before the next main-to-next promotion, and document that channel-local nix refresh PRs are advisory unless equivalent changes are merged into main.
2026-04-28 23:20:01 +03:00

78 lines
2.4 KiB
YAML

name: Validate Main Green CI
on:
workflow_dispatch:
inputs:
branch:
description: "Branch to validate"
required: false
default: main
type: string
workflow_call:
inputs:
branch:
required: false
default: main
type: string
jobs:
validate:
runs-on: ubuntu-latest
permissions:
contents: read
checks: read
statuses: read
steps:
- name: validate branch checks are green
uses: actions/github-script@v7
env:
TARGET_BRANCH: ${{ inputs.branch || github.event.inputs.branch || 'main' }}
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const branch = process.env.TARGET_BRANCH || "main";
const branchResp = await github.rest.repos.getBranch({ owner, repo, branch });
const sha = branchResp.data.commit.sha;
core.info(`Validating checks for ${branch} @ ${sha}`);
const combined = await github.rest.repos.getCombinedStatusForRef({
owner,
repo,
ref: sha,
});
const statusState = combined.data.state;
const statusCount = combined.data.statuses.length;
core.info(`Combined status state: ${statusState} (${statusCount} status contexts)`);
const checks = await github.paginate(github.rest.checks.listForRef, {
owner,
repo,
ref: sha,
per_page: 100,
});
if (checks.length === 0 && statusCount === 0) {
core.setFailed(`No checks/statuses found for ${branch}. Refusing promotion.`);
return;
}
const badChecks = checks.filter((c) => {
if (c.status !== "completed") return true;
return !["success", "neutral", "skipped"].includes(c.conclusion || "");
});
if (badChecks.length > 0) {
const details = badChecks.map((c) => `${c.name}: status=${c.status}, conclusion=${c.conclusion}`).join("\n");
core.setFailed(`Branch ${branch} is not green.\n${details}`);
return;
}
if (!["success", "neutral"].includes(statusState)) {
core.setFailed(`Combined status is ${statusState} for ${branch}.`);
return;
}
core.info(`Branch ${branch} is green.`);