From 9d4ddfbaadf2ac8f162dba4bf2ee9b3d0296ddb3 Mon Sep 17 00:00:00 2001 From: limiting-factor Date: Sun, 23 Feb 2025 15:30:06 +0100 Subject: [PATCH 1/2] chore(editorconfig): comply with .editorconfig --- forgejo-release.sh | 108 +++++++++++++++---------------- testdata/forgejo-release-test.sh | 13 ++-- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/forgejo-release.sh b/forgejo-release.sh index 8abb54e..20d5221 100755 --- a/forgejo-release.sh +++ b/forgejo-release.sh @@ -22,23 +22,23 @@ if ${VERBOSE:-false}; then set -x; fi export GNUPGHOME setup_tea() { - if ! test -f "$BIN_DIR"/tea ; then - ARCH=$(dpkg --print-architecture) - curl -sL https://dl.gitea.io/tea/$TEA_VERSION/tea-$TEA_VERSION-linux-"$ARCH" > "$BIN_DIR"/tea - chmod +x "$BIN_DIR"/tea + if ! test -f "$BIN_DIR"/tea; then + ARCH=$(dpkg --print-architecture) + curl -sL https://dl.gitea.io/tea/$TEA_VERSION/tea-$TEA_VERSION-linux-"$ARCH" >"$BIN_DIR"/tea + chmod +x "$BIN_DIR"/tea fi } ensure_tag() { - if api GET repos/$REPO/tags/"$TAG" > "$TMP_DIR"/tag.json ; then - local sha=$(jq --raw-output .commit.sha < "$TMP_DIR"/tag.json) - if test "$sha" != "$SHA" ; then - cat "$TMP_DIR"/tag.json - echo "the tag SHA in the $REPO repository does not match the tag SHA that triggered the build: $SHA" - false - fi + if api GET repos/$REPO/tags/"$TAG" >"$TMP_DIR"/tag.json; then + local sha=$(jq --raw-output .commit.sha <"$TMP_DIR"/tag.json) + if test "$sha" != "$SHA"; then + cat "$TMP_DIR"/tag.json + echo "the tag SHA in the $REPO repository does not match the tag SHA that triggered the build: $SHA" + false + fi else - api POST repos/$REPO/tags --data-raw '{"tag_name": "'"$TAG"'", "target": "'"$SHA"'"}' + api POST repos/$REPO/tags --data-raw '{"tag_name": "'"$TAG"'", "target": "'"$SHA"'"}' fi } @@ -50,15 +50,15 @@ upload_release() { for file in "$RELEASE_DIR"/*; do assets=("${assets[@]}" -a "$file") done - if $PRERELEASE || echo "${TAG}" | grep -qi '\-rc' ; then + if $PRERELEASE || echo "${TAG}" | grep -qi '\-rc'; then releaseType="--prerelease" echo "Uploading as Pre-Release" else echo "Uploading as Stable" fi ensure_tag - if ! "$BIN_DIR"/tea release create "${assets[@]}" --repo $REPO --note "$RELEASENOTES" --tag "$TAG" --title "$TITLE" --draft ${releaseType} >& "$TMP_DIR"/tea.log ; then - if grep --quiet 'Unknown API Error: 500' "$TMP_DIR"/tea.log && grep --quiet services/release/release.go:194 "$TMP_DIR"/tea.log ; then + if ! "$BIN_DIR"/tea release create "${assets[@]}" --repo $REPO --note "$RELEASENOTES" --tag "$TAG" --title "$TITLE" --draft ${releaseType} >&"$TMP_DIR"/tea.log; then + if grep --quiet 'Unknown API Error: 500' "$TMP_DIR"/tea.log && grep --quiet services/release/release.go:194 "$TMP_DIR"/tea.log; then echo "workaround v1.20 race condition https://codeberg.org/forgejo/forgejo/issues/1370" sleep 10 "$BIN_DIR"/tea release create "${assets[@]}" --repo $REPO --note "$RELEASENOTES" --tag "$TAG" --title "$TITLE" --draft ${releaseType} @@ -90,29 +90,29 @@ maybe_use_release_note_assistant() { sign_release() { local passphrase if test -s "$GPG_PASSPHRASE"; then - passphrase="--passphrase-file $GPG_PASSPHRASE" + passphrase="--passphrase-file $GPG_PASSPHRASE" fi gpg --import --no-tty --pinentry-mode loopback $passphrase "$GPG_PRIVATE_KEY" - for asset in "$RELEASE_DIR"/* ; do - if [[ $asset =~ .sha256$ ]] ; then - continue - fi - gpg --armor --detach-sign --no-tty --pinentry-mode loopback $passphrase < "$asset" > "$asset".asc + for asset in "$RELEASE_DIR"/*; do + if [[ $asset =~ .sha256$ ]]; then + continue + fi + gpg --armor --detach-sign --no-tty --pinentry-mode loopback $passphrase <"$asset" >"$asset".asc done } maybe_sign_release() { if test -s "$GPG_PRIVATE_KEY"; then - sign_release + sign_release fi } maybe_override() { if test "$OVERRIDE" = "false"; then - return + return fi - api DELETE repos/$REPO/releases/tags/"$TAG" >& /dev/null || true - api DELETE repos/$REPO/tags/"$TAG" >& /dev/null || true + api DELETE repos/$REPO/releases/tags/"$TAG" >&/dev/null || true + api DELETE repos/$REPO/tags/"$TAG" >&/dev/null || true } upload() { @@ -126,9 +126,9 @@ upload() { } setup_api() { - if ! which jq curl ; then - apt-get -qq update - apt-get install -y -qq jq curl + if ! which jq curl; then + apt-get -qq update + apt-get install -y -qq jq curl fi } @@ -144,40 +144,40 @@ api() { wait_release() { local ready=false for i in $(seq $RETRY); do - if api GET repos/$REPO/releases/tags/"$TAG" | jq --raw-output .draft > "$TMP_DIR"/draft; then - if test "$(cat "$TMP_DIR"/draft)" = "false"; then - ready=true - break + if api GET repos/$REPO/releases/tags/"$TAG" | jq --raw-output .draft >"$TMP_DIR"/draft; then + 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" fi - echo "release $TAG is still a draft" - else - echo "release $TAG does not exist yet" - fi - echo "waiting $DELAY seconds" - sleep $DELAY + echo "waiting $DELAY seconds" + sleep $DELAY done - if ! $ready ; then - echo "no release for $TAG" - return 1 + if ! $ready; then + echo "no release for $TAG" + return 1 fi } download() { setup_api ( - mkdir -p $RELEASE_DIR - cd $RELEASE_DIR - if [[ ${DOWNLOAD_LATEST} == "true" ]] ; then - echo "Downloading the latest release" - api GET repos/$REPO/releases/latest > "$TMP_DIR"/assets.json - elif [[ ${DOWNLOAD_LATEST} == "false" ]] ; then - wait_release - echo "Downloading tagged release ${TAG}" - api GET repos/$REPO/releases/tags/"$TAG" > "$TMP_DIR"/assets.json - 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 - curl --fail -H "Authorization: token $TOKEN" -o "$name" -L "$url" - done + mkdir -p $RELEASE_DIR + cd $RELEASE_DIR + if [[ ${DOWNLOAD_LATEST} == "true" ]]; then + echo "Downloading the latest release" + api GET repos/$REPO/releases/latest >"$TMP_DIR"/assets.json + elif [[ ${DOWNLOAD_LATEST} == "false" ]]; then + wait_release + echo "Downloading tagged release ${TAG}" + api GET repos/$REPO/releases/tags/"$TAG" >"$TMP_DIR"/assets.json + 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 + curl --fail -H "Authorization: token $TOKEN" -o "$name" -L "$url" + done ) } diff --git a/testdata/forgejo-release-test.sh b/testdata/forgejo-release-test.sh index 4e84498..4ff2eae 100755 --- a/testdata/forgejo-release-test.sh +++ b/testdata/forgejo-release-test.sh @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT set -ex +PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: ' test_teardown() { setup_api @@ -44,16 +45,16 @@ test_ensure_tag() { # idempotent # ensure_tag - api GET repos/$REPO/tags/$TAG > $TMP_DIR/tag1.json + api GET repos/$REPO/tags/$TAG >$TMP_DIR/tag1.json ensure_tag - api GET repos/$REPO/tags/$TAG > $TMP_DIR/tag2.json + api GET repos/$REPO/tags/$TAG >$TMP_DIR/tag2.json diff -u $TMP_DIR/tag[12].json # # sanity check on the SHA of an existing tag # ( - SHA=12345 - ! ensure_tag + SHA=12345 + ! ensure_tag ) api DELETE repos/$REPO/tags/$TAG } @@ -94,8 +95,8 @@ test_maybe_sign_release_skipped() { } test_maybe_sign_release_verify() { - for file in $RELEASE_DIR/file-one.txt $RELEASE_DIR/file-two.txt; do - gpg --verify $file.asc $file + for file in $RELEASE_DIR/file-one.txt $RELEASE_DIR/file-two.txt; do + gpg --verify $file.asc $file done } From 0079bcb471a6d260bb06ef51ff495ec1c6cdcc2f Mon Sep 17 00:00:00 2001 From: limiting-factor Date: Sun, 23 Feb 2025 16:03:14 +0100 Subject: [PATCH 2/2] fix: override=true must not needlessly delete a tag If the tag to be set is exactly the same as the tag that exists, do not delete it. When the tag is recreated although it is not necessary, it may trigger workflows that have already been triggered and send the workflow in a loop. - split `get_tag` & `matched_tag` out of ensure_tag - in case of an override, only delete the tag if it fails `matched_tag` - trace shell lines to help debug - add testing --- forgejo-release.sh | 37 ++++++++++++++++++++++++++------ testdata/forgejo-release-test.sh | 7 ++++-- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/forgejo-release.sh b/forgejo-release.sh index 20d5221..1474b6a 100755 --- a/forgejo-release.sh +++ b/forgejo-release.sh @@ -19,6 +19,8 @@ if ${VERBOSE:-false}; then set -x; fi : ${RETRY:=1} : ${DELAY:=10} +TAG_FILE="$TMP_DIR/tag$$.json" + export GNUPGHOME setup_tea() { @@ -29,16 +31,35 @@ setup_tea() { fi } +get_tag() { + if ! test -f "$TAG_FILE"; then + if api GET repos/$REPO/tags/"$TAG" >"$TAG_FILE"; then + 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 +} + ensure_tag() { - if api GET repos/$REPO/tags/"$TAG" >"$TMP_DIR"/tag.json; then - local sha=$(jq --raw-output .commit.sha <"$TMP_DIR"/tag.json) - if test "$sha" != "$SHA"; then - cat "$TMP_DIR"/tag.json + if get_tag; then + if ! matched_tag; then + cat "$TAG_FILE" echo "the tag SHA in the $REPO repository does not match the tag SHA that triggered the build: $SHA" - false + return 1 fi else - api POST repos/$REPO/tags --data-raw '{"tag_name": "'"$TAG"'", "target": "'"$SHA"'"}' + api POST repos/$REPO/tags --data-raw '{"tag_name": "'"$TAG"'", "target": "'"$SHA"'"}' >"$TAG_FILE" fi } @@ -112,7 +133,9 @@ maybe_override() { return fi api DELETE repos/$REPO/releases/tags/"$TAG" >&/dev/null || true - api DELETE repos/$REPO/tags/"$TAG" >&/dev/null || true + if get_tag && ! matched_tag; then + api DELETE repos/$REPO/tags/"$TAG" + fi } upload() { diff --git a/testdata/forgejo-release-test.sh b/testdata/forgejo-release-test.sh index 4ff2eae..97f630c 100755 --- a/testdata/forgejo-release-test.sh +++ b/testdata/forgejo-release-test.sh @@ -45,15 +45,18 @@ test_ensure_tag() { # idempotent # ensure_tag - api GET repos/$REPO/tags/$TAG >$TMP_DIR/tag1.json + mv $TAG_FILE $TMP_DIR/tag1.json + ensure_tag - api GET repos/$REPO/tags/$TAG >$TMP_DIR/tag2.json + mv $TAG_FILE $TMP_DIR/tag2.json + diff -u $TMP_DIR/tag[12].json # # sanity check on the SHA of an existing tag # ( SHA=12345 + ! matched_tag ! ensure_tag ) api DELETE repos/$REPO/tags/$TAG