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
|
// Builds are driven by the tag name. The pipeline does nothing at all unless
// the checkout is a tag of the form
//
// fedora-<fedora_ver>-kernel-<upstream_ver>-patchset-<patchset_ver>
//
// e.g. fedora-45-kernel-7.2.3-patchset-1.
//
// The Fedora version picks the build container and the bucket prefix. The
// kernel and patchset versions are asserted against the spec rather than fed
// into it, so the spec stays the one place they are defined and a mistyped tag
// fails the build instead of publishing something that disagrees with its name.
TAG_PATTERN = /^fedora-(\d+)-kernel-(.+)-patchset-(\d+)$/
// The container image is the one field that has to be known before the agent
// exists, so it cannot be read out of the shell below. Everything between
// `fedora-` and `-kernel-` is the Fedora version, and it never contains a dash.
def fedoraVersionFromTag() {
def tag = env.TAG_NAME ?: ''
tag ==~ TAG_PATTERN ? tag.split('-')[1] : null
}
pipeline {
agent none
options {
timestamps()
}
environment {
B2_ENDPOINT = 'https://s3.eu-central-003.backblazeb2.com'
AWS_DEFAULT_REGION = 'eu-central-003'
RPM_BUCKET = 'dist-sayagit-fedora-rpm'
// awscli2 sends CRC32 checksums by default, which B2 rejects. Ask for
// them only where the S3 API requires them.
AWS_REQUEST_CHECKSUM_CALCULATION = 'when_required'
AWS_RESPONSE_CHECKSUM_VALIDATION = 'when_required'
}
stages {
stage('Build and publish kernel-surface RPM (ARM64)') {
when {
beforeAgent true
allOf {
buildingTag()
expression { env.TAG_NAME ==~ TAG_PATTERN }
}
}
agent {
kubernetes {
defaultContainer 'rpmbuild'
yaml """
apiVersion: v1
kind: Pod
metadata:
namespace: jenkins
spec:
nodeSelector:
kubernetes.io/arch: arm64
containers:
- name: rpmbuild
image: fedora:${fedoraVersionFromTag()}
imagePullPolicy: Always
command: [ 'sleep' ]
args: [ 'infinity' ]
tty: true
resources:
requests:
cpu: "4"
memory: 5Gi
ephemeral-storage: 40Gi
limits:
memory: 5Gi
ephemeral-storage: 100Gi
"""
}
}
steps {
checkout scm
container('rpmbuild') {
withCredentials([usernamePassword(
credentialsId: 'backblaze-b2-dist-rpm',
usernameVariable: 'AWS_ACCESS_KEY_ID',
passwordVariable: 'AWS_SECRET_ACCESS_KEY')]) {
sh '''
set -eux
dnf --assumeyes install \\
git rpm-build rpmdevtools dnf5-plugins awscli2 curl tar \\
createrepo_c
git config --global --add safe.directory '*'
git submodule update --init overlay
rest=${TAG_NAME#fedora-*-kernel-}
tag_fedora=${TAG_NAME#fedora-}
tag_fedora=${tag_fedora%%-kernel-*}
tag_kernel=${rest%-patchset-*}
tag_patchset=${rest##*-patchset-}
fedora_version=${tag_fedora}
# The tag drives the build: these override the
# spec's own %global defaults, and make-sources.sh
# reads them out of the environment so the patch
# tarball it assembles is the one Source1 names.
export UPSTREAM_VER=${tag_kernel}
export PATCHSET_VER=${tag_patchset}
# A numbered tag has to agree with the container it
# selected, which is what stamps %{?dist} onto the
# release.
container_fedora=$(rpm --eval '%{fedora}')
if [ "${tag_fedora}" != "${container_fedora}" ]; then
echo "tag names Fedora ${tag_fedora}, container is ${container_fedora}" >&2
exit 1
fi
rpmdev-setuptree
# The published file names are whatever the spec
# resolves to under the tag's versions, so the two
# cannot drift. Note the plural: kernel-surface-dtb
# is a separate package because the main one is
# installonly and cannot own a path that carries no
# kernel version. Publishing only the first would
# leave the kernel unresolvable.
prefix="s3://${RPM_BUCKET}/fedora/${fedora_version}/aarch64"
rpm_files=$(rpmspec -q \\
--define "upstream_ver ${UPSTREAM_VER}" \\
--define "patchset_ver ${PATCHSET_VER}" \\
--queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm\\n' \\
kernel-surface.spec)
# A kernel build is expensive; skip it only when
# every one of those is already in the bucket.
skip_build=true
for rpm_name in ${rpm_files}; do
if ! aws s3 ls --endpoint-url "${B2_ENDPOINT}" \\
"${prefix}/${rpm_name}"; then
skip_build=false
fi
done
if [ "${skip_build}" = true ]; then
echo "${TAG_NAME} is already published in full, skipping build"
fi
if [ "${skip_build}" = false ]; then
./make-sources.sh
dnf --assumeyes builddep kernel-surface.spec
rpmbuild -bb \\
--define "upstream_ver ${UPSTREAM_VER}" \\
--define "patchset_ver ${PATCHSET_VER}" \\
--define '_smp_mflags -j4' \\
kernel-surface.spec
# kernel-surface-dtb is noarch, so it lands
# in RPMS/noarch rather than RPMS/aarch64; ask
# where each one actually is.
for rpm_name in ${rpm_files}; do
built=$(find "${HOME}/rpmbuild/RPMS" -type f \\
-name "${rpm_name}" -print -quit)
test -n "${built}"
aws s3 cp --endpoint-url "${B2_ENDPOINT}" \\
"${built}" "${prefix}/${rpm_name}"
done
fi
repo="${WORKSPACE}/repo"
mkdir -p "${repo}"
aws s3 sync --endpoint-url "${B2_ENDPOINT}" \\
--exclude '*' --include '*.rpm' \\
"${prefix}/" "${repo}/"
createrepo_c --update "${repo}"
aws s3 sync --endpoint-url "${B2_ENDPOINT}" \\
--exclude 'repomd.xml*' \\
"${repo}/repodata/" "${prefix}/repodata/"
aws s3 cp --endpoint-url "${B2_ENDPOINT}" \\
"${repo}/repodata/repomd.xml" \\
"${prefix}/repodata/repomd.xml"
# Served next to the repository so that consumers
# can `dnf config-manager --add-repo` the URL.
sed "s|[$]releasever|${fedora_version}|g" \\
kernel-sp12in.repo > "${WORKSPACE}/published.repo"
aws s3 cp --endpoint-url "${B2_ENDPOINT}" \\
"${WORKSPACE}/published.repo" \\
"s3://${RPM_BUCKET}/fedora/${fedora_version}/kernel-sp12in.repo"
'''
}
}
}
}
}
}
|