-
Notifications
You must be signed in to change notification settings - Fork 55
/
make-release.sh
executable file
·350 lines (292 loc) · 12.2 KB
/
make-release.sh
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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#!/bin/bash
#
# Copyright (c) 2019-2024 Red Hat, Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
set -e
DWO_REPO="${DWO_REPO:[email protected]:devfile/devworkspace-operator}"
DWO_QUAY_REPO="${DWO_QUAY_REPO:-quay.io/devfile/devworkspace-controller}"
PROJECT_CLONE_QUAY_REPO="${PROJECT_CLONE_QUAY_REPO:-quay.io/devfile/project-clone}"
DWO_BUNDLE_QUAY_REPO="${DWO_BUNDLE_QUAY_REPO:-quay.io/devfile/devworkspace-operator-bundle}"
DWO_INDEX_IMAGE="${DWO_INDEX_IMAGE:-quay.io/devfile/devworkspace-operator-index:release}"
DWO_DIGEST_INDEX_IMAGE="${DWO_DIGEST_INDEX_IMAGE:-quay.io/devfile/devworkspace-operator-index:release-digest}"
MAIN_BRANCH="main"
ARCHITECTURES="linux/amd64,linux/arm64,linux/ppc64le,linux/s390x"
VERBOSE=""
TMP=""
usage () {
cat << EOF
This scripts handles the upstream release process for DWO.
To begin a new release process, use the '--prerelease' flag. This will create a
branch, e.g. '0.<VERSION>.x' for the specified version and update all relevant
files within that branch to reflect the new version. This branch should then be
tested, with additional commits cherry-picked as necessary to prepare for
release. Once the HEAD commit of the '0.<VERSION>.x' branch is ready for
release, use the '--release' from the release branch to create the release tag
and build and push release container images to the Quay repo. Running with the
release flag will also update versions in the release branch to reflect the next
bugfix release (e.g. will update from v0.8.0 to v0.8.1).
To issue a bugfix release, cherry-pick commits into the existing release branch
as necessary and run this script with the '--release' flag for the given bugfix
version.
Arguments:
--version : version to release, e.g. v0.8.0
--prerelease : flag to perform prerelease. Is performed from main branch
--release : flag to perform release. Is performed from v0.x.y branch
Development arguments to debug:
--dry-run : do not push changes locally
--verbose : enables verbose output
--tmp-dir : perform operation in repo cloned into temporary folder. Repo can be modified with DWO_REPO env var
Examples:
$0 --prerelease --version v0.1.0
$0 --release --version v0.1.0
This script is intended to be triggered by GitHub Actions on the repo.
EOF
}
dryrun() {
printf -v cmd_str '%q ' "$@"; echo "DRYRUN: Not executing $cmd_str" >&2
}
parse_args() {
while [[ "$#" -gt 0 ]]; do
case $1 in
# Ensure version parameter is in format vX.Y.Z
'-v'|'--version') VERSION="v${2#v}"; shift 1;;
'--tmp-dir') TMP=$(mktemp -d); shift 0;;
'--release') DO_RELEASE=true; shift 0;;
'--prerelease') DO_PRERELEASE='true'; shift 0;;
'--dry-run') DRY_RUN='dryrun'; shift 0;;
'--verbose') VERBOSE='true'; shift 0;;
'--help') usage; exit 0;;
*) echo "[ERROR] Unknown parameter is used: $1."; usage; exit 1;;
esac
shift 1
done
if [ -z "${VERSION}" ]; then
echo "[ERROR] Required parameter --version is missing."
usage
exit 1
fi
version_pattern='^v[0-9]+\.[0-9]+\.[0-9]+$'
if [[ ! ${VERSION} =~ $version_pattern ]]; then
echo "did not match"
echo "exit 1"
fi
}
# Updates hard-coded version strings in repo (version.go, CSV templates). For go files, version is prepended with 'v',
# e.g. if version is 0.10.0, Go files use version v0.10.0. Files are regenerated but changes are not committed to the
# repo.
# Args:
# $1 - Version to set in files
update_version() {
local VERSION=${1#v}
# change version/version.go file
VERSION_GO="v${VERSION}"
VERSION_CSV="$VERSION"
sed -i version/version.go -e "s#Version = \".*\"#Version = \"${VERSION_GO}\"#g"
yq -Yi \
--arg operator_name "devworkspace-operator.v$VERSION_CSV" \
--arg version "$VERSION_CSV" \
'.metadata.name = $operator_name | .spec.version = $version' deploy/templates/components/csv/clusterserviceversion.yaml
make generate_all
}
# Updates container images and tags used in deployment templates for a release version
# of DWO. Sets appropriate image names for controller and project clone images and
# updates defaults in Makefile. Does not commit changes to repo.
# Args:
# $1 - Version for images
update_images() {
VERSION="$1"
# Get image tags
DWO_QUAY_IMG="${DWO_QUAY_REPO}:${VERSION}"
PROJECT_CLONE_QUAY_IMG="${PROJECT_CLONE_QUAY_REPO}:${VERSION}"
DWO_BUNDLE_QUAY_IMG="${DWO_BUNDLE_QUAY_REPO}:${VERSION}"
# Update defaults in Makefile
sed -i Makefile -r \
-e "s|quay.io/devfile/devworkspace-controller:[0-9a-zA-Z._-]+|${DWO_QUAY_IMG}|g" \
-e "s|quay.io/devfile/project-clone:[0-9a-zA-Z._-]+|${PROJECT_CLONE_QUAY_IMG}|g" \
-e "s|quay.io/devfile/devworkspace-operator-bundle:[0-9a-zA-Z._-]+|${DWO_BUNDLE_QUAY_IMG}|g" \
-e "s|quay.io/devfile/devworkspace-operator-index:[0-9a-zA-Z._-]+|${DWO_INDEX_IMAGE}|g"
# Update defaults in generate_deployment.sh
sed -i build/scripts/generate_deployment.sh -r \
-e "s|quay.io/devfile/devworkspace-controller:[0-9a-zA-Z._-]+|${DWO_QUAY_IMG}|g" \
-e "s|quay.io/devfile/project-clone:[0-9a-zA-Z._-]+|${PROJECT_CLONE_QUAY_IMG}|g"
local DEFAULT_DWO_IMG="$DWO_QUAY_IMG"
local PROJECT_CLONE_IMG="$PROJECT_CLONE_QUAY_IMG"
export DEFAULT_DWO_IMG
export PROJECT_CLONE_IMG
make generate_all
}
# Build and push images for specified release version. Respects the DRY_RUN flag
# TODO:
# - Build release images for bundle and index
# Args:
# $1 - Version for images
build_and_push_images() {
DWO_QUAY_IMG="${DWO_QUAY_REPO}:${VERSION}"
PROJECT_CLONE_QUAY_IMG="${PROJECT_CLONE_QUAY_REPO}:${VERSION}"
if [ "$DRY_RUN" == "dryrun" ]; then
docker buildx build . -t "${DWO_QUAY_IMG}" -f ./build/Dockerfile \
--platform "$ARCHITECTURES"
docker buildx build . -t "${PROJECT_CLONE_QUAY_IMG}" -f ./project-clone/Dockerfile \
--platform "$ARCHITECTURES"
else
docker buildx build . -t "${DWO_QUAY_IMG}" -f ./build/Dockerfile \
--platform "$ARCHITECTURES" \
--push
docker buildx build . -t "${PROJECT_CLONE_QUAY_IMG}" -f ./project-clone/Dockerfile \
--platform "$ARCHITECTURES" \
--push
fi
}
# Commit and push changes in local repo to remote (respecting DRY_RUN setting). If the branch cannot be pushed to,
# create a temporary branch and open a PR based off it. If repo state is clean, no new commit is created and branch
# is pushed.
# Args:
# $1 - Commit message to use for commit
# $2 - PR branch name to use if necessary
git_commit_and_push() {
local COMMIT_MSG="$1"
local PR_BRANCH="$2"
local CURRENT_BRANCH
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
git add -A
if [[ -n $(git status -s) ]]; then # dirty
git commit -m "${COMMIT_MSG}" --signoff
fi
if [[ -z "$DRY_RUN" ]]; then
set +e
PUSH_TRY="$(git push origin "${CURRENT_BRANCH}")"
PUSH_TRY_EXIT_CODE=$?
set -e
else
PUSH_TRY="protected branch hook declined"
fi
# shellcheck disable=SC2181
if [[ "${PUSH_TRY_EXIT_CODE}" -gt 0 ]] || [[ $PUSH_TRY == *"protected branch hook declined"* ]]; then
# create pull request for the main branch branch, as branch is restricted
git branch "${PR_BRANCH}"
git checkout "${PR_BRANCH}"
git pull origin "${PR_BRANCH}" || true
$DRY_RUN git push origin "${PR_BRANCH}"
$DRY_RUN gh pr create -f -B "${CURRENT_BRANCH}" -H "${PR_BRANCH}"
fi
git checkout "${CURRENT_BRANCH}"
}
# Perform prerelease actions in repo based on VERSION env var (--version flag):
# 1. Create a new release branch, e.g v0.10.x if $VERSION is v0.10.0
# 2. Update version in release branch to reflect $VERSION
# 3. Push release branch to remote repo
# 4. Update main branch to reflect next version
# 5. Push changes to remote main branch (via PR if necessary)
# Args:
# $1 - Next version to release (e.g. v0.10.0). Should be minor release, not bugfix
prerelease() {
local VERSION=$1
if [ "${VERSION##*.}" != "0" ]; then
echo "[ERROR] Flag --prerelease should not be used for bugfix versions"
exit 1
fi
echo "[INFO] Starting prerelease procedure"
# derive bugfix branch from version
X_BRANCH=${VERSION#v}
X_BRANCH=${X_BRANCH%.*}.x
echo "[INFO] Creating ${X_BRANCH} from ${MAIN_BRANCH}"
git checkout ${MAIN_BRANCH}
git checkout -b "${X_BRANCH}"
echo "[INFO] Updating version to $VERSION"
update_version "$VERSION"
update_images "$VERSION"
git_commit_and_push "[prerelease] Prepare branch for release" "ci-prerelease-$VERSION"
# bump version in MAIN_BRANCH to next dev version
[[ $X_BRANCH =~ ^([0-9]+)\.([0-9]+)\.x ]] \
&& BASE=${BASH_REMATCH[1]}; \
NEXT=${BASH_REMATCH[2]}; \
(( NEXT=NEXT+1 )) # for X_BRANCH=0.1.x, get BASE=0, NEXT=2
NEXT_DEV_VERSION="${BASE}.${NEXT}.0-dev"
git checkout ${MAIN_BRANCH}
update_version "$NEXT_DEV_VERSION"
git_commit_and_push "chore: release: bump to ${NEXT_DEV_VERSION} in $MAIN_BRANCH" "ci-bump-$MAIN_BRANCH-$NEXT_DEV_VERSION"
echo "[INFO] Prerelease is done"
}
# Perform release process for new version. Assumes that pre-release has been completed:
#
# Args:
# $1 - Version to release
release() {
local VERSION=$1
if git ls-remote --exit-code --tags origin "${VERSION}" > /dev/null; then
echo "Version $VERSION is already tagged; aborting"
exit 1
fi
echo "[INFO] Starting Release procedure"
# derive bugfix branch from version
X_BRANCH=${VERSION#v}
X_BRANCH=${X_BRANCH%.*}.x
git fetch origin "${X_BRANCH}:${X_BRANCH}" || true
git checkout "${X_BRANCH}"
# Build bundle and index images
$DRY_RUN build/scripts/build_index_image.sh \
--release \
--bundle-tag "$VERSION" \
--bundle-repo "$DWO_BUNDLE_QUAY_REPO" \
--index-image "$DWO_INDEX_IMAGE" \
--force
# Commit changes from releasing bundle
git_commit_and_push "[release] Add OLM bundle for $VERSION in $X_BRANCH" "ci-add-bundle-$VERSION"
# Tag current commit as release version
git tag "${VERSION}"
$DRY_RUN git push origin "${VERSION}"
# Build container images for relase
build_and_push_images "$VERSION"
$DRY_RUN build/scripts/build_digests_bundle.sh \
--bundle "${DWO_BUNDLE_QUAY_REPO}:${VERSION}" \
--render olm-catalog/release-digest/ \
--push "${DWO_BUNDLE_QUAY_REPO}:${VERSION}-digest" \
--container-tool docker \
--debug
CHANNEL_ENTRY_JSON=$(yq --arg version "$VERSION" '.entries[] | select(.name == "devworkspace-operator.\($version)")' olm-catalog/release/channel.yaml)
yq -Y -i --argjson entry "$CHANNEL_ENTRY_JSON" '.entries |= . + [$entry]' olm-catalog/release-digest/channel.yaml
opm validate olm-catalog/release-digest/
echo "[INFO] Building index image $DWO_DIGEST_INDEX_IMAGE"
docker build . -t "$DWO_DIGEST_INDEX_IMAGE" -f "build/index.release-digest.Dockerfile"
docker push "$DWO_DIGEST_INDEX_IMAGE" 2>&1
# Commit changes from rendering digests bundle
git_commit_and_push "[post-release] Add OLM digest bundle for $VERSION in $X_BRANCH" "ci-add-digest-bundle-$VERSION"
# Update ${X_BRANCH} to the new rc version
git checkout "${X_BRANCH}"
# bump the z digit
[[ ${VERSION#v} =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]] \
&& BASE="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"; \
NEXT="${BASH_REMATCH[3]}"; (( NEXT=NEXT+1 )) # for VERSION=0.1.2, get BASE=0.1, NEXT=3
NEXT_VERSION_Z="v${BASE}.${NEXT}"
update_version "$NEXT_VERSION_Z"
update_images "$NEXT_VERSION_Z"
git_commit_and_push "chore: release: bump to ${NEXT_VERSION_Z} in $X_BRANCH" "ci-bump-$X_BRANCH-$NEXT_VERSION_Z"
echo "[INFO] Release is done"
}
parse_args "$@"
[[ -n $VERBOSE ]] && echo "[INFO] Enabling verbose output" && set -x
# work in tmp dir
if [[ $TMP ]] && [[ -d $TMP ]]; then
pushd "$TMP" > /dev/null || exit 1
echo "[INFO] Check out ${DWO_REPO} to ${TMP}/${DWO_REPO##*/}"
git clone "${DWO_REPO}" -q
cd "${DWO_REPO##*/}" || exit 1
fi
[[ -n "$DO_PRERELEASE" ]] && prerelease "$VERSION"
[[ -n "$DO_RELEASE" ]] && release "$VERSION"
# cleanup tmp dir
if [[ $TMP ]] && [[ -d $TMP ]]; then
popd > /dev/null || exit
$DRY_RUN rm -fr "$TMP"
fi