#!/bin/sh # Publishes a built release (make dist, make cli-dist, make deb for each # architecture) to Gitea: # # * a release for tag v with the CHANGELOG section for VERSION as # its notes, and every file in dist/ (tarballs, CLI binaries, .debs) # plus a SHA256SUMS of them attached; # * the .debs in the owner's Debian package registry, so servers can # 'apt install jarl' and get updates with apt (docs/install.md). # # Run by .gitea/workflows/release.yml when a v* tag is pushed. Running it # again for the same version replaces the attachments and packages. # # Variables: # GITEA_URL e.g. https://gitea.example.com (in Actions: # GITHUB_SERVER_URL) # GITEA_REPO owner/name (in Actions: GITHUB_REPOSITORY) # GITEA_TOKEN a token with write:repository and write:package # VERSION default: the VERSION file # DEB_DISTRIBUTION the apt distribution (default: stable) # DEB_COMPONENT the apt component (default: main) # # Needs curl and jq. set -eu : "${GITEA_URL:=${GITHUB_SERVER_URL:-}}" "${GITEA_REPO:=${GITHUB_REPOSITORY:-}}" : "${GITEA_URL:?set GITEA_URL}" "${GITEA_REPO:?set GITEA_REPO}" "${GITEA_TOKEN:?set GITEA_TOKEN}" VERSION=${VERSION:-$(cat VERSION)} DEB_DISTRIBUTION=${DEB_DISTRIBUTION:-stable} DEB_COMPONENT=${DEB_COMPONENT:-main} GITEA_URL=${GITEA_URL%/} owner=${GITEA_REPO%%/*} tag=v$VERSION api=$GITEA_URL/api/v1/repos/$GITEA_REPO # curl with the token; fails on HTTP errors except the codes in $ok. call() { ok=$1 shift out=$(mktemp) code=$(curl -sS -o "$out" -w '%{http_code}' -H "Authorization: token $GITEA_TOKEN" "$@") case " 200 201 204 $ok " in *" $code "*) cat "$out"; rm -f "$out"; return 0 ;; esac echo "gitea-release: HTTP $code from $*" >&2 cat "$out" >&2 echo >&2 rm -f "$out" return 1 } files=$(find dist -maxdepth 1 -type f ! -name SHA256SUMS | sort) [ -n "$files" ] || { echo "gitea-release: nothing in dist/" >&2; exit 1; } for f in $files; do case $f in *"$VERSION"*) ;; *) echo "gitea-release: $f is not version $VERSION" >&2; exit 1 ;; esac done # shellcheck disable=SC2046 # file names have no spaces (cd dist && sha256sum $(printf '%s\n' "$files" | sed 's|^dist/||')) > dist/SHA256SUMS files="$files dist/SHA256SUMS" # The release notes: the CHANGELOG section for this version. notes=$(awk -v v="$VERSION" ' /^## \[/ { if (on) exit; on = index($0, "## [" v "]") == 1; next } on' CHANGELOG.md) [ -n "$notes" ] || notes="See CHANGELOG.md." prerelease=false case $VERSION in *-*) prerelease=true ;; esac # The release (created, or found when publishing again). release=$(call 404 "$api/releases/tags/$tag") id=$(printf '%s\n' "$release" | jq -r '.id // empty') if [ -z "$id" ]; then body=$(jq -n --arg tag "$tag" --arg notes "$notes" --argjson pre "$prerelease" \ '{tag_name: $tag, name: ("Jarl " + $tag), body: $notes, prerelease: $pre}') release=$(call "" -X POST -H 'Content-Type: application/json' -d "$body" "$api/releases") id=$(printf '%s\n' "$release" | jq -r .id) echo "gitea-release: created release $tag" fi for f in $files; do name=${f#dist/} old=$(printf '%s\n' "$release" | jq -r --arg n "$name" '.assets[]? | select(.name == $n) | .id') [ -z "$old" ] || call "" -X DELETE "$api/releases/$id/assets/$old" >/dev/null call "" -X POST -F "attachment=@$f" "$api/releases/$id/assets?name=$name" >/dev/null echo "gitea-release: attached $name" done # The Debian packages. Gitea refuses a package version it already has # (409), so publishing again deletes it first. pool=$GITEA_URL/api/packages/$owner/debian/pool/$DEB_DISTRIBUTION/$DEB_COMPONENT for f in dist/*.deb; do [ -e "$f" ] || continue # shellcheck disable=SC2016,SC2046 # dpkg-deb's fields; split into "$@" set -- $(dpkg-deb --showformat '${Package} ${Version} ${Architecture}' --show "$f") if ! call 409 --upload-file "$f" "$pool/upload" >/dev/null; then echo "gitea-release: upload of $f failed" >&2 exit 1 fi if [ "$code" = 409 ]; then call "" -X DELETE "$pool/$1/$2/$3" >/dev/null call "" --upload-file "$f" "$pool/upload" >/dev/null fi echo "gitea-release: uploaded $1 $2 $3 to $DEB_DISTRIBUTION/$DEB_COMPONENT" done