TNT/scripts/package_release_assets.sh

150 lines
4 KiB
Bash
Executable file

#!/bin/sh
# Collect release workflow artifacts into one flat, checksum-verified bundle.
set -eu
usage() {
cat <<'USAGE'
Usage: scripts/package_release_assets.sh ARTIFACT_ROOT [OUT_DIR]
ARTIFACT_ROOT is the directory produced by actions/download-artifact.
OUT_DIR defaults to dist/release-assets.
The script validates the expected release asset names, verifies binary
architecture labels, verifies the source archive shape, writes checksums.txt,
and verifies that checksums.txt matches the assembled bundle. It never
publishes a release.
USAGE
}
fail() {
echo "release-artifact-gate: $*" >&2
exit 1
}
sha256_of() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$1" | awk '{print $1}'
else
fail "sha256sum or shasum is required"
fi
}
find_unique() {
name=$1
matches=$(find "$ARTIFACT_ROOT" -type f -name "$name" -print)
count=$(printf '%s\n' "$matches" | sed '/^$/d' | wc -l | tr -d ' ')
[ "$count" = "1" ] ||
fail "expected exactly one artifact named $name, found $count"
printf '%s\n' "$matches"
}
require_file_label() {
path=$1
pattern=$2
label=$(file "$path")
printf '%s\n' "$label" | grep -E "$pattern" >/dev/null ||
fail "unexpected file type for $(basename "$path"): $label"
}
verify_asset() {
name=$1
path=$2
[ -s "$path" ] || fail "empty artifact: $name"
case "$name" in
tnt-linux-amd64|tntctl-linux-amd64)
require_file_label "$path" 'ELF 64-bit.*x86-64'
;;
tnt-linux-arm64|tntctl-linux-arm64)
require_file_label "$path" 'ELF 64-bit.*(aarch64|ARM aarch64)'
;;
tnt-darwin-amd64|tntctl-darwin-amd64)
require_file_label "$path" 'Mach-O 64-bit.*x86_64'
;;
tnt-darwin-arm64|tntctl-darwin-arm64)
require_file_label "$path" 'Mach-O 64-bit.*arm64'
;;
tnt-chat-v*-source.tar.gz)
tar -tzf "$path" >/dev/null
tar -tzf "$path" | grep -q "^TNT-$VERSION/LICENSE$" ||
fail "source archive is missing LICENSE"
tar -tzf "$path" | grep -q "^TNT-$VERSION/src/tntctl.c$" ||
fail "source archive is missing src/tntctl.c"
tar -tzf "$path" | grep -q "^TNT-$VERSION/packaging/README.md$" ||
fail "source archive is missing packaging/README.md"
;;
*)
fail "unexpected release artifact: $name"
;;
esac
}
[ "${1:-}" != "-h" ] && [ "${1:-}" != "--help" ] || {
usage
exit 0
}
ARTIFACT_ROOT=${1:-}
OUT_DIR=${2:-dist/release-assets}
[ -n "$ARTIFACT_ROOT" ] || {
usage >&2
exit 2
}
[ -d "$ARTIFACT_ROOT" ] || fail "ARTIFACT_ROOT does not exist: $ARTIFACT_ROOT"
ARTIFACT_ROOT=$(CDPATH= cd -- "$ARTIFACT_ROOT" && pwd)
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$ROOT"
case "$OUT_DIR" in
/*) ;;
*) OUT_DIR="$ROOT/$OUT_DIR" ;;
esac
VERSION=$(sed -n 's/^#define TNT_VERSION "\([^"]*\)".*/\1/p' include/common.h)
[ -n "$VERSION" ] || fail "could not read TNT_VERSION"
SOURCE_ASSET="tnt-chat-v$VERSION-source.tar.gz"
EXPECTED_ASSETS="
tnt-linux-amd64
tntctl-linux-amd64
tnt-linux-arm64
tntctl-linux-arm64
tnt-darwin-amd64
tntctl-darwin-amd64
tnt-darwin-arm64
tntctl-darwin-arm64
$SOURCE_ASSET
"
mkdir -p "$OUT_DIR"
for name in $EXPECTED_ASSETS; do
dst="$OUT_DIR/$name"
[ ! -e "$dst" ] || fail "output already exists: $dst"
src=$(find_unique "$name")
verify_asset "$name" "$src"
cp "$src" "$dst"
done
(
cd "$OUT_DIR"
: > checksums.txt
for name in $EXPECTED_ASSETS; do
printf '%s %s\n' "$(sha256_of "$name")" "$name" >> checksums.txt
done
while read -r expected name; do
[ -n "$expected" ] || continue
actual=$(sha256_of "$name")
[ "$actual" = "$expected" ] ||
fail "checksum mismatch for $name"
done < checksums.txt
)
echo "release artifact bundle ready: $OUT_DIR"