Skip to content

ci: run independent release steps in parallel#4042

Open
Piotr1215 wants to merge 1 commit into
mainfrom
devops-1029/parallel-release-steps
Open

ci: run independent release steps in parallel#4042
Piotr1215 wants to merge 1 commit into
mainfrom
devops-1029/parallel-release-steps

Conversation

@Piotr1215

@Piotr1215 Piotr1215 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

What issue type does this pull request address? (keep at least one, remove the others)
/kind enhancement

What does this pull request do? Which issues does it resolve? (use resolves #<issue_number> if possible)
References DEVOPS-1029 (Linear). This is the vcluster pilot of a three-repo effort (vcluster, vcluster-pro, loft-enterprise); the final PR in the chain carries the Closes.

Please provide a short message that should be published in the vcluster release notes
No release note. Internal CI/release-pipeline change only; no user-facing behavior changes.

What else do we need to know?

Summary

The release publish job runs every setup step (tool installs, QEMU, Buildx) and both post-build uploads in sequence, even though none of them depend on each other. On the large-8_32 runner that serial setup burns a couple of minutes before goreleaser can start. This groups the genuinely independent steps with the GitHub Actions parallel-steps feature (GA 2026-06-25) so they overlap, while every real ordering is preserved.

Key Changes

  • .github/workflows/release.yaml, publish job:
    • Block A (setup): the tag fetch and the tool installs (Go, Just, Cosign, Syft, QEMU, Buildx, Helm) now run inside a parallel: block. The block's implicit wait-all guarantees all tools are on PATH and tags are fetched before get_version and goreleaser consume them.
    • Block B (post-build): the two release/ uploads (upload-artifact and the release-asset attach) run inside a parallel: block. Both only read release/, so they are independent; the implicit wait-all still surfaces any upload failure (release-blocking, exactly as before).
    • Unchanged ordering: the goreleaser build (the serial spine), the two docker logins (kept serial to avoid a ~/.docker/config.json write race), the version/semver/homebrew-downgrade steps, and the best-effort vcluster-docs notify steps (still serial, still continue-on-error).
  • .github/actionlint.yaml: a scoped paths: ignore for .github/workflows/release.yaml. actionlint (v1.7.x) has no schema for the new keys yet and flags each parallel: step as missing a run/uses section; the ignore suppresses only that one message, only for that one file. Remove it once actionlint ships native support.

Validation

I verified the feature on a real large-8_32 runner with a throwaway probe before writing this change:

  • a parallel: block of uses: setup actions leaves every tool on PATH after the block (env propagation across concurrent uses: steps works);
  • a backgrounded uses: action plus an explicit wait also lands its tool on PATH;
  • there is an implicit "wait for all background steps" at job end, so a failing background step fails the job even if never waited on (only relevant here in that the post-build uploads stay release-blocking, which is the prior behavior).

actionlint .github/workflows/release.yaml is clean with the scoped ignore, and the workflow is valid YAML.

Known trade-off: actionlint cannot parse a parallel: block, so it skips validation of the steps inside the two blocks (the action-pinning check among them) until it ships support for the syntax. The steps moved are stable and already pinned; the ignore is intentionally narrow and time-boxed.

Dependencies

None. Independent of the vcluster-pro and loft-enterprise PRs in the same DEVOPS-1029 chain.

TODO

  • Reviewer sanity-check the parallel grouping (no hidden data dependency among the grouped steps).
  • Confirm identical artifacts/signatures/SBOMs and the wall-clock drop on the first real release (only verifiable on an actual release run; the goreleaser spine dominates, so the expected win is modest, roughly 2-3 min of setup overlap).
  • Drop the .github/actionlint.yaml ignore once actionlint recognizes background/parallel/wait.

E2E Tests

Additional test suites

none

Note

Low Risk
Internal release workflow timing only; release ordering for goreleaser, docker logins, and blocking uploads is preserved, with a temporary reduction in actionlint coverage inside the parallel blocks.

Overview
The release publish job now uses GitHub Actions parallel: blocks so work that does not depend on other steps in the same group can overlap on large-8_32 runners.

Setup (before get_version / goreleaser): tag fetch plus tool installs (Go, Just, Cosign, Syft, QEMU, Buildx, Helm) run concurrently inside one parallel: block, with the block’s implicit wait-all preserving the prior guarantee that tags and PATH are ready before version resolution and the build.

Post-goreleaser uploads: upload-artifact and the release-asset attach step run in a second parallel: block; both still only read release/ and failures remain release-blocking via wait-all.

Unchanged: checkout/disk cleanup, semver/homebrew checks, serial Docker Hub/ghcr logins, the goreleaser step, and best-effort vcluster-docs notifies.

.github/actionlint.yaml: adds a file-scoped ignore for actionlint’s false “missing run/uses” errors on parallel: in release.yaml until actionlint supports the syntax (DEVOPS-1029).

Reviewed by Cursor Bugbot for commit aee330b. Bugbot is set up for automated code reviews on this repo. Configure here.

@Piotr1215
Piotr1215 requested review from a team as code owners June 29, 2026 16:13
@Piotr1215
Piotr1215 requested a review from sydorovdmytro June 29, 2026 16:14
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown

E2E Ginkgo Tests

Status Commit Run
Passed 05bca5ebb0649a2babc3a705d3639ecf01344c1f View run #28882506277

The release publish job runs every setup step (tool installs, QEMU,
Buildx) and both post-build uploads in sequence, even though none of
them depend on each other. On the large-8_32 runner that serial setup
burns a couple of minutes before goreleaser can even start.

Group the independent steps with the GitHub Actions parallel-steps
feature (GA 2026-06-25): the tag fetch and tool installs run
concurrently and the block's implicit wait-all completes them before
get_version and goreleaser consume them; the two release/ uploads run
concurrently after the build. The goreleaser spine, the docker logins
(serialized to avoid a config.json write race), and the
version/homebrew-check steps keep their existing order.

actionlint (v1.7.x) has no schema for the new keys yet and reports the
parallel: steps as missing a run/uses section, so a scoped ignore for
the release workflow is added to .github/actionlint.yaml; remove it once
actionlint ships native support.

Verified on a real large-8_32 runner before making this change: a
parallel block of uses: setup actions leaves every tool on PATH after
the block. Identical artifacts and the wall-clock drop confirm on the
first real release.
@Piotr1215
Piotr1215 force-pushed the devops-1029/parallel-release-steps branch from aee330b to 05bca5e Compare July 7, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant