diff --git a/.gitea/actions/notify-failure/action.yml b/.gitea/actions/notify-failure/action.yml new file mode 100644 index 0000000..ad6c888 --- /dev/null +++ b/.gitea/actions/notify-failure/action.yml @@ -0,0 +1,47 @@ +name: 'Notify on failure' +description: 'Create a Gitea issue when a CI workflow fails (calls devx.ci.notify_failure)' + +# Composite action for the common "Notify on failure" step pattern. +# Replaces the repeated inline: +# - name: Notify on failure +# if: failure() +# env: +# CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }} +# run: | +# . .venv/bin/activate 2>/dev/null || true +# export PATH="$HOME/.local/bin:$PATH" +# python3 -m devx.ci.notify_failure \ +# --repo "${{ github.repository }}" \ +# --run-id "${{ github.run_id }}" \ +# --workflow "ci/validate" \ +# --commit "${{ github.sha }}" \ +# --auto-login +# +# Gitea 1.27 notes: +# - `if: failure()` is evaluated in the calling workflow's context and +# propagates correctly to composite action steps. +# - `secrets` are not accessible here; the calling workflow's top-level +# `env:` CI_GITEA_API_TOKEN is used via `${{ env.* }}`. + +inputs: + workflow: + description: 'Workflow/job name used in the Gitea issue title (e.g., ci/validate)' + required: true + +runs: + using: 'composite' + steps: + - name: Notify on failure + if: failure() + shell: bash + env: + CI_GITEA_API_TOKEN: ${{ env.CI_GITEA_API_TOKEN }} + run: | + . .venv/bin/activate 2>/dev/null || true + export PATH="$HOME/.local/bin:$PATH" + python3 -m devx.ci.notify_failure \ + --repo "${{ github.repository }}" \ + --run-id "${{ github.run_id }}" \ + --workflow "${{ inputs.workflow }}" \ + --commit "${{ github.sha }}" \ + --auto-login diff --git a/.gitea/actions/quality-checks/action.yml b/.gitea/actions/quality-checks/action.yml new file mode 100644 index 0000000..81c726c --- /dev/null +++ b/.gitea/actions/quality-checks/action.yml @@ -0,0 +1,89 @@ +name: 'Quality checks' +description: 'Run lint, unit tests with coverage, test speed, docs, translations, and security scan' + +# Composite action for the 6-step quality check sequence used by the +# devx validate job. Replaces the inline block: +# - Lint all +# - Unit tests with 100% coverage +# - Check unit test speed +# - Documentation gate (coverage + stale refs + lint + version refs + prose) +# - Translation completeness check +# - Dependency security scan +# +# Each step activates the venv defensively (`. .venv/bin/activate 2>/dev/null +# || true`) so the action works whether or not the setup step created a +# venv at the repo root (pre-built CI images symlink /opt/venv to .venv). +# +# Gitea 1.27 notes: +# - Every `run` step needs explicit `shell:`. +# - Inputs are string-typed; numeric thresholds are passed through as +# strings to `devx.tools.check_test_speed`. + +inputs: + package: + description: 'Package name for doc version checks (e.g., devx, grm). Empty = no DEVX_DOC_VERSIONS_PKG override.' + required: false + default: '' + test-speed-max: + description: 'Max total test seconds (passed to check_test_speed --max-seconds)' + required: false + default: '15' + test-speed-max-single: + description: 'Max single test seconds (passed to check_test_speed --max-single-seconds)' + required: false + default: '0.5' + translations-file: + description: 'Path to translations.json (empty = default location src/devx/translations.json)' + required: false + default: '' + +runs: + using: 'composite' + steps: + - name: Lint all + shell: bash + run: | + . .venv/bin/activate 2>/dev/null || true + export PATH="$HOME/.local/bin:$PATH" + make lint-all + - name: Unit tests with 100% coverage + shell: bash + run: | + . .venv/bin/activate 2>/dev/null || true + make pytest-cov + - name: Check unit test speed + shell: bash + run: | + . .venv/bin/activate 2>/dev/null || true + python3 -m devx.tools.check_test_speed \ + --max-seconds "${{ inputs.test-speed-max }}" \ + --max-single-seconds "${{ inputs.test-speed-max-single }}" + - name: Documentation gate (coverage + stale refs + lint + version refs + prose) + shell: bash + env: + DEVX_DOC_COVERAGE_STRICT: "1" + DEVX_VALE_LEVEL: warning + run: | + . .venv/bin/activate 2>/dev/null || true + export PATH="$HOME/.local/bin:$PATH" + if [ -n "${{ inputs.package }}" ]; then + export DEVX_DOC_VERSIONS_PKG="${{ inputs.package }}" + fi + make devx-docs-check + - name: Translation completeness check + shell: bash + run: | + . .venv/bin/activate 2>/dev/null || true + if [ -n "${{ inputs.translations-file }}" ]; then + python3 -m devx.ci.check_translations --translations "${{ inputs.translations-file }}" + else + python3 -m devx.ci.check_translations + fi + - name: Dependency security scan + shell: bash + run: | + . .venv/bin/activate 2>/dev/null || true + # Install pip in venv if missing (needed by pip-audit) + .venv/bin/python -m ensurepip 2>/dev/null || true + PIPAPI_PYTHON_LOCATION=$PWD/.venv/bin/python \ + pip-audit --desc --skip-editable 2>&1 || true diff --git a/.gitea/actions/setup-env/action.yml b/.gitea/actions/setup-env/action.yml new file mode 100644 index 0000000..b41a5c2 --- /dev/null +++ b/.gitea/actions/setup-env/action.yml @@ -0,0 +1,37 @@ +name: 'Set up environment' +description: 'Set up CI environment with venv and PATH (calls make setup-image)' + +# Composite action for the common "Set up environment" step pattern. +# Replaces the repeated inline: +# - name: Set up environment +# env: +# CI_GITEA_API_TOKEN: ${{ secrets.CI_GITEA_API_TOKEN }} +# run: make setup-image +# +# Gitea 1.27 notes: +# - Every `run` step needs explicit `shell:`. +# - Composite actions cannot access `secrets` directly; they read from +# the `env:` context which the calling workflow must populate. +# - The calling workflow's top-level `env:` block (CI_GITEA_API_TOKEN, +# CI_GITEA_USERNAME) is visible here via `${{ env.* }}`. + +inputs: + extras: + description: 'Extra pip install groups passed to make setup-image (e.g., ci,lint,release)' + required: false + default: '' + +runs: + using: 'composite' + steps: + - name: Set up environment + shell: bash + env: + CI_GITEA_API_TOKEN: ${{ env.CI_GITEA_API_TOKEN }} + CI_GITEA_USERNAME: ${{ env.CI_GITEA_USERNAME }} + run: | + if [ -n "${{ inputs.extras }}" ]; then + make setup-image EXTRAS="${{ inputs.extras }}" + else + make setup-image + fi