| @@ -5,8 +5,26 @@ |
| 5 | 5 | # |
| 6 | 6 | # appimagetool is used from $PATH if present, otherwise downloaded once into |
| 7 | 7 | # build/.tools. Set APPIMAGETOOL=/path/to/appimagetool to use a specific one. |
| 8 | + # |
| 9 | + # ./build.sh --release (or -r) then publishes them as a release on Vectrum: |
| 10 | + # it tags the commit with the version in Cargo.toml, pushes the tag, and |
| 11 | + # uploads the AppImage, the binary and SHA256SUMS (the first upload |
| 12 | + # publishes the release). Bump the version in Cargo.toml for each release. |
| 13 | + # VECTRUM_TOKEN a read & write API token (vec_…); otherwise read from |
| 14 | + # ~/.config/vectrum/token (or $VECTRUM_TOKEN_FILE) |
| 15 | + # VECTRUM_URL the server, https://vectrum.cc by default |
| 16 | + # VECTRUM_REPO owner/repo, taken from the origin remote by default |
| 8 | 17 | set -euo pipefail |
| 9 | 18 | |
| 19 | + RELEASE=0 |
| 20 | + for arg in "$@"; do |
| 21 | + case "$arg" in |
| 22 | + -r|--release) RELEASE=1 ;; |
| 23 | + -h|--help) sed -n '2,/^set -euo/p' "$0" | sed '$d; s/^# \{0,1\}//'; exit 0 ;; |
| 24 | + *) printf 'Unknown option: %s (try --help)\n' "$arg" >&2; exit 2 ;; |
| 25 | + esac |
| 26 | + done |
| 27 | + |
| 10 | 28 | ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 11 | 29 | BUILD="$ROOT/build" |
| 12 | 30 | TOOLS="$BUILD/.tools" |
| @@ -18,6 +36,32 @@ VERSION="$(sed -n 's/^version *= *"\(.*\)"/\1/p' "$ROOT/Cargo.toml" | head -n1)" |
| 18 | 36 | ARCH="$(uname -m)" |
| 19 | 37 | |
| 20 | 38 | log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; } |
| 39 | + die() { printf '\033[1;31mxx\033[0m %s\n' "$*" >&2; exit 1; } |
| 40 | + |
| 41 | + # ── 0. Release checks, before spending time on a build ─────────────────────── |
| 42 | + if (( RELEASE )); then |
| 43 | + TAG="$VERSION" |
| 44 | + SERVER="${VECTRUM_URL:-https://vectrum.cc}" |
| 45 | + SERVER="${SERVER%/}" |
| 46 | + TOKEN_FILE="${VECTRUM_TOKEN_FILE:-$HOME/.config/vectrum/token}" |
| 47 | + TOKEN="${VECTRUM_TOKEN:-}" |
| 48 | + if [[ -z "$TOKEN" && -r "$TOKEN_FILE" ]]; then |
| 49 | + TOKEN="$(tr -d '[:space:]' < "$TOKEN_FILE")" |
| 50 | + fi |
| 51 | + [[ -n "$TOKEN" ]] || die "No API token: set VECTRUM_TOKEN or save a read & write token to $TOKEN_FILE" |
| 52 | + # ssh://git@git.vectrum.cc:2222/vectrum/code.git, https://…/vectrum/code → vectrum/code |
| 53 | + REPO="${VECTRUM_REPO:-$(git -C "$ROOT" remote get-url origin | sed -E 's#\.git$##; s#^.*[:/]([^/:]+/[^/:]+)$#\1#')}" |
| 54 | + [[ "$REPO" == */* ]] || die "Couldn't tell the repository from the origin remote; set VECTRUM_REPO=owner/repo" |
| 55 | + [[ -z "$(git -C "$ROOT" status --porcelain)" ]] || die "Commit or stash your changes first: a release is built from a commit" |
| 56 | + HEAD="$(git -C "$ROOT" rev-parse HEAD)" |
| 57 | + REMOTE_TAG="$(git -C "$ROOT" ls-remote origin "refs/tags/$TAG^{}" "refs/tags/$TAG" | awk 'NR==1 || /\^\{\}$/ {sha=$1} END {print sha}')" |
| 58 | + LOCAL_TAG="$(git -C "$ROOT" rev-parse -q --verify "refs/tags/$TAG^{commit}" || true)" |
| 59 | + for tagged in "$REMOTE_TAG" "$LOCAL_TAG"; do |
| 60 | + [[ -z "$tagged" || "$tagged" == "$HEAD" ]] || |
| 61 | + die "$TAG is already tagged at ${tagged:0:7}; bump the version in Cargo.toml for a new release" |
| 62 | + done |
| 63 | + log "Releasing $TAG of $REPO on $SERVER from ${HEAD:0:7}" |
| 64 | + fi |
| 21 | 65 | |
| 22 | 66 | # ── 1. Binary ──────────────────────────────────────────────────────────────── |
| 23 | 67 | log "Building $NAME $VERSION (release, $ARCH)" |
| @@ -84,3 +128,32 @@ APPIMAGE_EXTRACT_AND_RUN=1 ARCH="$ARCH" "$APPIMAGETOOL" --no-appstream "$APPDIR" |
| 84 | 128 | rm -rf "$APPDIR" |
| 85 | 129 | |
| 86 | 130 | log "AppImage: ${OUT#"$ROOT"/}" |
| 131 | + |
| 132 | + # ── 5. Release ─────────────────────────────────────────────────────────────── |
| 133 | + if (( RELEASE )); then |
| 134 | + STAGE="$BUILD/release-$TAG" |
| 135 | + rm -rf "$STAGE" |
| 136 | + mkdir -p "$STAGE" |
| 137 | + cp "$OUT" "$STAGE/" |
| 138 | + cp "$BUILD/$NAME" "$STAGE/$NAME-$VERSION-$ARCH" |
| 139 | + (cd "$STAGE" && sha256sum -- * > SHA256SUMS) |
| 140 | + |
| 141 | + if [[ -z "$LOCAL_TAG" ]]; then |
| 142 | + git -C "$ROOT" tag -a "$TAG" -m "$PRETTY $VERSION" "$HEAD" |
| 143 | + fi |
| 144 | + if [[ -z "$REMOTE_TAG" ]]; then |
| 145 | + log "Pushing tag $TAG" |
| 146 | + git -C "$ROOT" push -q origin "refs/tags/$TAG" |
| 147 | + fi |
| 148 | + |
| 149 | + for file in "$STAGE"/*; do |
| 150 | + name="$(basename "$file")" |
| 151 | + log "Uploading $name" |
| 152 | + # The token goes in through a file descriptor, so it never shows in ps. |
| 153 | + if ! reply="$(curl -sS --fail-with-body -T "$file" -H @<(printf 'Authorization: Bearer %s\n' "$TOKEN") \ |
| 154 | + "$SERVER/$REPO/releases/download/$TAG/$name")"; then |
| 155 | + die "Uploading $name failed: $reply" |
| 156 | + fi |
| 157 | + done |
| 158 | + log "Released: $SERVER/$REPO/releases/tag/$TAG" |
| 159 | + fi |