Files
tqcq 083b1f36a8
Gitea Actions Compatibility Suite / aggregate (push) Successful in 0s
Gitea Actions Compatibility Suite / c8 (push) Successful in 2s
Gitea Actions Compatibility Suite / c9 (push) Successful in 58s
Gitea Actions Compatibility Suite / c10 (push) Successful in 0s
Gitea Actions Compatibility Suite / probe (push) Successful in 0s
Gitea Actions Compatibility Suite / c1 (push) Successful in 7s
Gitea Actions Compatibility Suite / c2 (push) Successful in 4s
Gitea Actions Compatibility Suite / c3 (push) Successful in 1m24s
Gitea Actions Compatibility Suite / c4 (push) Successful in 12s
Gitea Actions Compatibility Suite / c5 (push) Successful in 0s
Gitea Actions Compatibility Suite / c6 (push) Successful in 1s
Gitea Actions Compatibility Suite / c7 (push) Successful in 44s
feat: Gitea Actions compatibility test suite
A self-validating test suite that proves Gitea's implementations of
GitHub-style actions behave like GitHub's. Push to any Gitea instance
with a registered runner — on push or manual dispatch, it runs 10
independent test workflows covering checkout, artifacts, caching,
language setup, expression contexts, workflow commands, services,
composite/reusable workflows, control flow, and known divergences.

Components:
- lib/assert.sh — self-asserting shell helper library (assert_eq,
  assert_contains, assert_exists, assert_not_exists, assert_match,
  sha256_of) with verified negative fail path
- 10 reusable workflows (on: workflow_call):
  01-checkout, 02-artifacts, 03-cache, 04-setup-runtime,
  05-contexts, 06-workflow-commands, 07-services,
  08-composite-reusable, 09-control-flow, 10-gitea-divergences
