-
-
Notifications
You must be signed in to change notification settings - Fork 139
Expand file tree
/
Copy pathtag-release.sh
More file actions
executable file
·271 lines (222 loc) · 9.38 KB
/
Copy pathtag-release.sh
File metadata and controls
executable file
·271 lines (222 loc) · 9.38 KB
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#!/bin/bash
# tag-release.sh - Create signed CachyOS kernel tags in cachyos/linux
# Usage: ./tag-release.sh <kernel-version> [pkgrel]
# Example: ./tag-release.sh 6.19.3 1
set -euo pipefail
usage() {
cat <<EOF
Usage: $(basename "$0") <kernel-version> [pkgrel]
Create a signed CachyOS release tag on the current branch.
Tags the HEAD commit of whatever branch is currently checked out.
Tag scheme: cachyos-<version>-<pkgrel>
Kernel variant Tag example
─────────────────────────────────────────────
Stable initial cachyos-6.19.0-1
Stable point release cachyos-6.19.3-1
Stable re-spin cachyos-6.19.3-2
LTS cachyos-6.18.9-1
RC cachyos-6.19-rc8-1
Arguments:
kernel-version Kernel version (required)
Accepts X.Y.Z (e.g. 6.19.3) or X.Y-rcN (e.g. 6.19-rc8)
pkgrel Package release number (default: 1)
Examples:
$(basename "$0") 6.19.3
$(basename "$0") 6.19.3 2
$(basename "$0") 6.19-rc8
Notes:
- Requires a GPG signing key configured via 'git config user.signingkey'
or signing enabled globally with 'git config tag.gpgSign true'
- The release tarball is signed with the same GPG key (produces .tar.gz.asc)
- Run this script from a checkout of github.com/CachyOS/linux
- Topic branches must be merged (not squashed) into the release branch.
The changelog is built from first-parent merge commits on top of the
upstream base commit ("Linux X.Y.Z").
EOF
}
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
usage
exit 0
fi
VERSION="${1:-}"
PKGREL="${2:-1}"
if [[ -z "$VERSION" ]]; then
usage
exit 1
fi
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
echo "Error: not inside a git repository"
exit 1
fi
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+|-rc[0-9]+)$ ]]; then
echo "Error: version must be X.Y.Z or X.Y-rcN (got: $VERSION)"
exit 1
fi
if ! [[ "$PKGREL" =~ ^[0-9]+$ ]]; then
echo "Error: pkgrel must be a positive integer (got: $PKGREL)"
exit 1
fi
TAG="cachyos-${VERSION}-${PKGREL}"
# Extract major.minor ("6.19" from "6.19.3" or "6.19-rc8")
[[ "$VERSION" =~ ^([0-9]+\.[0-9]+) ]]
MAJOR_MINOR="${BASH_REMATCH[1]}"
if git tag -l "$TAG" | grep -q .; then
echo "Error: tag '$TAG' already exists"
exit 1
fi
# ---------------------------------------------------------------------------
# Changelog helpers
# ---------------------------------------------------------------------------
# Hash of the "Linux X.Y.Z" commit reachable from <ref>.
# Upstream tags the first release of a series as "Linux X.Y" (no ".0"),
# so fall back to the stripped form when "Linux X.Y.0" isn't found.
find_upstream_commit() {
local version="$1" ref="$2" hash
hash=$(git log --format="%H %s" "$ref" 2>/dev/null \
| awk -v tgt="Linux $version" '$0 ~ "^[0-9a-f]+ "tgt"$" {print $1; exit}')
if [[ -z "$hash" && "$version" == *.0 ]]; then
hash=$(git log --format="%H %s" "$ref" 2>/dev/null \
| awk -v tgt="Linux ${version%.0}" '$0 ~ "^[0-9a-f]+ "tgt"$" {print $1; exit}')
fi
printf '%s' "$hash"
}
# Most recent cachyos-<major.minor>-* tag. Works across stable rebases
# because it sorts by version name, not by ancestry.
find_prev_tag() {
local major_minor="$1"
git tag -l "cachyos-${major_minor}*" --sort=-v:refname 2>/dev/null | head -n1
}
# Extract the kernel version out of a "cachyos-<ver>-<pkgrel>" tag.
tag_to_version() {
sed -E 's/^cachyos-(.+)-[0-9]+$/\1/' <<< "$1"
}
# Enumerate first-parent merge commits of topic branches on top of <upstream>
# reachable from <ref>. Emits "<merge-hash>\t<branch-name>" per line.
list_branch_merges() {
local upstream="$1" ref="$2"
[[ -z "$upstream" ]] && return 0
git log --first-parent --merges --format="%H%x09%s" \
"${upstream}..${ref}" 2>/dev/null \
| sed -n "s/^\\([0-9a-f]\\+\\)\\t[Mm]erge branch '\\([^']\\+\\)'.*/\\1\\t\\2/p"
}
# Commits introduced by a merge (branch side), oldest first: "<short-hash> <subject>".
merge_side_commits() {
git log --format="%h %s" --no-merges --reverse "${1}^1..${1}^2" 2>/dev/null
}
# Snapshot of branch composition at <ref>: "<branch>\t<subject>" lines.
# Used to diff two releases without relying on hashes (survives rebases).
snapshot_branches() {
local upstream="$1" ref="$2"
list_branch_merges "$upstream" "$ref" | while IFS=$'\t' read -r mhash branch; do
merge_side_commits "$mhash" | while read -r _ subject; do
printf '%s\t%s\n' "$branch" "$subject"
done
done
}
generate_changelog() {
local version="$1" pkgrel="$2" major_minor="$3" prev_tag="$4"
local upstream_hash
upstream_hash=$(find_upstream_commit "$version" "HEAD")
echo "## CachyOS Linux ${version}-${pkgrel}"
echo ""
echo "Based on Linux ${version}"
[[ -n "$prev_tag" ]] && echo "Previous release: \`${prev_tag}\`"
echo ""
# --- Diff vs. previous release -----------------------------------------
if [[ -n "$prev_tag" ]]; then
local prev_version prev_upstream prev_snap cur_snap
prev_version=$(tag_to_version "$prev_tag")
prev_upstream=$(find_upstream_commit "$prev_version" "$prev_tag")
prev_snap=$(snapshot_branches "$prev_upstream" "$prev_tag")
cur_snap=$(snapshot_branches "$upstream_hash" "HEAD")
local prev_branches cur_branches
prev_branches=$(cut -f1 <<< "$prev_snap" | sort -u | sed '/^$/d')
cur_branches=$(cut -f1 <<< "$cur_snap" | sort -u | sed '/^$/d')
echo "### Changes since \`${prev_tag}\`"
echo ""
if [[ "$prev_version" != "$version" ]]; then
echo "- Rebased to upstream: \`${prev_version}\` → \`${version}\`"
fi
comm -13 <(echo "$prev_branches") <(echo "$cur_branches") \
| sed '/^$/d;s/^/- Added branch: **/;s/$/**/'
comm -23 <(echo "$prev_branches") <(echo "$cur_branches") \
| sed '/^$/d;s/^/- Removed branch: **/;s/$/**/'
while read -r b; do
[[ -z "$b" ]] && continue
local prev_set cur_set added dropped
prev_set=$(awk -F'\t' -v B="$b" '$1==B {print $2}' <<< "$prev_snap" | sort)
cur_set=$(awk -F'\t' -v B="$b" '$1==B {print $2}' <<< "$cur_snap" | sort)
added=$(comm -13 <(echo "$prev_set") <(echo "$cur_set") | sed '/^$/d')
dropped=$(comm -23 <(echo "$prev_set") <(echo "$cur_set") | sed '/^$/d')
if [[ -n "$added" || -n "$dropped" ]]; then
echo "- Updated branch: **${b}**"
[[ -n "$added" ]] && sed 's/^/ - `+` /' <<< "$added"
[[ -n "$dropped" ]] && sed 's/^/ - `-` /' <<< "$dropped"
fi
done < <(comm -12 <(echo "$prev_branches") <(echo "$cur_branches"))
echo ""
fi
# --- Full branch listing -----------------------------------------------
echo "### Applied branches"
echo ""
list_branch_merges "$upstream_hash" "HEAD" | while IFS=$'\t' read -r mhash branch; do
echo "#### ${branch}"
merge_side_commits "$mhash" | while read -r chash subject; do
echo "- \`${chash}\` ${subject}"
done
echo ""
done
}
# ---------------------------------------------------------------------------
# Main flow
# ---------------------------------------------------------------------------
PREV_TAG=$(find_prev_tag "$MAJOR_MINOR")
echo ""
echo "Tag: $TAG"
echo "Branch: $(git branch --show-current)"
echo "Commit: $(git log -1 --oneline)"
[[ -n "$PREV_TAG" ]] && echo "Prev: $PREV_TAG"
echo ""
echo "Generating changelog..."
CHANGELOG=$(generate_changelog "$VERSION" "$PKGREL" "$MAJOR_MINOR" "$PREV_TAG")
echo ""
echo "=== Changelog Preview ==="
echo "$CHANGELOG"
echo "========================="
echo ""
read -rp "Create signed tag? [y/N] " confirm
[[ "$confirm" == [yY] ]] || { echo "Aborted."; exit 0; }
git tag -s "$TAG" -m "$CHANGELOG"
echo ""
echo "Tag '$TAG' created."
read -rp "Push tag and create GitHub release? [y/N] " push_confirm
if [[ "$push_confirm" == [yY] ]]; then
git push origin "$TAG"
echo "Generating source tarball..."
TARBALL="${TAG}.tar.gz"
git archive --format=tar.gz --prefix="${TAG}/" "$TAG" > "$TARBALL"
SIGNING_KEY=$(git config --get user.signingkey || true)
echo "Signing tarball with GPG..."
if [[ -n "$SIGNING_KEY" ]]; then
gpg --local-user "$SIGNING_KEY" --armor --detach-sign -o "${TARBALL}.asc" "$TARBALL"
else
gpg --armor --detach-sign -o "${TARBALL}.asc" "$TARBALL"
fi
NOTES_FILE=$(mktemp --suffix=.md)
echo "$CHANGELOG" > "$NOTES_FILE"
echo "Creating GitHub release and uploading tarball + signature..."
REPO_URL=$(git remote get-url origin)
REPO_SLUG=$(echo "$REPO_URL" | sed -E 's#(https://github\.com/|git@github\.com:)##;s#\.git$##')
gh release create "$TAG" "$TARBALL" "${TARBALL}.asc" \
--repo "$REPO_SLUG" \
--title "CachyOS Linux ${VERSION}-${PKGREL}" \
--notes-file "$NOTES_FILE" \
--verify-tag
rm -f "$TARBALL" "${TARBALL}.asc" "$NOTES_FILE"
echo ""
echo "Release created with uploaded tarball and GPG signature."
echo "Download URL: https://github.com/CachyOS/linux/releases/download/${TAG}/${TARBALL}"
echo "Signature: https://github.com/CachyOS/linux/releases/download/${TAG}/${TARBALL}.asc"
else
echo "Push with: git push origin $TAG"
fi