ci(release): attach the Linux, Arch and Android builds to the release
A release page with nothing to download is one nobody can use. The Arch package and the APK are already built and merely go unattached; the plain Linux binary is new, and is what answers 'get the latest version' without a package manager. scripts/release-asset.sh waits for the release to exist first. semantic-release pushes the tag in prepare and creates the release in publish, so the tag push that starts these workflows happens before there is an id to upload to -- and a capacity-1 runner serialises that into working by accident, which is the worst kind of bug. macOS is absent because it cannot be built here: GOOS=darwin CGO_ENABLED=0 fails at wails/v3/pkg/mac, the darwin backend being Objective-C behind cgo. Homebrew builds from source on the user's Mac and stays the macOS channel. Windows cross-compiles cleanly and is still withheld: no build of it has ever been run. All three skip v0.0.0, which is semantic-release's version floor rather than a shipment.
This commit is contained in:
@@ -129,6 +129,18 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
v="${v#v}"
|
v="${v#v}"
|
||||||
|
|
||||||
|
# v0.0.0 is semantic-release's version floor, not a shipment —
|
||||||
|
# see the bootstrap step in release.yml. It is skipped cleanly
|
||||||
|
# rather than failing the guard below, because a 45-minute red
|
||||||
|
# run against a tag that was never meant to ship is noise, and
|
||||||
|
# this is the most expensive of the three workflows a tag fires.
|
||||||
|
if [ "$v" = "0.0.0" ]; then
|
||||||
|
echo "v0.0.0 is the version floor, not a release; nothing to build"
|
||||||
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
# Android orders releases by an integer and refuses anything
|
# Android orders releases by an integer and refuses anything
|
||||||
# not greater than what is installed. 1.3.1 -> 10301, which
|
# not greater than what is installed. 1.3.1 -> 10301, which
|
||||||
# increases as long as minor and patch stay below 100.
|
# increases as long as minor and patch stay below 100.
|
||||||
@@ -143,9 +155,24 @@ jobs:
|
|||||||
|
|
||||||
echo "version=$v" >> "$GITHUB_OUTPUT"
|
echo "version=$v" >> "$GITHUB_OUTPUT"
|
||||||
echo "code=$code" >> "$GITHUB_OUTPUT"
|
echo "code=$code" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "tag=v$v" >> "$GITHUB_OUTPUT"
|
||||||
echo "building $v (versionCode $code)"
|
echo "building $v (versionCode $code)"
|
||||||
|
|
||||||
|
# Releases restarted at 0.0.1 when they became automatic (plan
|
||||||
|
# 017), so versionCode restarted at 1 — *below* the 10300 an
|
||||||
|
# installed 1.3.0 build carries. Android refuses a downgrade
|
||||||
|
# outright, and the only remedy is an uninstall, which takes the
|
||||||
|
# user's library with it. Said here because this is the file
|
||||||
|
# that computes the number.
|
||||||
|
if [ "$code" -lt 10600 ]; then
|
||||||
|
echo
|
||||||
|
echo "note: versionCode $code is below the 10600 that v1.6.0 shipped."
|
||||||
|
echo " An existing install must be removed before this one will"
|
||||||
|
echo " install, and that removal takes its library with it."
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Go toolchain
|
- name: Go toolchain
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
if [ ! -x /cache/tool/go/bin/go ] || ! /cache/tool/go/bin/go version | grep -q "$GO_VERSION"; then
|
if [ ! -x /cache/tool/go/bin/go ] || ! /cache/tool/go/bin/go version | grep -q "$GO_VERSION"; then
|
||||||
@@ -156,6 +183,7 @@ jobs:
|
|||||||
/cache/tool/go/bin/go version
|
/cache/tool/go/bin/go version
|
||||||
|
|
||||||
- name: Node toolchain
|
- name: Node toolchain
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
||||||
@@ -167,6 +195,7 @@ jobs:
|
|||||||
# but still spends minutes verifying, so the guards are what make
|
# but still spends minutes verifying, so the guards are what make
|
||||||
# this cheap on every run after the first.
|
# this cheap on every run after the first.
|
||||||
- name: Android SDK and NDK (cached)
|
- name: Android SDK and NDK (cached)
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
mkdir -p "$ANDROID_HOME/cmdline-tools"
|
mkdir -p "$ANDROID_HOME/cmdline-tools"
|
||||||
@@ -226,6 +255,7 @@ jobs:
|
|||||||
# that are *verbatim* a secret, so a trimmed one could print in
|
# that are *verbatim* a secret, so a trimmed one could print in
|
||||||
# clear — or repeating the trimming logic in both.
|
# clear — or repeating the trimming logic in both.
|
||||||
- name: Build the signed APK
|
- name: Build the signed APK
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
working-directory: /src
|
working-directory: /src
|
||||||
env:
|
env:
|
||||||
KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }}
|
KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }}
|
||||||
@@ -349,6 +379,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Verify the APK
|
- name: Verify the APK
|
||||||
id: apk
|
id: apk
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
working-directory: /src
|
working-directory: /src
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
@@ -390,6 +421,7 @@ jobs:
|
|||||||
# file, so `latest` is deleted first. Credentials are the same
|
# file, so `latest` is deleted first. Credentials are the same
|
||||||
# OWNER/PACKAGE_TOKEN pair arch-package.yml publishes with.
|
# OWNER/PACKAGE_TOKEN pair arch-package.yml publishes with.
|
||||||
- name: Publish to the Gitea package registry
|
- name: Publish to the Gitea package registry
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
working-directory: /src
|
working-directory: /src
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ steps.version.outputs.version }}
|
VERSION: ${{ steps.version.outputs.version }}
|
||||||
@@ -425,3 +457,18 @@ jobs:
|
|||||||
echo
|
echo
|
||||||
echo "Obtainium URL:"
|
echo "Obtainium URL:"
|
||||||
echo " $base/latest/yellowjacket.apk"
|
echo " $base/latest/yellowjacket.apk"
|
||||||
|
|
||||||
|
# The generic registry is what Obtainium polls; the release page is
|
||||||
|
# what a person looks at. Same file, already built and already
|
||||||
|
# verified by the step above — so this cannot publish something the
|
||||||
|
# signature check would have refused.
|
||||||
|
- name: Attach the APK to the release
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
|
working-directory: /src
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.version.outputs.tag }}
|
||||||
|
VERSION: ${{ steps.version.outputs.version }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
./scripts/release-asset.sh "$TAG" bin/yellowjacket.apk \
|
||||||
|
"yellowjacket-${VERSION}-android-arm64.apk"
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
name: Attach the desktop build to the release
|
||||||
|
|
||||||
|
# The Arch package goes to the pacman registry and the APK to the generic
|
||||||
|
# one, but a release page with nothing on it to download is a release page
|
||||||
|
# nobody can use. This builds the plain Linux x86_64 binary and attaches
|
||||||
|
# it, so "get the latest version" has an answer that needs no package
|
||||||
|
# manager at all.
|
||||||
|
#
|
||||||
|
# **Linux only, and macOS is not an oversight.** `GOOS=darwin
|
||||||
|
# CGO_ENABLED=0` fails at `wails/v3/pkg/mac: build constraints exclude all
|
||||||
|
# Go files` — the darwin backend is Objective-C behind cgo, so a .app
|
||||||
|
# needs a macOS host, and the runner is a Linux container. That is
|
||||||
|
# exactly why the Homebrew formula builds from source on the user's own
|
||||||
|
# Mac, and it stays the macOS channel.
|
||||||
|
#
|
||||||
|
# Windows *does* cross-compile (GOOS=windows CGO_ENABLED=0 succeeds in a
|
||||||
|
# couple of seconds — nothing in the audio, database or webview path needs
|
||||||
|
# cgo there), and is deliberately not published: no Windows build of this
|
||||||
|
# app has ever been run, and no tier here can exercise one. Shipping it
|
||||||
|
# would be a promise nothing in this repo can keep. Revisit when someone
|
||||||
|
# has actually booted it.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ["v*"]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: "Version to build and attach (default: the latest v* tag)"
|
||||||
|
required: false
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: desktop-assets-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ubuntu:24.04
|
||||||
|
volumes:
|
||||||
|
- /home/logan/docker/gitea/data/runner/cache/tool:/cache/tool
|
||||||
|
- /home/logan/docker/gitea/data/runner/cache/pnpm-store:/cache/pnpm-store
|
||||||
|
env:
|
||||||
|
PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }}
|
||||||
|
SERVER_URL: ${{ github.server_url }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
SHA: ${{ github.sha }}
|
||||||
|
REF_NAME: ${{ github.ref_name }}
|
||||||
|
DEBIAN_FRONTEND: noninteractive
|
||||||
|
GO_VERSION: '1.25.0'
|
||||||
|
npm_config_store_dir: /cache/pnpm-store
|
||||||
|
steps:
|
||||||
|
# The same set ci.yml's check job installs: the app is cgo, and
|
||||||
|
# without alsa.pc oto/v3 fails at `pkg-config --cflags -- alsa`
|
||||||
|
# before anything is compiled.
|
||||||
|
- name: System packages
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y -qq --no-install-recommends \
|
||||||
|
ca-certificates curl git jq build-essential pkg-config \
|
||||||
|
libwebkitgtk-6.0-dev libgtk-4-dev libasound2-dev
|
||||||
|
|
||||||
|
- name: Clone repo at this commit
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
git clone --quiet \
|
||||||
|
"https://x-access-token:${PACKAGE_TOKEN}@${SERVER_URL#https://}/${REPO}.git" /src
|
||||||
|
git -C /src checkout --quiet --detach "$SHA"
|
||||||
|
git config --global --add safe.directory /src
|
||||||
|
git -C /src log --oneline -1
|
||||||
|
|
||||||
|
- name: Resolve the version
|
||||||
|
id: version
|
||||||
|
working-directory: /src
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
v="${{ inputs.version }}"
|
||||||
|
if [ -z "$v" ]; then
|
||||||
|
case "$REF_NAME" in
|
||||||
|
v*) v="$REF_NAME" ;;
|
||||||
|
*) v=$(git describe --tags --abbrev=0 --match 'v[0-9]*') ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
case "$v" in v*) ;; *) v="v$v" ;; esac
|
||||||
|
|
||||||
|
# v0.0.0 is semantic-release's version floor, not a shipment —
|
||||||
|
# see the bootstrap step in release.yml. Nothing is built for
|
||||||
|
# it, and this is a clean skip rather than a failure because a
|
||||||
|
# red run against a tag that was never meant to ship is noise.
|
||||||
|
if [ "$v" = "v0.0.0" ]; then
|
||||||
|
echo "v0.0.0 is the version floor, not a release; nothing to build"
|
||||||
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "tag=$v" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "version=${v#v}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "building $v"
|
||||||
|
|
||||||
|
- name: Go toolchain
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
if [ ! -x /cache/tool/go/bin/go ] || ! /cache/tool/go/bin/go version | grep -q "$GO_VERSION"; then
|
||||||
|
mkdir -p /cache/tool && rm -rf /cache/tool/go
|
||||||
|
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar -C /cache/tool -xz
|
||||||
|
fi
|
||||||
|
echo "/cache/tool/go/bin" >> "$GITHUB_PATH"
|
||||||
|
/cache/tool/go/bin/go version
|
||||||
|
|
||||||
|
- name: Node toolchain
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
||||||
|
apt-get install -y -qq --no-install-recommends nodejs
|
||||||
|
corepack enable
|
||||||
|
node --version
|
||||||
|
|
||||||
|
# `make build-prod` is the production task: -trimpath and -w -s are
|
||||||
|
# already in it, so only the version stamp is passed, through the
|
||||||
|
# LDFLAGS_EXTRA variable this repo added to build/linux/Taskfile.yml.
|
||||||
|
# (`wails3 build` has no -ldflags of its own; that was v2.)
|
||||||
|
- name: Build
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
|
working-directory: /src
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.version.outputs.tag }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
export PATH="/src/scripts/toolbin:$PATH"
|
||||||
|
commit=$(git rev-parse --short HEAD)
|
||||||
|
|
||||||
|
go generate ./...
|
||||||
|
go tool wails3 task build \
|
||||||
|
LDFLAGS_EXTRA="-X 'main.version=${TAG}' -X 'main.commit=${commit}'"
|
||||||
|
|
||||||
|
# Described, never run: main.go has no flag parsing, so any
|
||||||
|
# invocation here would try to open a window in a container with
|
||||||
|
# no display and hang the job rather than printing a version.
|
||||||
|
test -x bin/yellowjacket
|
||||||
|
ls -la bin/yellowjacket
|
||||||
|
file bin/yellowjacket || true
|
||||||
|
|
||||||
|
# The .desktop file and the icon go in the tarball because without
|
||||||
|
# them the binary is a window with no menu entry — the Arch package
|
||||||
|
# installs both, and this is the same app for people not using it.
|
||||||
|
- name: Package the tarball
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
|
working-directory: /src
|
||||||
|
env:
|
||||||
|
VERSION: ${{ steps.version.outputs.version }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
dir="yellowjacket-${VERSION}-linux-amd64"
|
||||||
|
mkdir -p "/tmp/$dir"
|
||||||
|
cp bin/yellowjacket "/tmp/$dir/"
|
||||||
|
cp packaging/arch/yellowjacket.desktop "/tmp/$dir/"
|
||||||
|
cp frontend/src/assets/images/icons/music/compact-disc.svg \
|
||||||
|
"/tmp/$dir/yellowjacket.svg"
|
||||||
|
tar -C /tmp -czf "/tmp/${dir}.tar.gz" "$dir"
|
||||||
|
ls -la "/tmp/${dir}.tar.gz"
|
||||||
|
|
||||||
|
- name: Attach it to the release
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
|
working-directory: /src
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.version.outputs.tag }}
|
||||||
|
VERSION: ${{ steps.version.outputs.version }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
./scripts/release-asset.sh "$TAG" \
|
||||||
|
"/tmp/yellowjacket-${VERSION}-linux-amd64.tar.gz"
|
||||||
@@ -14,6 +14,15 @@ on:
|
|||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "v*"
|
- "v*"
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: "Version to sync (default: the pushed tag)"
|
||||||
|
required: false
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: homebrew-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
sync-formula:
|
sync-formula:
|
||||||
@@ -30,10 +39,25 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Compute version and tarball checksum
|
- name: Compute version and tarball checksum
|
||||||
|
id: version
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
TAG="${GITHUB_REF_NAME}" # e.g. v1.3.0
|
TAG="${{ inputs.version }}"
|
||||||
VERSION="${TAG#v}" # e.g. 1.3.0
|
[ -n "$TAG" ] || TAG="${GITHUB_REF_NAME}" # e.g. v0.0.1
|
||||||
|
case "$TAG" in v*) ;; *) TAG="v$TAG" ;; esac
|
||||||
|
VERSION="${TAG#v}" # e.g. 0.0.1
|
||||||
|
|
||||||
|
# v0.0.0 is semantic-release's version floor, not a shipment —
|
||||||
|
# see the bootstrap step in release.yml. Skipped cleanly rather
|
||||||
|
# than failing: this one would otherwise push a formula for a
|
||||||
|
# version that does not exist into a *public* tap.
|
||||||
|
if [ "$VERSION" = "0.0.0" ]; then
|
||||||
|
echo "v0.0.0 is the version floor, not a release; nothing to sync"
|
||||||
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
TARBALL="${SOURCE_TARBALL_BASE}/${TAG}.tar.gz"
|
TARBALL="${SOURCE_TARBALL_BASE}/${TAG}.tar.gz"
|
||||||
|
|
||||||
echo "Fetching ${TARBALL}"
|
echo "Fetching ${TARBALL}"
|
||||||
@@ -53,6 +77,7 @@ jobs:
|
|||||||
echo "SHA256=${SHA256}" >> "$GITHUB_ENV"
|
echo "SHA256=${SHA256}" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Render the formula with the new version and checksum
|
- name: Render the formula with the new version and checksum
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
src="packaging/homebrew/Formula/yellowjacket.rb"
|
src="packaging/homebrew/Formula/yellowjacket.rb"
|
||||||
@@ -66,6 +91,7 @@ jobs:
|
|||||||
cat yellowjacket.rb
|
cat yellowjacket.rb
|
||||||
|
|
||||||
- name: Push to the Homebrew tap repo
|
- name: Push to the Homebrew tap repo
|
||||||
|
if: steps.version.outputs.skip == 'false'
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
git clone "https://x-access-token:${TAP_TOKEN}@github.com/${TAP_REPO}.git" tap
|
git clone "https://x-access-token:${TAP_TOKEN}@github.com/${TAP_REPO}.git" tap
|
||||||
|
|||||||
Executable
+88
@@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Attach a built artifact to the Gitea release for a tag.
|
||||||
|
#
|
||||||
|
# **It waits for the release to exist, and that is the point of the
|
||||||
|
# file.** semantic-release pushes the tag in its `prepare` step and
|
||||||
|
# creates the release object in `publish` — so the tag push, which is
|
||||||
|
# what starts every publishing workflow, happens *before* there is a
|
||||||
|
# release id to upload to. A fast publisher can therefore arrive first.
|
||||||
|
#
|
||||||
|
# The runner has capacity 1, which serialises things enough that this
|
||||||
|
# would usually work by accident; that is the worst kind of bug, so the
|
||||||
|
# wait is explicit and a timeout is a loud failure rather than a silently
|
||||||
|
# skipped asset.
|
||||||
|
#
|
||||||
|
# Usage: scripts/release-asset.sh <tag> <file> [upload-name]
|
||||||
|
#
|
||||||
|
# Environment:
|
||||||
|
# SERVER_URL https://git.ljones.me
|
||||||
|
# REPO yonlu/yellowjacket
|
||||||
|
# PACKAGE_TOKEN a user PAT with write access
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
tag="${1:?usage: release-asset.sh <tag> <file> [name]}"
|
||||||
|
file="${2:?usage: release-asset.sh <tag> <file> [name]}"
|
||||||
|
name="${3:-$(basename "$file")}"
|
||||||
|
|
||||||
|
: "${SERVER_URL:?SERVER_URL is not set}"
|
||||||
|
: "${REPO:?REPO is not set}"
|
||||||
|
: "${PACKAGE_TOKEN:?PACKAGE_TOKEN is not set}"
|
||||||
|
|
||||||
|
[ -s "$file" ] || { echo "release-asset: $file is missing or empty" >&2; exit 1; }
|
||||||
|
|
||||||
|
auth="Authorization: token ${PACKAGE_TOKEN}"
|
||||||
|
api="${SERVER_URL}/api/v1/repos/${REPO}"
|
||||||
|
|
||||||
|
# Up to five minutes. A release that has not appeared by then means the
|
||||||
|
# release job failed, and this should say so rather than time out quietly.
|
||||||
|
release_id=""
|
||||||
|
for attempt in $(seq 1 60); do
|
||||||
|
release_id=$(curl -sS -H "$auth" "${api}/releases/tags/${tag}" |
|
||||||
|
jq -r 'if type == "object" and has("id") then .id else empty end')
|
||||||
|
|
||||||
|
if [ -n "$release_id" ]; then
|
||||||
|
echo "release-asset: release for $tag is id $release_id (after ${attempt} check(s))"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$attempt" -eq 1 ] && echo "release-asset: waiting for the release for $tag to be created"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$release_id" ]; then
|
||||||
|
echo "release-asset: no release for $tag after 5 minutes." >&2
|
||||||
|
echo " The tag is pushed in semantic-release's prepare step and the release" >&2
|
||||||
|
echo " is created in publish, so this means the release job did not get that" >&2
|
||||||
|
echo " far. Check the run of release.yml for this commit." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Gitea refuses a duplicate asset name rather than replacing it, so a
|
||||||
|
# re-run of the same tag deletes the old one first. That keeps a manual
|
||||||
|
# workflow_dispatch rebuild idempotent, which is the only reason anyone
|
||||||
|
# re-runs one of these.
|
||||||
|
existing=$(curl -sS -H "$auth" "${api}/releases/${release_id}/assets" |
|
||||||
|
jq -r --arg n "$name" '.[]? | select(.name == $n) | .id')
|
||||||
|
|
||||||
|
if [ -n "$existing" ]; then
|
||||||
|
echo "release-asset: replacing the existing '$name' (asset $existing)"
|
||||||
|
curl -sS -o /dev/null -H "$auth" -X DELETE \
|
||||||
|
"${api}/releases/${release_id}/assets/${existing}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "release-asset: uploading $name ($(du -h "$file" | cut -f1))"
|
||||||
|
|
||||||
|
code=$(curl -sS -o /tmp/release-asset.out -w '%{http_code}' \
|
||||||
|
-H "$auth" \
|
||||||
|
-X POST \
|
||||||
|
-F "attachment=@${file};filename=${name}" \
|
||||||
|
"${api}/releases/${release_id}/assets?name=${name}")
|
||||||
|
|
||||||
|
if [ "$code" != "201" ]; then
|
||||||
|
echo "release-asset: upload returned $code" >&2
|
||||||
|
cat /tmp/release-asset.out >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "release-asset: attached $name to $tag"
|
||||||
Reference in New Issue
Block a user