Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 43 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
name: Release

on:
# Both ways of cutting a release are supported, and both end with the Homebrew
# tap bumped automatically:
#
# prereleased - the release is published as a pre-release. `build` uploads
# every asset, `publish-release` then flips the release to official, and
# `update-homebrew` bumps the tap.
# released - the release is published directly as official (or an existing
# pre-release is flipped by hand). `publish-release` is skipped because
# there is nothing to convert, so `update-homebrew` keys off `build`.
#
# Before `released` was listed here, a release published directly as official
# started no run at all: no binaries, no assets, no formula bump. Listing it
# cannot loop back on us either, because `publish-release` performs its flip
# with the default GITHUB_TOKEN and events raised by GITHUB_TOKEN do not start
# new workflow runs.
release:
types: [prereleased]
types: [prereleased, released]
workflow_dispatch:
inputs:
update_homebrew:
Expand Down Expand Up @@ -263,14 +278,38 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# ============================================================================
# Update Homebrew formula (after publish converts pre-release to official)
# Update Homebrew formula (after every release asset has been uploaded)
# ============================================================================
#
# `build` is listed in `needs` explicitly rather than relied on transitively
# through `publish-release`. The called workflow downloads the published
# assets and hashes them, so it must never start before all five build legs
# have finished uploading, and that guarantee has to hold on the path where
# `publish-release` does not run at all. `publish-release` stays in `needs` so
# the pre-release path is still ordered behind the flip to official.
#
# `!cancelled()` is required: `publish-release` is legitimately skipped when
# the release was published as official already, and under the implicit
# `success()` a job whose dependency was skipped is skipped too. A bare
# `always()` would be the wrong way to lift that, since it would also fire
# after a failed build and push a formula whose sha256 values point at assets
# that were never uploaded, so the build result is asserted explicitly instead
# of leaning on job ordering.
#
# On a manual `workflow_dispatch` of this workflow the formula is updated only
# when the `update_homebrew` input asks for it, so rebuilding a tag by hand
# does not push a tap commit as a side effect.
update-homebrew:
name: Update Homebrew formula
needs: [publish-release]
needs: [build, publish-release]
if: >-
!cancelled()
&& needs.build.result == 'success'
&& (needs.publish-release.result == 'success' || needs.publish-release.result == 'skipped')
&& (github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.update_homebrew == 'true'))
uses: ./.github/workflows/update_homebrew_formula.yml
with:
release_tag: ${{ github.event.release.tag_name }}
release_tag: ${{ github.event.release.tag_name || github.event.inputs.release_tag }}
secrets: inherit

# ============================================================================
Expand Down
15 changes: 14 additions & 1 deletion .github/workflows/update_homebrew_formula.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,20 @@ jobs:
runs-on: macos-latest
environment: packaging

if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
# No job-level `if` here, on purpose. This job used to carry
#
# if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
#
# which is unsatisfiable on the `uses:` path. Inside a called workflow
# `github.event_name` reports the *caller's* originating event, which is
# `release` during a release run, and never `workflow_call`. So the job was
# skipped in 0s on every release (v2.4.1 job 91700817094, v2.4.2 job
# 94746343757) and the tap had to be bumped afterwards by hand.
#
# The `on:` block above already declares the only two ways this workflow can
# start, so an event gate here can only exclude legitimate runs. Whether the
# formula should be updated at all is the caller's decision; see the
# `update-homebrew` job in release.yml.

steps:
- name: Checkout this repository
Expand Down