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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
name: COPR Rebuild
# Triggers a rebuild of the COPR package when a release is tagged, and pushes the COPR
# project page's description and instructions from packaging/copr/project-*.md.
#
# THE TRIGGER USED TO BE A PACKAGING COMMIT, AND THE REASON IS WORTH KEEPING.
#
# packaging/copr/retch.spec used to pin `Version:` to the last RELEASED tag, so it could
# only be bumped AFTER that tag existed:
# 1. push tag vX -> spec still said the PREVIOUS version
# 2. release workflow -> spec still said the PREVIOUS version
# 3. commit the packaging bump to main -> spec finally said vX
# A tag-triggered rebuild fired at step 1 and rebuilt the OLD version, so the only event
# that meant "there is something new" was the commit at step 3.
#
# Step 3 no longer exists. The spec is a template and `.copr/Makefile` renders its version
# from Cargo.toml when it builds the SRPM, so the tag IS the event: at the moment vX is
# pushed, main's Cargo.toml says X and its tree is what X names. Removing the post-tag
# commit is what removed the version bump a release used to force; see NOTES.md §5.
#
# The paths filter is gone with it. There is nothing to bump, so a push to main that touches
# packaging/copr no longer means a new release is ready -- it means someone edited the
# template, which the PR-triggered `copr` job in packaging.yml already verifies by building
# an SRPM. Rebuilding COPR for it would publish an UNRELEASED version, which is exactly what
# the guard below refuses.
on:
push:
tags:
workflow_dispatch:
permissions:
contents: read
jobs:
rebuild:
runs-on: ubuntu-latest
container: fedora:latest
steps:
# fetch-depth: 0 so a workflow_dispatch run can ask git for the last released tag.
# A tag-triggered run gets it from the ref and does not need the history, but the
# guard below must work identically either way -- a check that is skipped on one of
# its two entry points is not a check.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
- name: Install copr-cli
run: dnf -y install copr-cli git
# REFUSE TO REBUILD AN UNRELEASED VERSION.
#
# `.copr/Makefile` renders the spec's version from Cargo.toml, so a rebuild triggered
# while main is ahead of the last tag would publish a version that has no GitHub
# release and no crates.io upload -- and a published COPR NEVRA cannot be recalled.
# Asserting that Cargo.toml equals the tag being released is what makes the
# Cargo.toml-derived version safe.
- name: Refuse unless Cargo.toml matches the released tag
run: |
set -euo pipefail
git config --global --add safe.directory "$PWD"
V=$(python3 scripts/render_packaging.py --print-version)
if [ "$GITHUB_REF_TYPE" = "tag" ]; then
TAG="$GITHUB_REF_NAME"
else
TAG=$(git describe --tags --abbrev=0)
echo "manual run: comparing against the last tag, $TAG"
fi
echo "Cargo.toml: $V"
echo "tag: $TAG"
if [ "v$V" != "$TAG" ]; then
echo "::error::Cargo.toml is $V but the tag is $TAG — refusing to build a version that was not released"
exit 1
fi
echo "will build retch $V"
- name: Configure copr-cli
env:
COPR_LOGIN: ${{ secrets.COPR_LOGIN }}
COPR_USERNAME: ${{ secrets.COPR_USERNAME }}
COPR_TOKEN: ${{ secrets.COPR_TOKEN }}
run: |
set -euo pipefail
# Guard rather than fail: a fork has no secrets, and a red check there would be
# noise about a credential the fork is not supposed to have.
if [ -z "${COPR_LOGIN:-}" ] || [ -z "${COPR_TOKEN:-}" ] || [ -z "${COPR_USERNAME:-}" ]; then
echo "::notice::COPR credentials not configured; skipping the rebuild"
echo "skip=true" >> "$GITHUB_ENV"
exit 0
fi
mkdir -p ~/.config
# Written from env, never echoed. Actions masks the values in logs.
{
echo "[copr-cli]"
echo "login = $COPR_LOGIN"
echo "username = $COPR_USERNAME"
echo "token = $COPR_TOKEN"
echo "copr_url = https://copr.fedorainfracloud.org"
} > ~/.config/copr
chmod 600 ~/.config/copr
echo "skip=false" >> "$GITHUB_ENV"
# THE COPR PROJECT PAGE IS THE ONE PIECE OF COPR TEXT NO BUILD CARRIES.
#
# The spec's Summary/%description ship inside the RPM, but the description and install
# instructions shown on copr.fedorainfracloud.org are stored on the project itself, and
# nothing published them -- so the page drifted, quoting one machine's benchmark numbers
# from an old release. They are pushed from the committed files on every release, after
# the same guard `just check` runs, so text that fails it is never sent. Before the
# build rather than after it: the text is version-independent, and a failed build must
# not leave a stale page behind. `$(cat ...)` rather than inline text, because COPR
# renders Markdown and a paragraph indented 4 spaces becomes a code block.
- name: Sync the COPR project description and instructions
if: env.skip != 'true'
run: |
set -euo pipefail
python3 scripts/metadata_check.py
copr-cli modify \
--description "$(cat packaging/copr/project-description.md)" \
--instructions "$(cat packaging/copr/project-instructions.md)" \
kentobias/retch
echo "COPR project description and instructions synced from packaging/copr/project-*.md"
- name: Rebuild the COPR package
if: env.skip != 'true'
run: |
set -euo pipefail
if [ "$GITHUB_REF_TYPE" = "tag" ]; then
REF="$GITHUB_REF_NAME"
else
REF=$(git describe --tags --abbrev=0)
fi
# `buildscm --commit` rather than `build-package`, and the difference is a race
# that the previous trigger also had. `build-package` rebuilds from the package's
# stored SCM config, whose committish is `main` -- so a merge landing in the
# minute after a tag push would make COPR clone a tree that is AHEAD of the
# release and publish a version nobody released. Naming the tag removes the window
# entirely: COPR builds exactly what vX points at.
#
# --method make_srpm matches the stored config (.copr/Makefile generates the
# SRPM); no --subdir, because COPR runs the Makefile from the repository root.
# --enable-net on is stated rather than inherited: the build resolves crates.io,
# and a silently net-less buildroot fails deep inside cargo.
#
# If this ever misbehaves, the fallback is the previous call, which is still
# configured and needs no arguments:
# copr-cli build-package --name retch kentobias/retch
copr-cli buildscm \
--clone-url https://github.com/l1a/retch.git \
--commit "$REF" \
--method make_srpm \
--enable-net on \
kentobias/retch