From 6bf64e2195583ce83ac8e3695e10d16282bd1c4e Mon Sep 17 00:00:00 2001 From: Dmytro Sydorov Date: Mon, 16 Mar 2026 13:36:42 +0100 Subject: [PATCH] ci: add smoke tests for all reusable workflows Add 6 test workflows that call each reusable workflow_call workflow using local refs (./.github/workflows/...) to validate them on PRs. Add dispatch workflow to trigger E2E tests in the external vClusterLabs-Experiments/github-actions-test repo post-merge. --- .../workflows/dispatch-integration-tests.yaml | 34 ++++++++++++ .../workflows/test-actionlint-workflow.yaml | 38 +++++++++++++ .github/workflows/test-backport.yaml | 37 +++++++++++++ .../workflows/test-clean-github-cache.yaml | 30 ++++++++++ .../test-cleanup-backport-branches.yaml | 38 +++++++++++++ .github/workflows/test-detect-changes.yaml | 55 +++++++++++++++++++ .github/workflows/test-validate-renovate.yaml | 21 +++++++ Makefile | 3 + README.md | 18 ++++++ 9 files changed, 274 insertions(+) create mode 100644 .github/workflows/dispatch-integration-tests.yaml create mode 100644 .github/workflows/test-actionlint-workflow.yaml create mode 100644 .github/workflows/test-backport.yaml create mode 100644 .github/workflows/test-clean-github-cache.yaml create mode 100644 .github/workflows/test-cleanup-backport-branches.yaml create mode 100644 .github/workflows/test-detect-changes.yaml create mode 100644 .github/workflows/test-validate-renovate.yaml diff --git a/.github/workflows/dispatch-integration-tests.yaml b/.github/workflows/dispatch-integration-tests.yaml new file mode 100644 index 0000000..3d28579 --- /dev/null +++ b/.github/workflows/dispatch-integration-tests.yaml @@ -0,0 +1,34 @@ +name: Dispatch integration tests + +on: + push: + branches: [main] + paths: + - '.github/workflows/validate-renovate.yaml' + - '.github/workflows/actionlint.yaml' + - '.github/workflows/detect-changes.yaml' + - '.github/workflows/backport.yaml' + - '.github/workflows/clean-github-cache.yaml' + - '.github/workflows/cleanup-backport-branches.yaml' + +permissions: + contents: read + +env: + E2E_REPO: vClusterLabs-Experiments/github-actions-test + +jobs: + dispatch: # zizmor: ignore[secrets-outside-env] -- cross-org dispatch PAT, no dedicated environment needed + runs-on: ubuntu-latest + steps: + - name: Trigger integration tests + env: + GH_TOKEN: ${{ secrets.VCLUSTERLABS_DISPATCH_TOKEN }} + run: | + if ! gh api "repos/$E2E_REPO/dispatches" \ + -f event_type=integration-test \ + -f "client_payload[sha]=$GITHUB_SHA" \ + -f "client_payload[ref]=$GITHUB_REF"; then + echo "::error::Failed to dispatch integration tests to $E2E_REPO" + exit 1 + fi diff --git a/.github/workflows/test-actionlint-workflow.yaml b/.github/workflows/test-actionlint-workflow.yaml new file mode 100644 index 0000000..cd3e4ee --- /dev/null +++ b/.github/workflows/test-actionlint-workflow.yaml @@ -0,0 +1,38 @@ +name: Test actionlint workflow + +on: + pull_request: + paths: + - '.github/workflows/actionlint.yaml' + +permissions: {} + +jobs: + actionlint: + permissions: + contents: read + pull-requests: write + uses: ./.github/workflows/actionlint.yaml + with: + reporter: github-pr-check + + verify: + needs: [actionlint] + if: always() + runs-on: ubuntu-latest + steps: + - name: Check actionlint result + env: + RESULT: ${{ needs.actionlint.result }} + # actionlint.yaml skips fork PRs (head.repo.full_name != github.repository), + # so this verify step ensures we catch silent skips. + run: | + echo "actionlint result=$RESULT" + if [ "$RESULT" = "failure" ]; then + echo "::error::actionlint workflow failed unexpectedly" + exit 1 + fi + if [ "$RESULT" = "skipped" ]; then + echo "::warning::actionlint was skipped (likely a fork PR — actionlint.yaml skips forks)" + fi + echo "actionlint workflow completed with result: $RESULT" diff --git a/.github/workflows/test-backport.yaml b/.github/workflows/test-backport.yaml new file mode 100644 index 0000000..d0e8b89 --- /dev/null +++ b/.github/workflows/test-backport.yaml @@ -0,0 +1,37 @@ +name: Test backport + +on: + push: + branches: [main] + paths: + - '.github/workflows/backport.yaml' + pull_request: + paths: + - '.github/workflows/backport.yaml' + +permissions: + contents: read + +jobs: + backport: + permissions: + contents: read + uses: ./.github/workflows/backport.yaml + secrets: + gh-access-token: ${{ secrets.GITHUB_TOKEN }} + + verify: + needs: [backport] + if: always() + runs-on: ubuntu-latest + steps: + - name: Check backport result + env: + RESULT: ${{ needs.backport.result }} + run: | + echo "backport result=$RESULT" + if [ "$RESULT" != "skipped" ]; then + echo "::error::Expected backport result=skipped, got '$RESULT'" + exit 1 + fi + echo "Backport workflow completed with result: $RESULT" diff --git a/.github/workflows/test-clean-github-cache.yaml b/.github/workflows/test-clean-github-cache.yaml new file mode 100644 index 0000000..a5fe3b7 --- /dev/null +++ b/.github/workflows/test-clean-github-cache.yaml @@ -0,0 +1,30 @@ +name: Test clean-github-cache + +on: + pull_request: + paths: + - '.github/workflows/clean-github-cache.yaml' + +permissions: {} + +jobs: + clean-cache: + permissions: + actions: write + uses: ./.github/workflows/clean-github-cache.yaml + + verify: + needs: [clean-cache] + if: always() + runs-on: ubuntu-latest + steps: + - name: Check clean-cache result + env: + RESULT: ${{ needs.clean-cache.result }} + run: | + echo "clean-cache result=$RESULT" + if [ "$RESULT" = "failure" ]; then + echo "::error::clean-github-cache workflow failed unexpectedly" + exit 1 + fi + echo "clean-github-cache workflow completed with result: $RESULT" diff --git a/.github/workflows/test-cleanup-backport-branches.yaml b/.github/workflows/test-cleanup-backport-branches.yaml new file mode 100644 index 0000000..18b4cab --- /dev/null +++ b/.github/workflows/test-cleanup-backport-branches.yaml @@ -0,0 +1,38 @@ +name: Test cleanup-backport-branches + +on: + push: + branches: [main] + paths: + - '.github/workflows/cleanup-backport-branches.yaml' + pull_request: + paths: + - '.github/workflows/cleanup-backport-branches.yaml' + +permissions: {} + +jobs: + cleanup: + permissions: + contents: write + uses: ./.github/workflows/cleanup-backport-branches.yaml + with: + dry-run: ${{ format('{0}', true) }} # zizmor: ignore[obfuscation] -- workaround for actionlint treating 'true' as bool + secrets: + gh-access-token: ${{ secrets.GITHUB_TOKEN }} + + verify: + needs: [cleanup] + if: always() + runs-on: ubuntu-latest + steps: + - name: Check cleanup result + env: + RESULT: ${{ needs.cleanup.result }} + run: | + echo "cleanup result=$RESULT" + if [ "$RESULT" != "success" ]; then + echo "::error::Expected cleanup result=success (dry-run), got '$RESULT'" + exit 1 + fi + echo "cleanup-backport-branches workflow completed with result: $RESULT" diff --git a/.github/workflows/test-detect-changes.yaml b/.github/workflows/test-detect-changes.yaml new file mode 100644 index 0000000..b148188 --- /dev/null +++ b/.github/workflows/test-detect-changes.yaml @@ -0,0 +1,55 @@ +name: Test detect-changes + +on: + push: + branches: [main] + paths: + - '.github/workflows/detect-changes.yaml' + pull_request: + paths: + - '.github/workflows/detect-changes.yaml' + +permissions: + contents: read + pull-requests: read + +jobs: + detect-self: + permissions: + contents: read + pull-requests: read + uses: ./.github/workflows/detect-changes.yaml + with: + paths: "- '.github/workflows/detect-changes.yaml'" + + detect-none: + permissions: + contents: read + pull-requests: read + uses: ./.github/workflows/detect-changes.yaml + with: + paths: "- 'nonexistent-dir/**'" + + verify: + needs: [detect-self, detect-none] + runs-on: ubuntu-latest + steps: + - name: Assert detect-self found changes + env: + HAS_CHANGED: ${{ needs.detect-self.outputs.has_changed }} + run: | + echo "detect-self has_changed=$HAS_CHANGED" + if [ "$HAS_CHANGED" != "true" ]; then + echo "::error::Expected detect-self has_changed=true, got '$HAS_CHANGED'" + exit 1 + fi + + - name: Assert detect-none found no changes + env: + HAS_CHANGED: ${{ needs.detect-none.outputs.has_changed }} + run: | + echo "detect-none has_changed=$HAS_CHANGED" + if [ "$HAS_CHANGED" != "false" ]; then + echo "::error::Expected detect-none has_changed=false, got '$HAS_CHANGED'" + exit 1 + fi diff --git a/.github/workflows/test-validate-renovate.yaml b/.github/workflows/test-validate-renovate.yaml new file mode 100644 index 0000000..bb02cbd --- /dev/null +++ b/.github/workflows/test-validate-renovate.yaml @@ -0,0 +1,21 @@ +name: Test validate-renovate + +on: + push: + branches: [main] + paths: + - '.github/workflows/validate-renovate.yaml' + - 'renovate.json' + pull_request: + paths: + - '.github/workflows/validate-renovate.yaml' + - 'renovate.json' + +permissions: {} + +jobs: + validate-renovate: + permissions: + contents: read + pull-requests: read + uses: ./.github/workflows/validate-renovate.yaml diff --git a/Makefile b/Makefile index 81bc093..17277a0 100644 --- a/Makefile +++ b/Makefile @@ -16,3 +16,6 @@ test-linear-pr-commenter: ## run linear-pr-commenter unit tests lint: ## run actionlint and zizmor on workflows actionlint .github/workflows/*.yaml zizmor .github/ + +# Reusable workflow tests (test-*.yaml for workflow_call workflows) run in CI only. +# They require GitHub event context and cannot be executed locally. diff --git a/README.md b/README.md index f57379b..b5b5617 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,24 @@ the action's files change: - `test-semver-validation.yaml` - triggers on `.github/actions/semver-validation/**` - `test-linear-pr-commenter.yaml` - triggers on `.github/actions/linear-pr-commenter/**` +Each reusable workflow (`workflow_call`) also has a smoke/integration test +workflow that triggers on PRs when the workflow file changes: + +- `test-validate-renovate.yaml` - calls `validate-renovate.yaml` with local ref. + **Note:** When triggered by workflow YAML changes alone, the inner `paths-filter` + won't match any renovate config files so `npx renovate-config-validator` never runs. + The validator only exercises its full path when `renovate.json` is also changed. +- `test-detect-changes.yaml` - calls `detect-changes.yaml` and asserts outputs (true/false) +- `test-actionlint-workflow.yaml` - calls `actionlint.yaml` with `github-pr-check` reporter (PR-only). + **Note:** `actionlint.yaml` skips fork PRs silently; the verify job emits a warning when this happens. +- `test-backport.yaml` - calls `backport.yaml` and asserts the result is `skipped` +- `test-clean-github-cache.yaml` - calls `clean-github-cache.yaml` (PR-only, since the + underlying workflow needs `github.event.pull_request.number`) +- `test-cleanup-backport-branches.yaml` - calls `cleanup-backport-branches.yaml` with `dry-run: true` + +Post-merge, `dispatch-integration-tests.yaml` triggers full E2E tests in +[vClusterLabs-Experiments/github-actions-test](https://github.com/vClusterLabs-Experiments/github-actions-test). + ### Writing tests for new actions 1. Node.js actions - add a `test/` directory with Jest tests. See