Files
runner-test/.github/workflows/06-workflow-commands.yml
tqcq 703410dc3d
Setup Runtime (C4) / setup-go (push) Successful in 2s
Gitea Actions Compatibility Suite / probe (push) Successful in 1s
Checkout Variants (C1) / checkout-variants (push) Successful in 3s
Setup Runtime (C4) / setup-java (push) Successful in 45s
Setup Runtime (C4) / setup-node (push) Successful in 3s
Setup Runtime (C4) / setup-python (push) Successful in 3s
Artifacts v3+v4 round-trip / producer (push) Successful in 3s
C3 cache / restore (push) Successful in 44s
C3 cache / seed (push) Successful in 44s
C5 - Contexts / consume needs output (push) Successful in 1s
C5 - Contexts / github/env/token/secrets/status-fns (push) Successful in 1s
C5 - Contexts / failure-test (push) Successful in 0s
C5 - Contexts / produce needs output (push) Successful in 1s
06 Workflow Commands / workflow-commands (push) Successful in 1s
C7 - services / services (postgres + redis, healthcheck-gated) (push) Successful in 1s
C7 - services / container (node:20, bash present) (push) Successful in 13s
C8 - Composite Action and Reusable Workflow / composite-reusable (push) Successful in 0s
09-control-flow / timeout + continue-on-error + concurrency (push) Successful in 1m1s
Artifacts v3+v4 round-trip / consumer (push) Successful in 0s
Gitea Divergences (C10) / environment-result-check (push) Successful in 2s
Gitea Divergences (C10) / environment-non-blocking (push) Successful in 0s
Gitea Divergences (C10) / problem-matcher-emit (push) Successful in 1s
Gitea Divergences (C10) / upload-artifact-v4-reconfirm (push) Successful in 0s
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-08 02:05:11 +00:00

165 lines
7.6 KiB
YAML

# C6 — workflow-commands compatibility test.
#
# Verifies the runner honours the modern file-based workflow-command interface:
# * $GITHUB_OUTPUT (single-line + multi-line value via heredoc delimiter)
# * $GITHUB_PATH (added directory becomes callable in a LATER step)
# * $GITHUB_ENV (var set in one step is visible in the NEXT step)
# * $GITHUB_STEP_SUMMARY
# * ::warning:: / ::error:: / ::notice:: workflow commands
#
# Annotation assertion policy (important):
# A job CANNOT observe its own RENDERED annotations in the UI. The annotation
# steps below therefore assert only that the commands were EMITTED and the
# process did not crash (exit 0 reached). Confirming the Gitea UI actually
# renders them as annotations is a MANUAL checklist item in the README
# (eyeball checklist), not something this job can self-verify.
#
# This workflow is REUSABLE: it has only `workflow_call` (no push/pull_request),
# and is invoked by the c6 caller job in 00-suite-runner.yml.
name: "06 Workflow Commands"
on: [push, workflow_dispatch]
permissions:
contents: read
jobs:
workflow-commands:
runs-on: ubuntu-24.04
steps:
# ------------------------------------------------------------------
# Bootstrap: check out the repo so lib/assert.sh is on disk, then
# source it. assert_* log [PASS]/[FAIL] to stderr and return 0/1.
# We do NOT set `set -e` globally: assert.sh leaves flow control to
# the caller, so each step explicitly checks $? after asserting.
# ------------------------------------------------------------------
- name: Checkout
uses: actions/checkout@v4
- name: Source assert library
id: source-lib
shell: bash
run: |
# shellcheck source=lib/assert.sh
source ./lib/assert.sh
# Smoke-check that sourcing actually loaded the functions.
assert_eq "${BASH_SOURCE[1]:-sourced}" "sourced" "assert.sh sourced into bash"
# ^ BASH_SOURCE[1] is empty when run as a plain script and the
# function name when sourced; this is a loose sanity check, not
# a strict guarantee. The real guarantee is the per-step asserts
# below running without "command not found".
# ------------------------------------------------------------------
# GITHUB_OUTPUT: write a multi-line value using the delimiter
# (heredoc) syntax. The NEXT step consumes it via steps.<id>.outputs.
# ------------------------------------------------------------------
- name: Write GITHUB_OUTPUT (multi-line value)
id: output-writer
shell: bash
run: |
source ./lib/assert.sh
# Single-line value.
echo "simple=hello" >> "$GITHUB_OUTPUT"
# Multi-line value via delimiter (the modern replacement for
# the deprecated ::set-output heredoc hack).
{
echo "myval<<DELIMITER_EOF"
echo "line1"
echo "line2"
echo "DELIMITER_EOF"
} >> "$GITHUB_OUTPUT"
# Sanity: the file actually received the block.
assert_contains "$(cat "$GITHUB_OUTPUT")" "DELIMITER_EOF" "GITHUB_OUTPUT delimiter block written"
- name: Assert GITHUB_OUTPUT consumed via step output
id: output-check
shell: bash
run: |
source ./lib/assert.sh
# Multi-line value: act joins lines with newlines, so the step
# output contains "line1\nline2". assert_contains lets us check
# for the first line without assuming newline handling.
assert_contains "${{ steps.output-writer.outputs.myval }}" "line1" "GITHUB_OUTPUT multi-line value consumed"
assert_eq "${{ steps.output-writer.outputs.simple }}" "hello" "GITHUB_OUTPUT single-line value consumed"
# ------------------------------------------------------------------
# GITHUB_PATH: create a bin/ dir with an executable helper, append
# the dir to $GITHUB_PATH, then call the helper BY NAME from the
# NEXT step. If the runner honoured $GITHUB_PATH, the call resolves.
# ------------------------------------------------------------------
- name: Append dir to GITHUB_PATH
id: path-writer
shell: bash
run: |
source ./lib/assert.sh
mkdir -p ./bin
cat > ./bin/myhelper <<'EOF'
#!/usr/bin/env bash
echo "helper-output"
EOF
chmod +x ./bin/myhelper
assert_exists "./bin/myhelper" "helper script created before GITHUB_PATH append"
echo "$PWD/bin" >> "$GITHUB_PATH"
assert_contains "$(cat "$GITHUB_PATH")" "/bin" "GITHUB_PATH received the dir entry"
- name: Assert GITHUB_PATH dir is callable from next step
id: path-check
shell: bash
run: |
source ./lib/assert.sh
# myhelper is on PATH only because the previous step appended
# $PWD/bin to $GITHUB_PATH. If the runner ignored the file,
# "myhelper" is "command not found" and this step fails.
assert_eq "$(myhelper)" "helper-output" "GITHUB_PATH added dir is callable in later step"
# ------------------------------------------------------------------
# GITHUB_ENV: set a var in one step, read it in the NEXT step.
# ------------------------------------------------------------------
- name: Write GITHUB_ENV
id: env-writer
shell: bash
run: |
source ./lib/assert.sh
echo "MY_ENV_VAR=envvalue" >> "$GITHUB_ENV"
assert_contains "$(cat "$GITHUB_ENV")" "MY_ENV_VAR=envvalue" "GITHUB_ENV file received the var entry"
- name: Assert GITHUB_ENV propagated to next step
id: env-check
shell: bash
run: |
source ./lib/assert.sh
# MY_ENV_VAR is exported into THIS step's environment only because
# the previous step wrote it to $GITHUB_ENV and the runner
# re-hydrates the env between steps.
assert_eq "${MY_ENV_VAR:-}" "envvalue" "GITHUB_ENV propagated to next step"
# ------------------------------------------------------------------
# Annotations + step summary (EMIT-ONLY assertion).
#
# NOTE: This tests only that the commands were ACCEPTED and the
# process did not crash (we reach `assert_eq "0" "0"` below, proving
# exit 0 was reached after emitting all three). Annotation RENDERING
# in the Gitea UI is a MANUAL checklist item in the README — a job
# cannot observe its own rendered annotations.
# ------------------------------------------------------------------
- name: Emit annotations and write step summary
id: annotations
shell: bash
run: |
source ./lib/assert.sh
# Emit the three annotation workflow commands. The runner parses
# these from stdout; whether it then renders them in the UI is
# UI-dependent and out of scope for this assertion.
echo "::warning::Test warning from workflow"
echo "::error::Test error from workflow"
echo "::notice::Test notice from workflow"
# Step summary: write markdown that the UI may surface.
echo "## Step summary test" >> "$GITHUB_STEP_SUMMARY"
# The fact that we reach this line at all proves the emit did
# not abort the step. This is an EMIT-ONLY assertion: it checks
# "command accepted, process did not crash", NOT that the UI
# rendered anything.
assert_eq "0" "0" "annotations emitted without error"
assert_exists "$GITHUB_STEP_SUMMARY" "step summary file exists after write"