--- # 00-suite-runner.yml - entry point for the Gitea Actions compatibility suite. # # This is the SOLE entry workflow. It has the push/workflow_dispatch triggers. # The ten sub-workflows (01-10) are `on: workflow_call` only and are invoked by # the caller jobs below. Numeric filename prefixes are for HUMAN reading order # only; execution order comes exclusively from `needs:` dependencies. # # Flow: probe (hard gate) -> callers (parallel) -> aggregate (must-all-pass). # If probe fails, every caller is skipped (needs probe), and aggregate # (if: always()) sees them as non-success and turns the run red - never green. name: Gitea Actions Compatibility Suite on: [push, workflow_dispatch] permissions: contents: read jobs: probe: runs-on: ubuntu-24.04 outputs: gitea-version: ${{ steps.check.outputs.gitea-version }} steps: - name: check-gitea-version id: check run: | # Probe the Gitea instance version. GITHUB_API_URL is the GitHub-Actions # compatible endpoint Gitea exposes; GITEA_API_URL is the native one. VERSION="" if [ -n "${GITHUB_API_URL:-}" ]; then VERSION=$(curl -sf "${GITHUB_API_URL}/version" 2>/dev/null | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4) || true fi if [ -n "${GITEA_API_URL:-}" ]; then VERSION=$(curl -sf "${GITEA_API_URL}/version" 2>/dev/null | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4) || true fi echo "Detected Gitea version: ${VERSION:-unknown}" echo "gitea-version=${VERSION:-unknown}" >> "$GITHUB_OUTPUT" # Assert >= 1.22.0 (minimum to parse/accept workflows). MAJOR=0; MINOR=0; PATCH=0 if [[ "$VERSION" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then MAJOR="${BASH_REMATCH[1]}" MINOR="${BASH_REMATCH[2]}" PATCH="${BASH_REMATCH[3]}" fi if [ "$MAJOR" -lt 1 ] || { [ "$MAJOR" -eq 1 ] && [ "$MINOR" -lt 22 ]; }; then echo "::error::Gitea version ${VERSION:-unknown} is below 1.22.0 (minimum to parse/accept workflows). Suite aborted." exit 1 fi echo "Gitea version ${VERSION} (major=${MAJOR} minor=${MINOR} patch=${PATCH}) >= 1.22.0: OK" - name: info-action-mirroring continue-on-error: true run: | # Best-effort: check that action mirroring can resolve at least one actions/* ref. echo "Best-effort action mirroring check (informational only, not a hard gate)" echo "If actions fail to resolve at runtime, check ACTIONS_URL / DEFAULT_ACTIONS_URL settings" - name: info-storage-cache continue-on-error: true run: | # Best-effort: note about storage and cache. echo "Storage backend and cache server should be configured. Artifacts and cache tests will fail if not." # --- Caller jobs: each invokes a reusable workflow via `uses:`. # Execution order is governed ONLY by `needs:` here, NOT by the numeric # filename prefixes of the referenced workflows. The caller jobs are # independent of each other (they all only need probe) and run in parallel. checkout: needs: probe uses: ./.github/workflows/01-checkout.yml artifacts: needs: probe uses: ./.github/workflows/02-artifacts.yml cache: needs: probe uses: ./.github/workflows/03-cache.yml setup-runtime: needs: probe uses: ./.github/workflows/04-setup-runtime.yml contexts: needs: probe uses: ./.github/workflows/05-contexts.yml secrets: inherit workflow-commands: needs: probe uses: ./.github/workflows/06-workflow-commands.yml services: needs: probe uses: ./.github/workflows/07-services.yml composite-reusable: needs: probe uses: ./.github/workflows/08-composite-reusable.yml with: who: gitea-compat-suite secrets: inherit control-flow: needs: probe uses: ./.github/workflows/09-control-flow.yml gitea-divergences: needs: probe uses: ./.github/workflows/10-gitea-divergences.yml aggregate: needs: [probe, checkout, artifacts, cache, setup-runtime, contexts, workflow-commands, services, composite-reusable, control-flow, gitea-divergences] if: always() runs-on: ubuntu-24.04 steps: - name: aggregate-results run: | # Fail unless probe AND every caller is 'success'. # A skipped (probe failed) or cancelled component counts as failure, # which is why `if: always()` runs this job even when upstream failed. # # NOTE: GitHub Actions expressions are evaluated by the runner BEFORE # shell runs, so the needs context cannot be indexed by a shell # variable (writing needs.$j.result would never substitute $j into the # pre-evaluated expression). Each needs..result is written out # explicitly below. echo "probe=${{ needs.probe.result }}" echo "checkout=${{ needs.checkout.result }}" echo "artifacts=${{ needs.artifacts.result }}" echo "cache=${{ needs.cache.result }}" echo "setup-runtime=${{ needs.setup-runtime.result }}" echo "contexts=${{ needs.contexts.result }}" echo "workflow-commands=${{ needs.workflow-commands.result }}" echo "services=${{ needs.services.result }}" echo "composite-reusable=${{ needs.composite-reusable.result }}" echo "control-flow=${{ needs.control-flow.result }}" echo "gitea-divergences=${{ needs.gitea-divergences.result }}" all_ok=true if [ "${{ needs.probe.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.checkout.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.artifacts.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.cache.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.setup-runtime.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.contexts.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.workflow-commands.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.services.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.composite-reusable.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.control-flow.result }}" != "success" ]; then all_ok=false; fi if [ "${{ needs.gitea-divergences.result }}" != "success" ]; then all_ok=false; fi if [ "$all_ok" != "true" ]; then echo "::error::Suite FAILED: not all components reported success" exit 1 fi echo "Suite PASSED: all components reported success"