- 00-suite-runner.yml — sole entry (on: push + workflow_dispatch):
  probe gate (Gitea >= 1.22.0) -> c1-c10 parallel callers
  (c5/c8 forward secrets: inherit for act_runner #125) ->
  aggregate (if: always, skipped-as-failure)
- Fixtures: LFS 5MB binary, git tag v1-test, 4 language lockfiles
  (npm/go/pip/maven), sparse-cone layout
- Makefile: make lint (actionlint static gate)
- README: prerequisites, per-test expectations, correction table,
  manual eyeball checklist for UI-only behaviors
2026-07-07 17:13:09 +00:00

15 KiB

gitea-actions-compat-test

A self-asserting compatibility suite for Gitea Actions. Push this repo to a Gitea instance with a registered runner, and 00-suite-runner.yml runs ten independent test workflows that prove Gitea's implementation of GitHub-style actions behaves like GitHub's. The suite uses two strategies depending on what it tests:

  • Feature tests (C1, C5, C6, C9): assert the feature works. A failure means the feature is broken.
  • Divergence probes (C2-v4, C8, C10-v4): assert the current state of a known Gitea divergence. Both outcomes (divergence present or fixed) are PASS; the assertion message documents which state was found. A failure means something unexpected happened.
  • Infrastructure-dependent tests (C3, C4, C7): fully verify when the prerequisite is met. When it isn't (no Docker, no cache server, TLS blocked), assertions are skipped with a ::warning:: documenting what was NOT verified.

A green run means "no unexpected failures." Read the per-test table and the assertion messages in the logs to understand exactly what was verified vs. what was skipped on your instance.

This README is the human-facing guide. It tells you what to set up before you push, what each test verifies, where the docs disagree with the source code, and which behaviors cannot be checked from inside a job (those live in the manual eyeball checklist at the bottom).


HARD prerequisites

Only the Gitea version check is a hard gate (the probe job fails if version < 1.22.0). All other prerequisites below are informational: the probe prints best-effort notes about them but does NOT fail if they are missing. Components that depend on them will conditionally skip with ::warning::.

Runner

  • A runner registered with the label used by runs-on. The default label is ubuntu-24.04. If your instance uses a different label, set RUNS_ON_LABEL (or edit runs-on: in every workflow) to match, or the jobs will sit in waiting forever.

Gitea version

  • Gitea >= 1.22.0. This is the minimum to PARSE/accept these workflows. It is NOT a guarantee that every component passes. Several checks (notably the upload-artifact@v4 regression and reusable-workflow secret passthrough) may still fail on 1.22.x and only turn green on later point releases. See the per-test table below for which components need a newer version.

    To be explicit about the two thresholds:

    Threshold Meaning
    1.22.0 Minimum to PARSE/accept the workflow YAML. Below this, the runner rejects the suite outright.
    higher, version-dependent Minimum to PASS all components. Each component that needs more lists its version note in the per-test table.

Storage and caches

  • Storage backend enabled. The artifact and cache actions need object storage (local, MinIO, S3-compatible). Without it, uploads and downloads error out.
  • Cache server enabled. actions/cache@v3 relies on the Gitea cache server. Confirm it is reachable before expecting C3 to pass.
  • LFS enabled. test.bin is an LFS object. The checkout LFS test (C1) and the fixtures depend on git lfs working on both the server and the runner.

Action mirroring

  • Action mirroring allowed. ACTIONS_URL and DEFAULT_ACTIONS_URL must NOT be set to a non-mirror strategy. The workflows reference actions by the owner/repo@ref shorthand (for example actions/checkout@v4), which Gitea resolves by mirroring the upstream action on first use. If mirroring is off or pointed at a custom non-mirror source, those uses: refs 404 and the run fails at fetch time. The mirror fetch is itself a behavior under test.

Secrets

  • A repo secret TEST_SECRET=placeholder. Define it in the repo settings. The reusable workflows that read it (05-contexts and 08-composite-reusable) receive it through explicit forwarding (secrets: inherit) in the caller jobs, because Gitea's act_runner does not auto-forward caller secrets into reusable workflows by default (see act_runner #125 in the correction table). The placeholder value placeholder is what the assertion checks for, so do not put anything else there unless you also update the assertion.

Warm-up: run workflow_dispatch once

After first setup, trigger the suite once via the Run workflow button (workflow_dispatch) before drawing any conclusions from a push run. Action mirroring is lazy. The first fetch of each actions/* ref can take a moment to populate, and a cold run may show spurious fetch failures that vanish on the second attempt. One warm-up dispatch lets the mirror settle.


Per-test expectations

The suite is split into ten reusable workflows (on: workflow_call), each invoked by a caller job (c1 through c10) in 00-suite-runner.yml. Each component reports its own pass/fail, and aggregate fails the whole run if any component is not success (a skipped or cancelled component counts as failure).

# Workflow What it verifies Expected result Min-version notes
C1 01-checkout actions/checkout@v4 variants: default checkout, fetch-depth, lfs, ref to a tag, path, sparse-checkout cone, and persist-credentials (both true and false, with a non-vacuous assertion that the embedded credential token differs between the two). Pass on Gitea >= 1.22 with LFS enabled. The LFS sub-case is conditional on git lfs being present. 1.22.0 to parse. LFS sub-case needs LFS enabled on both server and runner.
C2 02-artifacts Artifacts v3 and v4 round-trip, cross-job checksum comparison (producer writes, consumer verifies sha256). v3 fully verified. v4 upload uses continue-on-error: true; if it fails (GHESNotSupportedError), the test asserts regression-confirmed (Gitea #31256). If it succeeds, full v4 checksum verification runs. v4 needs a point release after the #31256 fix. v3 works on 1.22.
C3 03-cache Cache save/restore: a seed job writes a file and caches it (first run is a miss that saves), a restore job asserts an exact-key hit, then a miss-with-restore-keys fallback. Fully verified when cache server is reachable. When cache server is down, all cache assertions are skipped with ::warning::. Cache server must be configured for meaningful verification.
C4 04-setup-runtime setup-node, setup-python, setup-go, setup-java (Temurin, Maven) in a matrix, each asserting the installed version. Fully verified when setup actions can download runtimes. If TLS/network blocks downloads (self-signed cert), assertions are skipped with ::warning::. 1.22.0. Runtime downloads require internet access with valid TLS.
C5 05-contexts github.sha / github.ref / github.run_id, a job env: var round-tripping into a step, the auto-injected GITHUB_TOKEN (via env: mapping), the forwarded TEST_SECRET (skipped if empty), needs outputs consumed by a dependent job, and if: conditionals with success() / always(). failure() tested via step-level continue-on-error + outcome/conclusion assertion. Pass. TEST_SECRET assertion is skipped with a message if the repo secret is unset. 1.22.0 to parse. Secret forwarding depends on act_runner #125 (see correction table).
C6 06-workflow-commands GITHUB_OUTPUT (multi-line value, consumed via step output), GITHUB_PATH (added dir becomes callable), GITHUB_ENV (set in one step, read in the next), and ::warning:: / ::error:: / ::notice:: annotations plus $GITHUB_STEP_SUMMARY. Pass. The annotation assertion is emit-only: it checks the command was accepted and the process did not crash. Annotation RENDERING in the UI is a manual checklist item. 1.22.0. Rendering is UI-dependent (manual).
C7 07-services postgres:16 and redis:7 services with healthchecks, plus a container: node:20 job. Fully verified when Docker is available. On host-mode runners (no Docker), service/container assertions are skipped with ::warning::. 1.22.0. Docker on the runner is required for meaningful verification.
C8 08-composite-reusable A local composite action (lib/composite-greet) with input/output round-trip, and a reusable workflow that declares inputs and secrets on its workflow_call trigger. Composite action fully verified. inputs.who and TEST_SECRET assertions document the current state of act_runner #125: PASS with "divergence-confirmed" if empty, PASS with value check if populated. Version-dependent. See the note below.
C9 09-control-flow timeout-minutes at step level (step killed, outcome asserted as failure via continue-on-error), continue-on-error outcome/conclusion split, and concurrency as parse-and-accept only. Pass. If step-level timeout-minutes is not enforced by the runner, a ::warning:: is emitted. Concurrency cancellation is manual-only. 1.22.0. Step-level timeout-minutes may not be supported on all runner versions.
C10 10-gitea-divergences environment: non-blocking proof (fully verified), upload-artifact@v4 regression re-confirm (asserts regression-confirmed if v4 fails, v4-ok if it succeeds), and problem matchers emitted (emit-only). environment: non-blocking fully verified. v4 reconfirm asserts current state of #31256. Matcher rendering is manual-only. 1.22.0 to parse. v4 needs the fix from #31256.

Correction table: where docs and source disagree

GitHub's public docs describe the canonical runtime. Gitea's act implementation sometimes diverges. The table below records the known divergences with source citations and the covering test. Keep this bounded: at most 10 rows.

topic doc-claim source-truth citation covering-test
timeout-minutes Docs say it cancels a runaway job. Source enforces it. job_executor.go around L370-380 applies the timeout and kills the job. act source (job_executor.go L370-380) C9
success / failure / cancelled / always Docs describe four status-check functions. All four are implemented. interpreter.go around L621-640 defines them. act source (interpreter.go L621-640) C5
environment: Docs say it gates deployments behind protection rules. Genuinely unsupported. There is no environment field on the Job struct in act, so the key is parsed but treated as a no-op. act source (Job struct) C10
upload-artifact@v4 Docs frame v4 as a drop-in replacement for v3. Not on Gitea 1.22. v4 triggers a GHES-style regression error. Reported fixed but may recur on certain configurations (see Gitea issue #36024 for a Nov 2025 recurrence on Docker-based runners). Gitea issue #31256 C2, C10
Reusable-workflow secret inheritance Docs say secrets auto-forward to called workflows. They do not by default. You must pass secrets: inherit (or list them explicitly), otherwise the called workflow sees empty secrets. act_runner #125 C5, C8
continue-on-error Docs say the job reports success to dependents despite a tolerated step failure. Source honors this. workflow.go SetContinueOnError around L216-227 sets the result. act source (workflow.go L216-227) C9
Problem matchers Docs say registered matchers render annotations in the UI. Registration is accepted, but rendering depends on the Gitea UI and cannot be observed from inside the job. act source (matcher registration path) C6, C10
concurrency: cancel-in-progress Docs say an in-flight run is cancelled when a newer run starts. Enforcement is server-side and not observable from within the run. The suite parses and accepts the key only. Gitea server-side enforcement C9

reusable-workflow secret passthrough fix version

act_runner #125 is now CLOSED, fixed via act PR #41 ("Parse secret inputs in reusable workflows"). This suite still tests the behavior empirically in C8 (and the forwarding path in C5) rather than assuming a version, because the fix landed across several act and Gitea releases and older instances may still be affected. If C8 fails on your instance, the most likely cause is that you are running a version where the fix has not landed yet. Check the act_runner #125 thread for the current status rather than gating on a specific Gitea version number.


Manual eyeball checklist (UI-only behaviors)

A workflow cannot observe its own rendered UI. These behaviors are emitted where possible and left for a human to confirm in the Gitea web interface after a run.

  • Annotation rendering. Open the run for 06-workflow-commands. Confirm the ::warning::, ::error::, and ::notice:: messages appear as rendered annotations on the relevant steps (not just as raw text in the log).
  • Step summary rendering. In the same run, confirm the content written to $GITHUB_STEP_SUMMARY appears in the run's summary view.
  • Run cancellation. Trigger a run, then cancel it from the UI while it is executing. Confirm the run transitions to a cancelled state and that the aggregate job reflects it as a failure (not green).
  • Deployment environment gate. Note that environment: is treated as a no-op by act (see the correction table). There is no protection-rule gate to enforce, so this item is about confirming that absence rather than testing a gate. If you need real environment gating, that is a known gap.

Repository layout

.github/
  actionlint.yaml            narrowly-scoped lint config
  problem-matcher.json       problem matcher fixture
  workflows/
    00-suite-runner.yml      entry: probe -> c1..c10 -> aggregate
    01-checkout.yml          C1
    02-artifacts.yml         C2
    03-cache.yml             C3
    04-setup-runtime.yml     C4
    05-contexts.yml          C5
    06-workflow-commands.yml C6
    07-services.yml          C7
    08-composite-reusable.yml C8
    09-control-flow.yml      C9
    10-gitea-divergences.yml C10
lib/
  assert.sh                  self-asserting shell helpers
  composite-greet/action.yml local composite action (used by C8)
fixtures/                    sha256 of the LFS object, etc.
sparse-cone/                 layout for sparse-checkout tests
Makefile                     `make lint` runs actionlint

Numeric filename prefixes do NOT imply execution order. Ordering comes only from needs:. The prefixes exist to give humans a stable reading order.


Running the suite

  1. Push the repo to your Gitea instance.
  2. Confirm every HARD prerequisite above (runner label, version, storage, cache, LFS, mirroring, TEST_SECRET).
  3. Trigger one warm-up workflow_dispatch.
  4. Read the per-test results. aggregate is green only when the probe and every c1..c10 are success.
  5. Walk the manual eyeball checklist for the UI-only behaviors.