1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
name: Release-plz
# Publishes pending releases, then opens or updates the next release PR.
#
# Under the open-source release process (see docs/release-process.md),
# releases are published ONLY from release-line branches -- never from
# `main` (which is nightly-like and intentionally unpublished) and never
# from a release-candidate branch (which bakes before promotion). On each
# release-line push, this workflow publishes any merged release PR and then
# opens/updates the next release PR. The jobs are ordered so release-pr sees
# tags created by release-plz in the publish job.
#
# release-plz creates the `v*` tag here; that tag then drives the binary
# build in c2patool-release.yml. This workflow does not build binaries
# itself -- keeping binary builds tag-driven means release-candidate builds
# (which never reach this workflow) produce the same binaries via
# release-rc.yml's tags.
permissions:
pull-requests: write
contents: write
on:
push:
branches:
- stable # currently-active release line
- 'v0.*' # long-lived per-line branches (backports to retired lines)
jobs:
# Refuse to publish if a [patch]/git dependency is present. main's own
# `c2pa` dependency is a git dependency by design (see docs/release-
# process.md, "Tracking c2pa-rs main") -- that must never reach stable.
guard-no-patch-deps:
name: Guard against patch/git dependencies
uses: ./.github/workflows/check-no-patch-deps.yml
release-plz:
name: Release-plz
runs-on: ubuntu-latest
needs: guard-no-patch-deps
# Defense in depth: release-candidate branches must never publish, even if
# one were ever added to the triggers above. RC branches are named
# `<version>-rc` (no numeric suffix), so match on `-rc` rather than `-rc.`.
if: ${{ !contains(github.ref_name, '-rc') }}
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
token: ${{ secrets.RELEASE_PLZ_ORG_TOKEN }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # master@2026-06-30
with:
toolchain: stable
- name: Run release-plz (publish)
id: release-plz
uses: MarcoIeni/release-plz-action@064f4d1e36c843611ddf013be726beaa4ad804db # v0.5.129
with:
command: release
verbose: true
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_ORG_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_ORG_TOKEN }}
- name: Debug release-plz outputs
env:
RELEASES: ${{ steps.release-plz.outputs.releases }}
run: |
echo "=== Release-plz releases ==="
echo "$RELEASES"
echo "==========================="
release-pr:
name: Release PR
runs-on: ubuntu-latest
needs: release-plz
steps:
# Checkout after publishing so release-plz sees tags created by the
# preceding job when it calculates the next version.
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
token: ${{ secrets.RELEASE_PLZ_ORG_TOKEN }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # master@2026-06-30
with:
toolchain: stable
- name: Run release-plz (release-pr)
uses: MarcoIeni/release-plz-action@064f4d1e36c843611ddf013be726beaa4ad804db # v0.5.129
with:
command: release-pr
verbose: true
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_ORG_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_ORG_TOKEN }}
# A release-plz branch can be reused or left behind when it opens a new
# release PR. Only prune closed release PRs for this branch: release
# branch names are shared across release lines.
- name: Clean up closed release-plz branches for this release line
env:
GH_TOKEN: ${{ secrets.RELEASE_PLZ_ORG_TOKEN }}
run: |
set -euo pipefail
gh pr list --state closed --base "$GITHUB_REF_NAME" --limit 1000 \
--json headRefName \
--jq '.[] | select(.headRefName | startswith("release-plz-")) | .headRefName' |
while IFS= read -r branch; do
[ -n "$branch" ] || continue
if git ls-remote --exit-code --heads origin "refs/heads/$branch" >/dev/null; then
git push origin --delete "$branch"
fi
done