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
4 changes: 4 additions & 0 deletions .github/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ formula *args:
install-formula *args:
python3 sh/gh/install-formula.py "$@"

# Open the pull request that merges `release` back into `main`, queued to land as a merge commit.
back-merge:
sh/gh/back-merge.sh

# Trigger the apt-repo and rpm-repo workflows for a release tag.
[positional-arguments]
trigger-repo-publish *args:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/alert.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ on:
#
# Swift, OBS, and Platform are here despite also running on pull requests:
# Swift warms its own Rust cache on `main`, and OBS and Platform build every
# merge to `main` and `dev`. Those push runs are nobody's check, so a break in them
# merge to `main` and `release`. Those push runs are nobody's check, so a break in them
# would otherwise go unseen. The cost is a skipped Alert run per pull
# request.
workflows:
- apt-repo
- Back-merge
- Cache
- Cachix
- Docker
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/back-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Back-merge

# Every push to `release` (a cut, a backport, or release-plz's version bump)
# merges `release` back into `main`, so trunk carries the published versions
# and CHANGELOGs and the next cut starts from an advanced merge base.
#
# It lands through a pull request as a merge commit, never a squash: a squash
# leaves the merge base at the last cut, so a second publish before the next
# cut would conflict.

on:
push:
branches: [release]
# Re-running by hand, e.g. after resolving a conflict that failed a run.
workflow_dispatch:

permissions:
contents: read

concurrency:
group: back-merge
cancel-in-progress: false

jobs:
back-merge:
name: Back-merge
runs-on: ubuntu-latest
if: github.repository_owner == 'moq-dev'

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: ./.github/actions/just

