Files
warmbly/scripts/build-cli.sh
T

191 lines
6.0 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Builds the `warmbly` CLI for every platform we publish, packages each one,
# and writes the manifests the package managers read.
#
# Run by the release workflow and by `make cli-dist`, so a release artifact can
# be reproduced locally byte for byte given the same VERSION and COMMIT.
#
# ./scripts/build-cli.sh dist
#
# Assets are named without the version on purpose: the install script resolves
# https://github.com/warmbly/warmbly/releases/latest/download/warmbly_<os>_<arch>.tar.gz
# with no GitHub API call, and the unauthenticated API's rate limit is exactly
# what breaks a curl installer on a shared CI runner.
set -euo pipefail
cd "$(dirname "$0")/.."
OUT=${1:-dist}
REPO=warmbly/warmbly
MODULE=github.com/warmbly/warmbly
VERSION=${VERSION:-$(git describe --tags --always --dirty 2>/dev/null || echo dev)}
COMMIT=${COMMIT:-$(git rev-parse HEAD 2>/dev/null || echo "")}
BUILT_AT=${BUILT_AT:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}
# Every platform the install script and the package managers know how to ask
# for. Keep this list and the one in site/public/cli.sh in step; the installer
# check verifies they agree.
PLATFORMS="darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 windows/amd64 windows/arm64"
LDFLAGS="-s -w
-X ${MODULE}/internal/version.Version=${VERSION}
-X ${MODULE}/internal/version.Commit=${COMMIT}
-X ${MODULE}/internal/version.BuiltAt=${BUILT_AT}"
# macOS ships shasum and not GNU sha256sum, and this script is meant to be
# reproducible on a maintainer's laptop as well as on the release runner.
sha256_all() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$@"
else
shasum -a 256 "$@"
fi
}
rm -rf "$OUT"
mkdir -p "$OUT"
# Completions ship inside every archive so the install script can drop them in
# without running the binary it just downloaded, which it cannot do for a
# cross-platform install anyway.
stage_completions() {
local host_bin=$1 dest=$2
mkdir -p "$dest"
for shell in bash zsh fish powershell; do
"$host_bin" completion "$shell" > "$dest/warmbly.$shell" 2>/dev/null || true
done
}
echo "building warmbly ${VERSION}"
host_bin="$OUT/.host/warmbly"
mkdir -p "$OUT/.host"
# shellcheck disable=SC2086
go build -ldflags="$LDFLAGS" -o "$host_bin" ./cmd/cli
completions="$OUT/.completions"
stage_completions "$host_bin" "$completions"
for target in $PLATFORMS; do
os=${target%/*}
arch=${target#*/}
ext=""
if [ "$os" = "windows" ]; then ext=".exe"; fi
stage="$OUT/.stage/warmbly_${os}_${arch}"
mkdir -p "$stage"
echo " $os/$arch"
# shellcheck disable=SC2086
CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" \
go build -ldflags="$LDFLAGS" -o "$stage/warmbly${ext}" ./cmd/cli
cp LICENSE README.md "$stage/"
cp -r "$completions" "$stage/completions"
if [ "$os" = "windows" ]; then
(cd "$stage" && zip -qr "../../warmbly_${os}_${arch}.zip" .)
else
tar -czf "$OUT/warmbly_${os}_${arch}.tar.gz" -C "$stage" .
fi
done
rm -rf "$OUT/.stage" "$OUT/.host" "$OUT/.completions"
(cd "$OUT" && sha256_all warmbly_* > checksums.txt)
echo
cat "$OUT/checksums.txt"
# ─────────────────────────────────────────────────────────────────────────
# Package manager manifests
#
# Written here rather than by hand so the checksums in them can never drift
# from the archives they describe, which is the failure mode that makes a tap
# install fail for everyone at once.
# ─────────────────────────────────────────────────────────────────────────
sum_for() { awk -v f="$1" '$2 == f { print $1 }' "$OUT/checksums.txt"; }
BASE="https://github.com/${REPO}/releases/download/${VERSION}"
cat > "$OUT/warmbly.rb" <<EOF
# Homebrew formula for the Warmbly CLI. Generated by scripts/build-cli.sh;
# the release workflow pushes it to the warmbly/homebrew-tap repository.
class Warmbly < Formula
desc "Warmbly from the command line: campaigns, contacts, mailboxes, inbox"
homepage "https://warmbly.com"
version "${VERSION#v}"
license "Apache-2.0"
on_macos do
on_intel do
url "${BASE}/warmbly_darwin_amd64.tar.gz"
sha256 "$(sum_for warmbly_darwin_amd64.tar.gz)"
end
on_arm do
url "${BASE}/warmbly_darwin_arm64.tar.gz"
sha256 "$(sum_for warmbly_darwin_arm64.tar.gz)"
end
end
on_linux do
on_intel do
url "${BASE}/warmbly_linux_amd64.tar.gz"
sha256 "$(sum_for warmbly_linux_amd64.tar.gz)"
end
on_arm do
url "${BASE}/warmbly_linux_arm64.tar.gz"
sha256 "$(sum_for warmbly_linux_arm64.tar.gz)"
end
end
def install
bin.install "warmbly"
bash_completion.install "completions/warmbly.bash" => "warmbly"
zsh_completion.install "completions/warmbly.zsh" => "_warmbly"
fish_completion.install "completions/warmbly.fish" => "warmbly.fish"
end
test do
assert_match "warmbly", shell_output("#{bin}/warmbly version")
end
end
EOF
cat > "$OUT/warmbly.json" <<EOF
{
"version": "${VERSION#v}",
"description": "Warmbly from the command line: campaigns, contacts, mailboxes, inbox",
"homepage": "https://warmbly.com",
"license": "Apache-2.0",
"architecture": {
"64bit": {
"url": "${BASE}/warmbly_windows_amd64.zip",
"hash": "$(sum_for warmbly_windows_amd64.zip)"
},
"arm64": {
"url": "${BASE}/warmbly_windows_arm64.zip",
"hash": "$(sum_for warmbly_windows_arm64.zip)"
}
},
"bin": "warmbly.exe",
"checkver": {
"github": "https://github.com/${REPO}"
},
"autoupdate": {
"architecture": {
"64bit": {
"url": "https://github.com/${REPO}/releases/download/v\$version/warmbly_windows_amd64.zip"
},
"arm64": {
"url": "https://github.com/${REPO}/releases/download/v\$version/warmbly_windows_arm64.zip"
}
}
}
}
EOF
echo
echo "wrote $OUT/ (archives, checksums.txt, warmbly.rb, warmbly.json)"