GRM-51: ci: add actionlint and act_runner exec for workflow verification
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
# actionlint configuration for Gitea Actions workflows
|
||||||
|
# https://github.com/rhysd/actionlint/blob/main/docs/config.md
|
||||||
|
#
|
||||||
|
# Run: actionlint -config-file .gitea/actionlint.yaml .gitea/workflows/*.yml
|
||||||
|
|
||||||
|
# Custom self-hosted runner labels used in runs-on
|
||||||
|
self-hosted-runner:
|
||||||
|
labels:
|
||||||
|
- docker
|
||||||
@@ -18,10 +18,14 @@ jobs:
|
|||||||
REPO_TOKEN: ${{ secrets.REPO_TOKEN }}
|
REPO_TOKEN: ${{ secrets.REPO_TOKEN }}
|
||||||
VIKUNJA_TOKEN: ${{ secrets.VIKUNJA_TOKEN }}
|
VIKUNJA_TOKEN: ${{ secrets.VIKUNJA_TOKEN }}
|
||||||
PYTHONPATH: src
|
PYTHONPATH: src
|
||||||
|
HEAD_REF: ${{ github.head_ref }}
|
||||||
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||||
|
REPOSITORY: ${{ github.repository }}
|
||||||
|
PR_NUMBER: ${{ github.event.number }}
|
||||||
run: |
|
run: |
|
||||||
python3 scripts/ci/auto_merge.py \
|
python3 scripts/ci/auto_merge.py \
|
||||||
"${{ github.head_ref }}" \
|
"$HEAD_REF" \
|
||||||
"${{ github.event.pull_request.title }}" \
|
"$PR_TITLE" \
|
||||||
"${{ github.repository }}" \
|
"$REPOSITORY" \
|
||||||
"${{ github.event.number }}" \
|
"$PR_NUMBER" \
|
||||||
"ready-to-merge"
|
"ready-to-merge"
|
||||||
|
|||||||
+12
-4
@@ -13,9 +13,16 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Set up environment
|
- name: Set up environment
|
||||||
run: make setup
|
run: make setup
|
||||||
|
- name: Install actionlint
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
mkdir -p "$HOME/.local/bin"
|
||||||
|
bash <(curl -sL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) latest "$HOME/.local/bin"
|
||||||
|
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||||
- name: Lint all
|
- name: Lint all
|
||||||
run: |
|
run: |
|
||||||
. .venv/bin/activate
|
. .venv/bin/activate
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
make lint-all
|
make lint-all
|
||||||
- name: Unit tests with 100% coverage
|
- name: Unit tests with 100% coverage
|
||||||
run: |
|
run: |
|
||||||
@@ -150,14 +157,14 @@ jobs:
|
|||||||
# Skip if runner index exceeds available runners
|
# Skip if runner index exceeds available runners
|
||||||
if [ "$RUNNER_INDEX" -gt "$MAX_RUNNERS" ]; then
|
if [ "$RUNNER_INDEX" -gt "$MAX_RUNNERS" ]; then
|
||||||
echo "Skipping — runner index $RUNNER_INDEX > max runners $MAX_RUNNERS"
|
echo "Skipping — runner index $RUNNER_INDEX > max runners $MAX_RUNNERS"
|
||||||
echo "TEST_PAIRS=" >> $GITHUB_ENV
|
echo "TEST_PAIRS=" >> "$GITHUB_ENV"
|
||||||
echo "SKIP=true" >> $GITHUB_ENV
|
echo "SKIP=true" >> "$GITHUB_ENV"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
PAIRS=$(python3 scripts/ci/distribute_molecule.py --runner-index "$RUNNER_INDEX" --max-runners "$MAX_RUNNERS")
|
PAIRS=$(python3 scripts/ci/distribute_molecule.py --runner-index "$RUNNER_INDEX" --max-runners "$MAX_RUNNERS")
|
||||||
echo "Assigned pairs: $PAIRS"
|
echo "Assigned pairs: $PAIRS"
|
||||||
echo "TEST_PAIRS=$PAIRS" >> $GITHUB_ENV
|
echo "TEST_PAIRS=$PAIRS" >> "$GITHUB_ENV"
|
||||||
echo "SKIP=false" >> $GITHUB_ENV
|
echo "SKIP=false" >> "$GITHUB_ENV"
|
||||||
- name: Run molecule tests
|
- name: Run molecule tests
|
||||||
if: env.SKIP != 'true'
|
if: env.SKIP != 'true'
|
||||||
run: |
|
run: |
|
||||||
@@ -167,6 +174,7 @@ jobs:
|
|||||||
echo "No test pairs assigned — skipping"
|
echo "No test pairs assigned — skipping"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
# shellcheck disable=SC2086 # intentional word splitting for argument expansion
|
||||||
python3 scripts/ci/molecule_ci_guard.py $TEST_PAIRS
|
python3 scripts/ci/molecule_ci_guard.py $TEST_PAIRS
|
||||||
env:
|
env:
|
||||||
GITEA_URL: ${{ github.server_url }}
|
GITEA_URL: ${{ github.server_url }}
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ jobs:
|
|||||||
git checkout --orphan badges
|
git checkout --orphan badges
|
||||||
git rm -rf .
|
git rm -rf .
|
||||||
cp -r .badges/* .
|
cp -r .badges/* .
|
||||||
git add *.svg
|
git add ./*.svg
|
||||||
git commit --no-verify -m "Update badges [skip ci]"
|
git commit --no-verify -m "Update badges [skip ci]"
|
||||||
git push origin badges --force
|
git push origin badges --force
|
||||||
- name: Notify on failure
|
- name: Notify on failure
|
||||||
|
|||||||
@@ -48,6 +48,15 @@ repos:
|
|||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
stages: [pre-commit]
|
stages: [pre-commit]
|
||||||
|
|
||||||
|
- id: workflow-lint
|
||||||
|
name: actionlint (workflow YAML)
|
||||||
|
entry: make workflow-lint
|
||||||
|
language: system
|
||||||
|
files: ^\.gitea/workflows/
|
||||||
|
types: [yaml]
|
||||||
|
pass_filenames: false
|
||||||
|
stages: [pre-commit]
|
||||||
|
|
||||||
- id: pytest-cov
|
- id: pytest-cov
|
||||||
name: pytest with 100% coverage
|
name: pytest with 100% coverage
|
||||||
entry: make pytest-cov
|
entry: make pytest-cov
|
||||||
|
|||||||
@@ -4,14 +4,35 @@
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
make setup # Create venv, install deps, set up hooks
|
make setup # Create venv, install deps, set up hooks
|
||||||
make lint-all # ruff + pyright + bandit + ansible-lint + checkmake
|
make lint-all # ruff + pyright + bandit + ansible-lint + checkmake + actionlint
|
||||||
make pytest-cov # Unit tests with 100% coverage enforcement
|
make pytest-cov # Unit tests with 100% coverage enforcement
|
||||||
make test-unit # Unit tests without coverage
|
make test-unit # Unit tests without coverage
|
||||||
make molecule # All 6 scenarios on Ubuntu 22.04
|
make molecule # All 6 scenarios on Ubuntu 22.04
|
||||||
make molecule-all # All 6 scenarios on all 4 supported OSes
|
make molecule-all # All 6 scenarios on all 4 supported OSes
|
||||||
make test-all # pytest-cov + molecule
|
make test-all # pytest-cov + molecule
|
||||||
|
make workflow-lint # Static lint of .gitea/workflows/*.yml (actionlint)
|
||||||
|
make workflow-dryrun # Dry-run all workflows in Docker (act_runner exec --dryrun)
|
||||||
|
make workflow-check # workflow-lint + workflow-dryrun
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Workflow Verification (Before Push)
|
||||||
|
|
||||||
|
Workflow YAML files (`.gitea/workflows/*.yml`) are verified with two tools:
|
||||||
|
|
||||||
|
1. **actionlint** — Static linter that catches syntax errors, invalid
|
||||||
|
expressions, unknown keys, type mismatches, and shellcheck issues.
|
||||||
|
Config: `.gitea/actionlint.yaml` (registers custom `docker` runner label).
|
||||||
|
Install: `bash <(curl -sL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)`
|
||||||
|
|
||||||
|
2. **act_runner exec --dryrun** — Gitea's own runner in dry-run mode.
|
||||||
|
Validates job dependencies, step ordering, and Docker image selection
|
||||||
|
without starting containers. Install from
|
||||||
|
[gitea/act_runner releases](https://gitea.com/gitea/act_runner/releases).
|
||||||
|
|
||||||
|
Both run via `make workflow-check` and are part of `make lint-all`.
|
||||||
|
The pre-commit hook runs actionlint automatically when workflow files change.
|
||||||
|
The CI `quality` job installs actionlint and runs `make lint-all`.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
- **Python CLI** (`src/gitea_runner_manager/`) — Click-based CLI that delegates to Ansible
|
- **Python CLI** (`src/gitea_runner_manager/`) — Click-based CLI that delegates to Ansible
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: all setup install update lint ansible-lint makefile-lint lint-all test test-unit pytest-cov molecule molecule-all test-all clean
|
.PHONY: all setup install update lint ansible-lint makefile-lint lint-all test test-unit pytest-cov molecule molecule-all test-all clean workflow-lint workflow-dryrun workflow-check
|
||||||
|
|
||||||
PYTHON := python3
|
PYTHON := python3
|
||||||
VENV := .venv
|
VENV := .venv
|
||||||
@@ -86,7 +86,22 @@ ansible-lint:
|
|||||||
makefile-lint:
|
makefile-lint:
|
||||||
@$(CHECKMAKE) Makefile
|
@$(CHECKMAKE) Makefile
|
||||||
|
|
||||||
lint-all: lint ansible-lint makefile-lint
|
lint-all: lint ansible-lint makefile-lint workflow-lint
|
||||||
|
|
||||||
|
workflow-lint:
|
||||||
|
@command -v actionlint >/dev/null 2>&1 || { \
|
||||||
|
echo "actionlint not found. Install: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)"; \
|
||||||
|
exit 1; \
|
||||||
|
}
|
||||||
|
actionlint -config-file .gitea/actionlint.yaml .gitea/workflows/*.yml
|
||||||
|
|
||||||
|
workflow-dryrun:
|
||||||
|
@command -v act_runner >/dev/null 2>&1 || { echo "act_runner not found. Install: https://gitea.com/gitea/act_runner/releases"; exit 1; }
|
||||||
|
@echo "Dry-running all workflows (no Docker containers started)..."
|
||||||
|
act_runner exec --dryrun -W .gitea/workflows/ 2>&1 | grep -E 'DRYRUN|ERROR|FAIL|Job'
|
||||||
|
|
||||||
|
workflow-check: workflow-lint workflow-dryrun
|
||||||
|
@echo "Workflow checks passed (static lint + dry-run)."
|
||||||
|
|
||||||
test-unit:
|
test-unit:
|
||||||
$(BIN)/pytest tests/unit/ -v --no-cov
|
$(BIN)/pytest tests/unit/ -v --no-cov
|
||||||
|
|||||||
Reference in New Issue
Block a user