# The app token, not GITHUB_TOKEN: a pull request GITHUB_TOKEN opens
# triggers no workflows, so Check and Test would never report.
- name: Generate moq-bot token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
id: token
with:
client-id: ${{ secrets.APP_CLIENT_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write

- name: Merge release into main
env:
GH_TOKEN: ${{ steps.token.outputs.token }}
run: just gh back-merge
4 changes: 2 additions & 2 deletions .github/workflows/obs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ name: OBS
# .cargo/config.toml could do it too -- and `rs/**` would run this on nearly
# every PR, which is the cost that removed the Windows and macOS gates (#2600).
# So this filter covers the likely inputs at PR time, and pushes to `main` and
# `dev` rebuild on any Rust or plugin change to cover the rest. nightly.yml also
# `release` rebuild on any Rust or plugin change to cover the rest. nightly.yml also
# runs the Linux recipe diff-independently.

permissions:
contents: read

on:
push:
branches: [main, dev]
branches: [main, release]
paths:
- "rs/**"
- "cpp/obs/**"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/platform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ name: Platform
#
# A pull request compiles only the crates it changed plus their dependents,
# the same selection the Linux `check` job makes, because these are the
# slowest and scarcest runners in CI. Pushes to `main` and `dev` compile
# slowest and scarcest runners in CI. Pushes to `main` and `release` compile
# everything, catching the break two individually green PRs make once both
# land. `dev` never ran the nightly at all.
# land.
#
# Outside Nix, like android.yml: neither runner has it, so each installs the
# runner-native toolchain. rust-toolchain.toml still pins the compiler, and the
Expand All @@ -26,7 +26,7 @@ permissions:

on:
push:
branches: [main, dev]
branches: [main, release]
paths:
- "rs/**"
- ".cargo/**"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/quest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Quest

# Validates the quest tree on every branch that carries one. check.yml already
# runs `quest check` on a pull request into any branch, but a direct push (a
# merge to `main` or `dev`, or `main` merged into a questline) is nobody's pull
# merge to `main` or `release`, or `main` merged into a questline) is nobody's pull
# request, so a broken tree could land there unseen.
#
# Push only: a pull request is check.yml's job, and a pull_request trigger here
Expand All @@ -18,7 +18,7 @@ on:
push:
branches:
- main
- dev
- release
- "quest/**"
paths:
- "quest/**"
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release-brew.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# workflow_run runs the default branch's file, whose checkout would
# otherwise take trunk rather than the tag that was released.
ref: ${{ github.event.workflow_run.head_sha }}
persist-credentials: false

- uses: ./.github/actions/just
Expand Down
12 changes: 7 additions & 5 deletions .github/workflows/release-go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ name: Release Go
# (registry is the gate, like release-plz / the PyPI check in release.sh).
#
# Triggers:
# * push to main — a wrapper API or VERSION change. The ffi require is
# * push to release — a wrapper API or VERSION change. The ffi require is
# pinned to the current crate version, whose mirror tag
# already exists in steady state. If it's missing (a
# release is mid-flight) or rs/moq-ffi changed since
Expand All @@ -20,13 +20,13 @@ name: Release Go
# Chaining off the upstream run guarantees the mirror
# tag is already present, so there is nothing to poll.
#
# Stray main pushes are harmless: publish-wrapper.sh skips when the staged tree
# Stray release pushes are harmless: publish-wrapper.sh skips when the staged tree
# matches the mirror, so unchanged content never mints an empty patch release.

on:
push:
branches:
- main
- release
workflow_run:
workflows: ["Release Go FFI"]
types:
Expand Down Expand Up @@ -62,6 +62,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
# Tags, for the unreleased ffi check.
fetch-depth: 0
persist-credentials: false
Expand All @@ -84,7 +85,7 @@ jobs:
echo "wrapper line: $LINE"

# The ffi version the wrapper should require: the version of the ffi that
# just published (workflow_run), or the current crate version (main push).
# just published (workflow_run), or the current crate version (release push).
- name: Resolve ffi version
id: ffi
env:
Expand All @@ -100,7 +101,7 @@ jobs:
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

# On a main push the wrapper pins the current crate's ffi version, but it
# On a release push the wrapper pins the current crate's ffi version, but it
# may call API added to rs/moq-ffi since that version was tagged.
- name: Check for unreleased ffi changes (push only)
id: ffi-diff
Expand Down Expand Up @@ -180,6 +181,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
persist-credentials: false

- uses: ./.github/actions/just
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ permissions:

on:
push:
branches: [main]
branches: [release]
paths:
- 'js/**'
- '.github/workflows/release-js.yml'
# Dry-run: builds, packs, and runs `deno publish --dry-run`, which catches
# JSR-only failures before they break a release on main.
# JSR-only failures before they break a release on `release`.
pull_request:
paths:
- 'js/**'
Expand Down
11 changes: 7 additions & 4 deletions .github/workflows/release-kt-lib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ name: Release Kotlin lib
on:
push:
branches:
- main
- dev
- release
paths:
- "kt/moq/**"
- "kt/gradle.properties"
Expand All @@ -41,7 +40,8 @@ on:
- "sh/gh/release.sh"
- "rs/moq-ffi/build.sh"
# Manual trigger so a wrapper bump can be published once the bindings it
# depends on land on Maven Central (the guard below skips otherwise).
# depends on land on Maven Central (the guard below skips otherwise). Only a
# dispatch on `release` publishes.
workflow_dispatch:
workflow_run:
workflows: ["Release Kotlin FFI"]
Expand Down Expand Up @@ -144,7 +144,10 @@ jobs:
name: Publish wrapper
needs: [check-version]
# PRs always run (dry-run). Pushes publish only when the version is new.
if: github.event_name == 'pull_request' || needs.check-version.outputs.should_publish == 'true'
if: >-
github.event_name == 'pull_request' ||
(needs.check-version.outputs.should_publish == 'true' &&
(github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/release'))
# Only publishing runs share the serialized group. GitHub keeps a single
# pending run per group and drops the older one, so a PR or a no-op push
# sharing it silently cancelled a queued release. Scoped to this job so runs
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-py.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: Release Py
# depends on are built separately (release-py-ffi.yml).
#
# Versioned independently of the moq-ffi crate: bump `version` in
# py/moq-rs/pyproject.toml by hand in a normal PR. On merge to main this reads
# py/moq-rs/pyproject.toml by hand in a normal PR. On merge to `release` this reads
# that version and publishes only if it isn't already on PyPI. That registry
# check is the release gate (the same model release-plz uses for crates), so
# there's no separate tag to remember. When wrapper and FFI changes land
Expand All @@ -15,7 +15,7 @@ name: Release Py
on:
push:
branches:
- main
- release
paths:
- "py/moq-rs/**"
- ".github/workflows/release-py.yml"
Expand Down
11 changes: 7 additions & 4 deletions .github/workflows/release-rs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ concurrency:
on:
push:
branches:
- main
- release
# A run costs the better part of an hour and they serialize on the
# concurrency group above, so a push that can't change a crate's version
# or its API shouldn't queue one.
Expand All @@ -26,15 +26,16 @@ on:
- "flake.lock"
- ".release-plz.toml"
- ".github/workflows/release-rs.yml"
# Releasing by hand, e.g. after a skipped push or a cold cache.
# Releasing by hand, e.g. after a skipped push or a cold cache. Dispatch it
# on `release`; the job refuses any other ref.
workflow_dispatch:

jobs:
release:
name: Plz

runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'moq-dev' }}
if: ${{ github.repository_owner == 'moq-dev' && github.ref == 'refs/heads/release' }}

env:
# release-plz copies each crate into its own temp directory to compare it
Expand Down Expand Up @@ -83,7 +84,9 @@ jobs:
# Its own scope rather than the shared store cache.yml warms: this holds
# cargo-semver-checks rustdoc, not check and test artifacts, and mixing
# the two would have each restoring a target tree built for the other.
# This workflow only runs on `main`, so it is the sole writer of its scope.
# This workflow only runs on `release`, so it is the sole writer of its scope.
# The cache action saves push runs only on the default branch, so pushes
# here restore without saving; a dispatch on `release` refreshes it.
#
# The action's shim is what gets mbx in here at all. release-plz spawns
# Cargo and cargo-semver-checks itself, so no environment variable reaches
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/release-swift-lib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: Release Swift Lib
# on are built separately (release-swift-ffi.yml).
#
# Versioned independently of the moq-ffi crate: bump `swift/VERSION` by hand in a
# normal PR. On merge to main/dev this reads that version and publishes only if
# normal PR. On merge to `release` this reads that version and publishes only if
# it isn't already tagged on the mirror. That tag check is the release gate (the
# same model release-plz uses for crates), so there's no separate tag to
# remember. When wrapper and FFI changes land together, publication waits for
Expand All @@ -15,8 +15,7 @@ name: Release Swift Lib
on:
push:
branches:
- main
- dev
- release
paths:
- "swift/VERSION"
- "swift/Package.swift.template"
Expand Down Expand Up @@ -46,8 +45,8 @@ on:
permissions:
contents: read

# Separate PR builds from mainline publishes so a PR run can't queue ahead of
# (and delay) a release on main.
# Separate PR builds from publishes so a PR run can't queue ahead of (and
# delay) a release.
concurrency:
group: release-swift-lib-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || 'publish' }}
cancel-in-progress: false
Expand All @@ -68,7 +67,7 @@ jobs:
version: ${{ steps.version.outputs.version }}
ffi_version: ${{ steps.version.outputs.ffi_version }}
ffi_unreleased: ${{ steps.ffi-diff.outputs.unreleased }}
# On PRs we only build (dry-run). On main/dev we publish when the version
# On PRs we only build (dry-run). On `release` we publish when the version
# isn't already tagged on the mirror.
publish: ${{ (github.event_name == 'push' || github.event_name == 'workflow_run') && steps.ffi-diff.outputs.unreleased != 'true' && steps.ffi-gate.outputs.exists == 'true' && steps.gate.outputs.exists == 'false' }}

Expand Down Expand Up @@ -149,6 +148,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
persist-credentials: false

- uses: ./.github/actions/just
Expand Down Expand Up @@ -196,6 +196,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
persist-credentials: false

- uses: ./.github/actions/just
Expand Down
Loading
Loading