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
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
214 lines
15 KiB
Markdown
214 lines
15 KiB
Markdown
# 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.
|