2023-03-26 17:41:37 +02:00
#!/bin/bash
2023-04-01 11:12:56 +02:00
# SPDX-License-Identifier: MIT
2023-03-26 17:41:37 +02:00
2023-03-29 17:16:26 +02:00
set -e
if ${ VERBOSE :- false } ; then set -x; fi
2023-03-26 17:41:37 +02:00
2025-08-07 17:59:21 +00:00
: " ${ FORGEJO : =https : //codeberg.org } "
: " ${ REPO : =forgejo-integration/forgejo } "
: " ${ TITLE : = $TAG } "
: " ${ RELEASE_DIR : =dist/release } "
: " ${ DOWNLOAD_LATEST : =false } "
: " ${ TMP_DIR : = $( mktemp -d) } "
: " ${ GNUPGHOME : = $TMP_DIR } "
: " ${ TEA_BIN : = $TMP_DIR /tea } "
2025-08-08 07:40:00 +00:00
: " ${ TEA_VERSION : =0.10.1 } "
2025-08-07 17:59:21 +00:00
: " ${ OVERRIDE : =false } "
: " ${ HIDE_ARCHIVE_LINK : =false } "
: " ${ RETRY : =1 } "
: " ${ DELAY : =10 } "
2023-03-26 17:41:37 +02:00
2025-08-02 13:14:48 +00:00
RELEASE_NOTES_ASSISTANT_VERSION = v1.4.0 # renovate: datasource=forgejo-releases depName=forgejo/release-notes-assistant registryUrl=https://code.forgejo.org
2025-07-27 08:08:16 +00:00
2025-02-23 16:03:14 +01:00
TAG_FILE = " $TMP_DIR /tag $$ .json "
2025-07-25 06:50:17 +00:00
TAG_URL = $( echo " $TAG " | sed 's/\//%2F/g' )
2025-02-23 16:03:14 +01:00
2023-05-26 13:03:49 +02:00
export GNUPGHOME
2023-03-26 17:41:37 +02:00
setup_tea( ) {
2025-06-28 20:36:41 +00:00
if which tea 2>/dev/null; then
TEA_BIN = $( which tea)
2025-08-07 17:59:21 +00:00
elif ! test -f " $TEA_BIN " ; then
2025-02-23 15:30:06 +01:00
ARCH = $( dpkg --print-architecture)
2025-08-07 17:59:21 +00:00
curl -sL " https://dl.gitea.io/tea/ $TEA_VERSION /tea- $TEA_VERSION -linux- $ARCH " >" $TEA_BIN "
chmod +x " $TEA_BIN "
2023-03-26 17:41:37 +02:00
fi
}
2025-02-23 16:03:14 +01:00
get_tag( ) {
if ! test -f " $TAG_FILE " ; then
2025-08-07 17:59:21 +00:00
if api GET " repos/ $REPO /tags/ $TAG_URL " >" $TAG_FILE " ; then
2025-02-23 16:03:14 +01:00
echo " tag $TAG exists "
else
echo " tag $TAG does not exists "
fi
fi
test -s " $TAG_FILE "
}
matched_tag( ) {
if get_tag; then
local sha = $( jq --raw-output .commit.sha <" $TAG_FILE " )
test " $sha " = " $SHA "
else
return 1
fi
}
2023-03-26 17:41:37 +02:00
ensure_tag( ) {
2025-02-23 16:03:14 +01:00
if get_tag; then
if ! matched_tag; then
cat " $TAG_FILE "
2025-02-23 15:30:06 +01:00
echo " the tag SHA in the $REPO repository does not match the tag SHA that triggered the build: $SHA "
2025-02-23 16:03:14 +01:00
return 1
2025-02-23 15:30:06 +01:00
fi
2023-03-26 17:41:37 +02:00
else
2025-02-23 23:49:15 +01:00
create_tag
fi
}
create_tag( ) {
2025-08-07 17:59:21 +00:00
api POST " repos/ $REPO /tags " --data-raw '{"tag_name": "' " $TAG " '", "target": "' " $SHA " '"}' >" $TAG_FILE "
2025-02-23 23:49:15 +01:00
}
delete_tag( ) {
if get_tag; then
2025-08-07 17:59:21 +00:00
api DELETE " repos/ $REPO /tags/ $TAG_URL "
2025-02-23 23:49:15 +01:00
rm -f " $TAG_FILE "
2023-03-26 17:41:37 +02:00
fi
}
2023-03-29 17:16:26 +02:00
upload_release( ) {
2024-12-09 05:38:35 +00:00
# assets is defined as a list of arguments, where values may contain whitespace and need to be quoted like this -a "my file.txt" -a "file.txt".
# It is expanded using "${assets[@]}" which preserves the separation of arguments and not split whitespace containing values.
# For reference, see https://github.com/koalaman/shellcheck/wiki/SC2086#exceptions
local assets = ( )
for file in " $RELEASE_DIR " /*; do
assets = ( " ${ assets [@] } " -a " $file " )
done
2025-02-23 15:30:06 +01:00
if $PRERELEASE || echo " ${ TAG } " | grep -qi '\-rc' ; then
2024-12-09 05:38:35 +00:00
releaseType = "--prerelease"
2024-10-29 17:44:34 +01:00
echo "Uploading as Pre-Release"
else
echo "Uploading as Stable"
fi
2023-03-26 17:41:37 +02:00
ensure_tag
2025-08-08 07:52:00 +00:00
if ! $TEA_BIN release create " ${ assets [@] } " --repo " $REPO " --tag " $TAG " --title " $TITLE " --draft ${ releaseType } --note " $RELEASENOTES " >& " $TMP_DIR " /tea.log; then
2025-02-23 15:30:06 +01:00
if grep --quiet 'Unknown API Error: 500' " $TMP_DIR " /tea.log && grep --quiet services/release/release.go:194 " $TMP_DIR " /tea.log; then
2024-10-29 16:08:41 +01:00
echo "workaround v1.20 race condition https://codeberg.org/forgejo/forgejo/issues/1370"
sleep 10
2025-08-08 07:52:00 +00:00
$TEA_BIN release create " ${ assets [@] } " --repo " $REPO " --tag " $TAG " --title " $TITLE " --draft ${ releaseType } --note " $RELEASENOTES "
2024-10-29 16:08:41 +01:00
else
2024-12-09 05:38:35 +00:00
cat " $TMP_DIR " /tea.log
2024-10-29 16:08:41 +01:00
return 1
fi
2023-09-02 08:57:24 +02:00
fi
2024-10-29 16:08:41 +01:00
maybe_use_release_note_assistant
2023-05-24 01:01:15 +02:00
release_draft false
}
release_draft( ) {
local state = " $1 "
2025-08-07 17:59:21 +00:00
local id = $( api GET " repos/ $REPO /releases/tags/ $TAG_URL " | jq --raw-output .id)
2024-11-19 16:38:34 +01:00
2025-08-07 17:59:21 +00:00
api PATCH " repos/ $REPO /releases/ $id " --data-raw '{"draft": ' " $state " ', "hide_archive_links": ' " $HIDE_ARCHIVE_LINK " '}'
2023-03-26 17:41:37 +02:00
}
2024-10-29 16:08:41 +01:00
maybe_use_release_note_assistant( ) {
if " $RELEASE_NOTES_ASSISTANT " ; then
2025-08-07 17:59:21 +00:00
curl --fail -s -S -o rna " https://code.forgejo.org/forgejo/release-notes-assistant/releases/download/ $RELEASE_NOTES_ASSISTANT_VERSION /release-notes-assistant "
2024-10-29 16:08:41 +01:00
chmod +x ./rna
2025-08-07 17:59:21 +00:00
mkdir -p " $RELEASE_NOTES_ASSISTANT_WORKDIR "
./rna --workdir= " $RELEASE_NOTES_ASSISTANT_WORKDIR " --storage release --storage-location " $TAG " --token " $TOKEN " --forgejo-url " $SCHEME :// $HOST " --repository " $REPO " --token " $TOKEN " release " $TAG "
2024-10-29 16:08:41 +01:00
fi
}
2023-05-26 13:03:49 +02:00
sign_release( ) {
local passphrase
if test -s " $GPG_PASSPHRASE " ; then
2025-02-23 15:30:06 +01:00
passphrase = " --passphrase-file $GPG_PASSPHRASE "
2023-05-26 13:03:49 +02:00
fi
2025-08-07 17:59:21 +00:00
gpg --import --no-tty --pinentry-mode loopback " $passphrase " " $GPG_PRIVATE_KEY "
2025-02-23 15:30:06 +01:00
for asset in " $RELEASE_DIR " /*; do
if [ [ $asset = ~ .sha256$ ] ] ; then
continue
fi
2025-08-07 17:59:21 +00:00
gpg --armor --detach-sign --no-tty --pinentry-mode loopback " $passphrase " <" $asset " >" $asset " .asc
2023-05-26 13:03:49 +02:00
done
}
maybe_sign_release( ) {
if test -s " $GPG_PRIVATE_KEY " ; then
2025-02-23 15:30:06 +01:00
sign_release
2023-05-26 13:03:49 +02:00
fi
}
2024-02-11 23:40:17 +01:00
maybe_override( ) {
if test " $OVERRIDE " = "false" ; then
2025-02-23 15:30:06 +01:00
return
2024-02-11 23:40:17 +01:00
fi
2025-08-07 17:59:21 +00:00
api DELETE " repos/ $REPO /releases/tags/ $TAG_URL " >& /dev/null || true
2025-02-23 16:03:14 +01:00
if get_tag && ! matched_tag; then
2025-02-23 23:49:15 +01:00
delete_tag
2025-02-23 16:03:14 +01:00
fi
2024-02-11 23:40:17 +01:00
}
2023-03-29 17:16:26 +02:00
upload( ) {
2023-03-26 17:41:37 +02:00
setup_api
setup_tea
2023-08-25 11:12:23 +02:00
rm -f ~/.config/tea/config.yml
2025-08-07 17:59:21 +00:00
GITEA_SERVER_TOKEN = $TOKEN $TEA_BIN login add --url " $FORGEJO "
2023-05-26 13:03:49 +02:00
maybe_sign_release
2024-02-11 23:40:17 +01:00
maybe_override
2023-03-29 17:16:26 +02:00
upload_release
2023-03-26 17:41:37 +02:00
}
setup_api( ) {
2025-02-23 15:30:06 +01:00
if ! which jq curl; then
apt-get -qq update
apt-get install -y -qq jq curl
2023-03-26 17:41:37 +02:00
fi
}
api( ) {
method = $1
shift
path = $1
shift
2025-08-07 17:59:21 +00:00
curl --fail -X " $method " -sS -H "Content-Type: application/json" -H " Authorization: token $TOKEN " " $@ " " $FORGEJO /api/v1/ $path "
2023-03-26 17:41:37 +02:00
}
2023-05-24 01:01:51 +02:00
wait_release( ) {
local ready = false
2025-08-07 17:59:21 +00:00
for i in $( seq " $RETRY " ) ; do
if api GET " repos/ $REPO /releases/tags/ $TAG_URL " | jq --raw-output .draft >" $TMP_DIR " /draft; then
2025-02-23 15:30:06 +01:00
if test " $( cat " $TMP_DIR " /draft) " = "false" ; then
ready = true
break
fi
echo " release $TAG is still a draft "
else
echo " release $TAG does not exist yet "
2024-12-09 05:38:35 +00:00
fi
2025-02-23 15:30:06 +01:00
echo " waiting $DELAY seconds "
2025-08-07 17:59:21 +00:00
sleep " $DELAY "
2023-05-24 01:01:51 +02:00
done
2025-02-23 15:30:06 +01:00
if ! $ready ; then
echo " no release for $TAG "
return 1
2023-05-24 01:01:51 +02:00
fi
}
2023-03-29 17:16:26 +02:00
download( ) {
2023-03-26 17:41:37 +02:00
setup_api
(
2025-08-07 17:59:21 +00:00
mkdir -p " $RELEASE_DIR "
cd " $RELEASE_DIR "
2025-02-23 15:30:06 +01:00
if [ [ ${ DOWNLOAD_LATEST } = = "true" ] ] ; then
echo "Downloading the latest release"
2025-08-07 17:59:21 +00:00
api GET " repos/ $REPO /releases/latest " >" $TMP_DIR " /assets.json
2025-02-23 15:30:06 +01:00
elif [ [ ${ DOWNLOAD_LATEST } = = "false" ] ] ; then
wait_release
echo " Downloading tagged release ${ TAG } "
2025-08-07 17:59:21 +00:00
api GET " repos/ $REPO /releases/tags/ $TAG_URL " >" $TMP_DIR " /assets.json
2025-02-23 15:30:06 +01:00
fi
jq --raw-output '.assets[] | "\(.browser_download_url) \(.name)"' <" $TMP_DIR " /assets.json | while read url name; do # `name` may contain whitespace, therefore, it must be last
2025-07-25 06:50:17 +00:00
url = $( echo " $url " | sed " s#/download/ ${ TAG } /#/download/ ${ TAG_URL } /# " )
2025-02-23 15:30:06 +01:00
curl --fail -H " Authorization: token $TOKEN " -o " $name " -L " $url "
done
2023-03-26 17:41:37 +02:00
)
}
missing( ) {
2023-03-29 17:16:26 +02:00
echo need upload or download argument got nothing
2023-03-26 17:41:37 +02:00
exit 1
}
${ @ :- missing }