diff --git a/.github/workflows/e2e-ginkgo.yaml b/.github/workflows/e2e-ginkgo.yaml index d24cb1807b..bc2710c94d 100644 --- a/.github/workflows/e2e-ginkgo.yaml +++ b/.github/workflows/e2e-ginkgo.yaml @@ -5,8 +5,6 @@ permissions: pull-requests: write on: - release: - types: [created] workflow_dispatch: inputs: ginkgo-label: @@ -44,7 +42,9 @@ env: jobs: parse_label-filter: name: Parse label filter and check if tests should run - if: github.repository_owner == 'loft-sh' # do not run on forks + # do not run on forks + if: >- + !cancelled() && github.repository_owner == 'loft-sh' runs-on: ubuntu-22.04 outputs: @@ -63,11 +63,19 @@ jobs: with: pr-body: ${{ github.event.pull_request.body }} previous-pr-body: ${{ github.event.changes.body.from }} - event-name: ${{ github.event_name }} + # A release-validation dispatch runs at refs/tags/; treat it + # like the old release:created path so the label filter resolves + # identically. A manual branch dispatch uses the ginkgo-label input; + # a PR uses pull_request. + event-name: ${{ startsWith(github.ref, 'refs/tags/') && 'release' || github.event_name }} event-action: ${{ github.event.action }} label-filter-input: ${{ inputs.ginkgo-label }} detect_changes: + # PR-only: the release path is a workflow_dispatch --ref dispatch that + # always validates and bypasses change detection; entry jobs break + # skip-propagation with !cancelled(). + if: github.event_name == 'pull_request' needs: [parse_label-filter] uses: loft-sh/github-actions/.github/workflows/detect-changes.yaml@detect-changes/v1 with: @@ -86,8 +94,13 @@ jobs: build: runs-on: ubuntu-latest - if: github.repository_owner == 'loft-sh' && needs.detect_changes.outputs.has_changed == 'true' - needs: detect_changes + if: >- + !cancelled() && github.repository_owner == 'loft-sh' && + ( + (github.event_name == 'pull_request' && needs.detect_changes.outputs.has_changed == 'true') || + github.event_name == 'workflow_dispatch' + ) + needs: [detect_changes] steps: - name: Checkout repository uses: actions/checkout@v5 @@ -133,8 +146,13 @@ jobs: download-latest-cli: - needs: detect_changes - if: needs.detect_changes.outputs.has_changed == 'true' + needs: [detect_changes] + if: >- + !cancelled() && + ( + (github.event_name == 'pull_request' && needs.detect_changes.outputs.has_changed == 'true') || + github.event_name == 'workflow_dispatch' + ) name: Download the latest vCluster cli runs-on: ubuntu-latest steps: @@ -154,9 +172,13 @@ jobs: - build - parse_label-filter - detect_changes - if: > + if: >- + !cancelled() && needs.build.result == 'success' && needs.parse_label-filter.outputs.skip-edited != 'true' && - needs.detect_changes.outputs.has_changed == 'true' + ( + (github.event_name == 'pull_request' && needs.detect_changes.outputs.has_changed == 'true') || + github.event_name == 'workflow_dispatch' + ) runs-on: large-8_32 permissions: id-token: write # needed for OIDC → AWS diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 74cf5242fe..69f905c58d 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -1,8 +1,6 @@ name: E2E CI on: - release: - types: [created] pull_request: branches: - main @@ -22,6 +20,10 @@ env: jobs: detect_changes: + # PR-only: the release path is a workflow_dispatch --ref dispatch that + # always validates, so it bypasses change detection. Entry jobs break the + # skip-propagation with !cancelled(). + if: github.event_name == 'pull_request' uses: loft-sh/github-actions/.github/workflows/detect-changes.yaml@detect-changes/v1 with: paths: | @@ -38,8 +40,13 @@ jobs: - "manifests/**" build: runs-on: ubuntu-latest - if: github.repository_owner == 'loft-sh' && needs.detect_changes.outputs.has_changed == 'true' - needs: detect_changes + if: >- + !cancelled() && github.repository_owner == 'loft-sh' && + ( + (github.event_name == 'pull_request' && needs.detect_changes.outputs.has_changed == 'true') || + github.event_name == 'workflow_dispatch' + ) + needs: [detect_changes] steps: - name: Checkout repository uses: actions/checkout@v6 @@ -84,8 +91,13 @@ jobs: retention-days: 7 get-testsuites-dir: - needs: detect_changes - if: needs.detect_changes.outputs.has_changed == 'true' + needs: [detect_changes] + if: >- + !cancelled() && + ( + (github.event_name == 'pull_request' && needs.detect_changes.outputs.has_changed == 'true') || + github.event_name == 'workflow_dispatch' + ) runs-on: ubuntu-latest steps: - name: Checkout repository @@ -112,7 +124,12 @@ jobs: needs: - build - detect_changes - if: needs.detect_changes.outputs.has_changed == 'true' + if: >- + !cancelled() && needs.build.result == 'success' && + ( + (github.event_name == 'pull_request' && needs.detect_changes.outputs.has_changed == 'true') || + github.event_name == 'workflow_dispatch' + ) runs-on: ubuntu-latest steps: - name: Checkout repository @@ -168,8 +185,13 @@ jobs: ./hack/vcluster-install-scripts/test-helm-install.sh download-latest-cli: - needs: detect_changes - if: needs.detect_changes.outputs.has_changed == 'true' + needs: [detect_changes] + if: >- + !cancelled() && + ( + (github.event_name == 'pull_request' && needs.detect_changes.outputs.has_changed == 'true') || + github.event_name == 'workflow_dispatch' + ) name: Download the latest vCluster cli runs-on: ubuntu-latest steps: @@ -189,7 +211,12 @@ jobs: - build - download-latest-cli - detect_changes - if: needs.detect_changes.outputs.has_changed == 'true' + if: >- + !cancelled() && needs.build.result == 'success' && needs.download-latest-cli.result == 'success' && + ( + (github.event_name == 'pull_request' && needs.detect_changes.outputs.has_changed == 'true') || + github.event_name == 'workflow_dispatch' + ) runs-on: ubuntu-latest strategy: fail-fast: false diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e10fdc692e..97e8ab0fb6 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,8 +1,14 @@ name: Release +# Builder for the vCluster release pipeline (DEVOPS-1050). The GitHub Release is +# a pipeline OUTPUT, not a trigger: goreleaser creates it at the end of a green +# build. This workflow is dispatched by the loft-sh/github-actions +# vcluster-release action via `gh workflow run release.yaml --ref `, so +# github.ref is refs/tags/ and github.ref_name is the version. It no +# longer triggers on release:created, so a monorepo-created OSS release can never +# re-trigger this builder. on: - release: - types: [created] + workflow_dispatch: jobs: check_minimum_version_tag: @@ -10,11 +16,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - if: ${{ !contains(github.event.release.tag_name, '-') }} + if: ${{ !contains(github.ref_name, '-') }} with: - ref: ${{ github.event.release.tag_name }} + ref: ${{ github.ref_name }} - name: Validate MinimumVersionTag is stable - if: ${{ !contains(github.event.release.tag_name, '-') }} + if: ${{ !contains(github.ref_name, '-') }} run: | MINIMUM_VERSION_TAG=$(grep -oP 'MinimumVersionTag\s*=\s*"\Kv[^"]+' pkg/platform/version.go) if [[ ! "$MINIMUM_VERSION_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then @@ -72,7 +78,10 @@ jobs: run: | RELEASE_VERSION=$(echo "$GITHUB_REF" | sed -nE 's!refs/tags/!!p') echo "release_version=$RELEASE_VERSION" >> "$GITHUB_OUTPUT" - echo "previous_tag=$(git describe --abbrev=0 --tags "$(git rev-list --tags --skip=1 --max-count=1)")" >> "$GITHUB_OUTPUT" + # Branch-local previous tag: the tag reachable from this commit's + # parent on THIS branch, not the global latest tag (which would be + # wrong on a release branch). See DEVOPS-1050. + echo "previous_tag=$(git describe --tags --abbrev=0 --match 'v*' "${GITHUB_SHA}^" 2>/dev/null || true)" >> "$GITHUB_OUTPUT" - name: Validate semver id: semver uses: loft-sh/github-actions/.github/actions/semver-validation@semver-validation/v1 @@ -228,6 +237,30 @@ jobs: github-token: ${{ secrets.GH_ACCESS_TOKEN }} linear-token: ${{ secrets.LINEAR_TOKEN }} + trigger-validators: + needs: [publish] + if: ${{ success() && github.repository_owner == 'loft-sh' && !contains(needs.publish.outputs.release_version, '-next') }} + runs-on: ubuntu-latest + permissions: + actions: write + contents: read + steps: + - name: Dispatch release validators at the built tag + env: + GH_TOKEN: ${{ github.token }} + VERSION: ${{ needs.publish.outputs.release_version }} + run: | + # Run each validator's OWN version at the built tag (per-line consistent). + # Each validator exists on the default branch (dispatchable) and carries a + # workflow_dispatch trigger in the tag's tree (true for lines cut from main). + for wf in e2e.yaml e2e-ginkgo.yaml unit-tests.yaml; do + if gh workflow run "$wf" --repo "$GITHUB_REPOSITORY" --ref "$VERSION"; then + echo "dispatched $wf @ $VERSION" + else + echo "::warning::could not dispatch $wf @ $VERSION (missing or no workflow_dispatch at tag)" + fi + done + notify_failure: if: ${{ always() && contains(needs.*.result, 'failure') && github.repository_owner == 'loft-sh' }} needs: @@ -239,7 +272,7 @@ jobs: contents: read uses: loft-sh/github-actions/.github/workflows/notify-release.yaml@release-notification/v2 with: - release_version: ${{ github.event.release.tag_name }} + release_version: ${{ github.ref_name }} target_repo: ${{ github.repository }} product: vCluster status: failure diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index 81581679ba..0b4b77681f 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -1,8 +1,7 @@ name: Unit tests on: - release: - types: [created] + workflow_dispatch: pull_request: branches: - main @@ -23,7 +22,8 @@ concurrency: jobs: helm-unit-tests: name: Execute all helm tests - if: github.repository_owner == 'loft-sh' # do not run on forks + # do not run on forks + if: github.repository_owner == 'loft-sh' runs-on: ubuntu-latest steps: - name: Checkout @@ -37,7 +37,8 @@ jobs: go-unit-test: name: Execute all go tests - if: github.repository_owner == 'loft-sh' # do not run on forks + # do not run on forks + if: github.repository_owner == 'loft-sh' runs-on: ubuntu-22.04 steps: - name: Check out code into the Go module directory