Some checks failed
Cache: Publish Nix / Publish Nix Cache (push) Waiting to run
Build Rust / Cargo Test (push) Successful in 4m14s
Build Site / Next.js Build (push) Failing after 6s
Infra: OpenTofu / OpenTofu (grafana) (push) Successful in 5s
Lint Governance / BEP Metadata (push) Successful in 0s
Build: Android / Android Rust Core Stub (push) Failing after 23s
332 lines
11 KiB
Bash
Executable file
332 lines
11 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
repo_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
cd "${repo_root}"
|
|
|
|
platform="${1:-all}"
|
|
build_number="${BUILD_NUMBER:-${RELEASE_BUILD_NUMBER:-${RELEASE_REF:-manual}}}"
|
|
out_root="${BURROW_RELEASE_OUT:-${repo_root}/dist/builds/${build_number}}"
|
|
|
|
mkdir -p "${out_root}"
|
|
|
|
sha256_file() {
|
|
local file="$1"
|
|
if command -v shasum >/dev/null 2>&1; then
|
|
shasum -a 256 "$file" > "${file}.sha256"
|
|
else
|
|
sha256sum "$file" > "${file}.sha256"
|
|
fi
|
|
}
|
|
|
|
burrow_crate_version() {
|
|
awk -F '"' '/^version = / { print $2; exit }' burrow/Cargo.toml
|
|
}
|
|
|
|
package_release_suffix() {
|
|
printf '%s' "$build_number" | tr -c 'A-Za-z0-9.+~' '.'
|
|
}
|
|
|
|
arch_package_suffix() {
|
|
printf '%s' "$build_number" | tr -c 'A-Za-z0-9.+_' '.'
|
|
}
|
|
|
|
deb_arch_for_target() {
|
|
case "$1" in
|
|
x86_64-unknown-linux-gnu) printf 'amd64' ;;
|
|
aarch64-unknown-linux-gnu) printf 'arm64' ;;
|
|
riscv64gc-unknown-linux-gnu) printf 'riscv64' ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
rpm_arch_for_target() {
|
|
case "$1" in
|
|
x86_64-unknown-linux-gnu) printf 'x86_64' ;;
|
|
aarch64-unknown-linux-gnu) printf 'aarch64' ;;
|
|
riscv64gc-unknown-linux-gnu) printf 'riscv64' ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
pacman_arch_for_target() {
|
|
case "$1" in
|
|
x86_64-unknown-linux-gnu) printf 'x86_64' ;;
|
|
aarch64-unknown-linux-gnu) printf 'aarch64' ;;
|
|
riscv64gc-unknown-linux-gnu) printf 'riscv64' ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
copy_license_readme() {
|
|
local dst="$1"
|
|
cp README.md "$dst/README.md"
|
|
if [[ -f LICENSE ]]; then
|
|
cp LICENSE "$dst/LICENSE"
|
|
elif [[ -f LICENSE.md ]]; then
|
|
cp LICENSE.md "$dst/LICENSE.md"
|
|
fi
|
|
}
|
|
|
|
package_deb() {
|
|
local target binary deb_arch pkg_version suffix staging deb_file installed_size
|
|
target="$1"
|
|
binary="$2"
|
|
if ! deb_arch="$(deb_arch_for_target "$target")"; then
|
|
echo "warning: no Debian architecture mapping for ${target}; skipping .deb package" >&2
|
|
return 0
|
|
fi
|
|
if ! command -v dpkg-deb >/dev/null 2>&1; then
|
|
echo "warning: dpkg-deb is not available; skipping .deb package" >&2
|
|
return 0
|
|
fi
|
|
|
|
suffix="$(package_release_suffix)"
|
|
pkg_version="${BURROW_PACKAGE_VERSION:-$(burrow_crate_version)+${suffix}}"
|
|
staging="${out_root}/linux/pkg-deb/burrow_${pkg_version}_${deb_arch}"
|
|
rm -rf "$staging"
|
|
mkdir -p \
|
|
"$staging/DEBIAN" \
|
|
"$staging/usr/bin" \
|
|
"$staging/usr/lib/systemd/system" \
|
|
"$staging/usr/share/doc/burrow" \
|
|
"$staging/usr/share/licenses/burrow"
|
|
|
|
install -m 0755 "$binary" "$staging/usr/bin/burrow"
|
|
install -m 0644 systemd/burrow.service "$staging/usr/lib/systemd/system/burrow.service"
|
|
install -m 0644 systemd/burrow.socket "$staging/usr/lib/systemd/system/burrow.socket"
|
|
install -m 0644 README.md "$staging/usr/share/doc/burrow/README.md"
|
|
install -m 0644 LICENSE.md "$staging/usr/share/licenses/burrow/LICENSE.md"
|
|
installed_size="$(du -sk "$staging/usr" | awk '{ print $1 }')"
|
|
|
|
cat > "$staging/DEBIAN/control" <<EOF
|
|
Package: burrow
|
|
Version: ${pkg_version}
|
|
Section: net
|
|
Priority: optional
|
|
Architecture: ${deb_arch}
|
|
Maintainer: Burrow Release Automation <packages@burrow.net>
|
|
Installed-Size: ${installed_size}
|
|
Depends: systemd
|
|
Description: Burrow VPN daemon and CLI
|
|
Burrow installs the daemon entrypoint and systemd socket used by the desktop UI.
|
|
EOF
|
|
|
|
deb_file="${out_root}/linux/burrow_${pkg_version}_${deb_arch}.deb"
|
|
dpkg-deb --build --root-owner-group "$staging" "$deb_file"
|
|
sha256_file "$deb_file"
|
|
}
|
|
|
|
package_rpm() {
|
|
local target binary rpm_arch
|
|
target="$1"
|
|
binary="$2"
|
|
if ! rpm_arch="$(rpm_arch_for_target "$target")"; then
|
|
echo "warning: no RPM architecture mapping for ${target}; skipping .rpm package" >&2
|
|
return 0
|
|
fi
|
|
if ! command -v cargo-generate-rpm >/dev/null 2>&1; then
|
|
echo "warning: cargo-generate-rpm is not available; skipping .rpm package" >&2
|
|
return 0
|
|
fi
|
|
|
|
mkdir -p target/release
|
|
cp "$binary" target/release/burrow
|
|
if cargo generate-rpm -p burrow; then
|
|
find target/generate-rpm -type f -name '*.rpm' -exec cp {} "${out_root}/linux/" \; 2>/dev/null || true
|
|
find "${out_root}/linux" -maxdepth 1 -type f -name '*.rpm' -print | while read -r rpm; do
|
|
sha256_file "$rpm"
|
|
done
|
|
else
|
|
echo "warning: cargo-generate-rpm failed for ${rpm_arch}; skipping .rpm package" >&2
|
|
fi
|
|
}
|
|
|
|
package_pacman() {
|
|
local target binary pacman_arch pkg_version pkgrel work source_sum service_sum socket_sum readme_sum license_sum
|
|
target="$1"
|
|
binary="$2"
|
|
if ! pacman_arch="$(pacman_arch_for_target "$target")"; then
|
|
echo "warning: no pacman architecture mapping for ${target}; skipping Arch package" >&2
|
|
return 0
|
|
fi
|
|
if ! command -v makepkg >/dev/null 2>&1; then
|
|
echo "warning: makepkg is not available; skipping Arch package" >&2
|
|
return 0
|
|
fi
|
|
|
|
pkg_version="${BURROW_ARCH_PKGVER:-$(burrow_crate_version)_$(arch_package_suffix)}"
|
|
pkgrel="${BURROW_ARCH_PKGREL:-1}"
|
|
work="${out_root}/linux/pkg-arch/${pacman_arch}"
|
|
rm -rf "$work"
|
|
mkdir -p "$work"
|
|
install -m 0755 "$binary" "$work/burrow"
|
|
install -m 0644 systemd/burrow.service "$work/burrow.service"
|
|
install -m 0644 systemd/burrow.socket "$work/burrow.socket"
|
|
install -m 0644 README.md "$work/README.md"
|
|
install -m 0644 LICENSE.md "$work/LICENSE.md"
|
|
|
|
source_sum="$(sha256sum "$work/burrow" | awk '{ print $1 }')"
|
|
service_sum="$(sha256sum "$work/burrow.service" | awk '{ print $1 }')"
|
|
socket_sum="$(sha256sum "$work/burrow.socket" | awk '{ print $1 }')"
|
|
readme_sum="$(sha256sum "$work/README.md" | awk '{ print $1 }')"
|
|
license_sum="$(sha256sum "$work/LICENSE.md" | awk '{ print $1 }')"
|
|
|
|
cat > "$work/PKGBUILD" <<EOF
|
|
# Maintainer: Burrow Release Automation <packages@burrow.net>
|
|
pkgname=burrow
|
|
pkgver=${pkg_version}
|
|
pkgrel=${pkgrel}
|
|
pkgdesc="Burrow VPN daemon and CLI"
|
|
arch=("${pacman_arch}")
|
|
url="https://git.burrow.net/hackclub/burrow"
|
|
license=("GPL-3.0-or-later")
|
|
depends=("systemd")
|
|
source=("burrow" "burrow.service" "burrow.socket" "README.md" "LICENSE.md")
|
|
sha256sums=("${source_sum}" "${service_sum}" "${socket_sum}" "${readme_sum}" "${license_sum}")
|
|
|
|
package() {
|
|
install -Dm755 "\${srcdir}/burrow" "\${pkgdir}/usr/bin/burrow"
|
|
install -Dm644 "\${srcdir}/burrow.service" "\${pkgdir}/usr/lib/systemd/system/burrow.service"
|
|
install -Dm644 "\${srcdir}/burrow.socket" "\${pkgdir}/usr/lib/systemd/system/burrow.socket"
|
|
install -Dm644 "\${srcdir}/README.md" "\${pkgdir}/usr/share/doc/burrow/README.md"
|
|
install -Dm644 "\${srcdir}/LICENSE.md" "\${pkgdir}/usr/share/licenses/burrow/LICENSE.md"
|
|
}
|
|
EOF
|
|
|
|
(
|
|
cd "$work"
|
|
makepkg --force --nodeps --noconfirm
|
|
)
|
|
find "$work" -maxdepth 1 -type f -name '*.pkg.tar.*' -exec cp {} "${out_root}/linux/" \;
|
|
find "${out_root}/linux" -maxdepth 1 -type f -name '*.pkg.tar.*' -print | while read -r package; do
|
|
sha256_file "$package"
|
|
done
|
|
}
|
|
|
|
package_linux() {
|
|
local target host archive staging
|
|
host="$(rustc -vV | awk '/^host:/ { print $2 }')"
|
|
target="${BURROW_LINUX_TARGET:-$host}"
|
|
if [[ "$target" != *-linux-* && -z "${BURROW_LINUX_TARGET:-}" ]]; then
|
|
mkdir -p "${out_root}/linux"
|
|
echo "warning: host target ${target} is not Linux; skipping Linux artifact on this host" >&2
|
|
printf 'Linux build was skipped on host target %s. Run this lane on a Linux Namespace runner or set BURROW_LINUX_TARGET explicitly.\n' "$target" > "${out_root}/linux/README.txt"
|
|
return 0
|
|
fi
|
|
staging="${out_root}/linux/burrow-${build_number}-${target}"
|
|
mkdir -p "$staging"
|
|
|
|
cargo build --locked --release -p burrow --bin burrow --target "$target"
|
|
install -m 0755 "target/${target}/release/burrow" "$staging/burrow"
|
|
copy_license_readme "$staging"
|
|
|
|
archive="${out_root}/linux/burrow-${build_number}-${target}.tar.gz"
|
|
tar -C "${out_root}/linux" -czf "$archive" "$(basename "$staging")"
|
|
sha256_file "$archive"
|
|
|
|
package_deb "$target" "target/${target}/release/burrow"
|
|
package_rpm "$target" "target/${target}/release/burrow"
|
|
package_pacman "$target" "target/${target}/release/burrow"
|
|
}
|
|
|
|
package_windows_stub_unix() {
|
|
local target exe archive staging
|
|
target="${BURROW_WINDOWS_TARGET:-x86_64-pc-windows-gnu}"
|
|
staging="${out_root}/windows/burrow-${build_number}-${target}"
|
|
mkdir -p "$staging"
|
|
|
|
target_libdir="$(rustc --print target-libdir --target "$target" 2>/dev/null || true)"
|
|
if [[ -z "$target_libdir" || ! -d "$target_libdir" ]]; then
|
|
echo "warning: Rust target ${target} is not installed on this host" >&2
|
|
printf 'Windows stub build for %s was skipped on this host. Use the Namespace Windows lane for the native artifact.\n' "$target" > "${out_root}/windows/README.txt"
|
|
return 0
|
|
fi
|
|
|
|
if cargo build --locked --release -p burrow-windows-stub --target "$target"; then
|
|
exe="target/${target}/release/burrow.exe"
|
|
else
|
|
echo "warning: unable to build the Windows release stub on this host" >&2
|
|
printf 'Windows stub build for %s was skipped on this host. Use the Namespace Windows lane for the native artifact.\n' "$target" > "${out_root}/windows/README.txt"
|
|
return 0
|
|
fi
|
|
|
|
install -m 0755 "$exe" "$staging/burrow.exe"
|
|
copy_license_readme "$staging"
|
|
printf 'Burrow Windows stub build %s\n' "$build_number" > "$staging/README-Windows.txt"
|
|
|
|
archive="${out_root}/windows/burrow-${build_number}-${target}.zip"
|
|
(cd "${out_root}/windows" && zip -qr "$archive" "$(basename "$staging")")
|
|
sha256_file "$archive"
|
|
}
|
|
|
|
package_sparkle_unsigned() {
|
|
local macos_dir appcast channel dmg
|
|
channel="${SPARKLE_CHANNEL:-build-${build_number}}"
|
|
macos_dir="${out_root}/macos"
|
|
appcast="${out_root}/sparkle/${channel}/appcast.xml"
|
|
mkdir -p "$(dirname "$appcast")"
|
|
|
|
dmg="$(find "$macos_dir" -maxdepth 1 -type f -name '*.dmg' -print 2>/dev/null | sort | tail -n 1 || true)"
|
|
if [[ -z "$dmg" ]]; then
|
|
echo "No macOS DMG exists yet; Sparkle appcast generation is waiting on the macOS signed artifact." > "${out_root}/sparkle/${channel}/README.txt"
|
|
return 0
|
|
fi
|
|
|
|
local name length pubdate url
|
|
name="$(basename "$dmg")"
|
|
length="$(wc -c < "$dmg" | tr -d ' ')"
|
|
pubdate="$(LC_ALL=C date -u '+%a, %d %b %Y %H:%M:%S +0000')"
|
|
url="${SPARKLE_DOWNLOAD_PREFIX:-https://releases.burrow.net/sparkle}/${channel}/${name}"
|
|
cat > "$appcast" <<EOF
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
|
<channel>
|
|
<title>Burrow ${channel}</title>
|
|
<item>
|
|
<title>Burrow ${build_number}</title>
|
|
<pubDate>${pubdate}</pubDate>
|
|
<sparkle:version>${build_number}</sparkle:version>
|
|
<sparkle:shortVersionString>0.1</sparkle:shortVersionString>
|
|
<enclosure url="${url}" sparkle:version="${build_number}" length="${length}" type="application/octet-stream" />
|
|
</item>
|
|
</channel>
|
|
</rss>
|
|
EOF
|
|
cp "$dmg" "${out_root}/sparkle/${channel}/"
|
|
}
|
|
|
|
case "$platform" in
|
|
all)
|
|
package_linux
|
|
package_windows_stub_unix
|
|
if [[ "$(uname -s)" == "Darwin" ]] && command -v xcodebuild >/dev/null 2>&1; then
|
|
Scripts/ci/package-apple-artifacts.sh all
|
|
else
|
|
mkdir -p "${out_root}/apple"
|
|
printf 'Apple artifacts require a macOS runner with Xcode. The release workflow builds them in the dedicated Apple lane.\n' > "${out_root}/apple/README.txt"
|
|
fi
|
|
package_sparkle_unsigned
|
|
;;
|
|
linux)
|
|
package_linux
|
|
;;
|
|
windows-stub|windows)
|
|
package_windows_stub_unix
|
|
;;
|
|
sparkle)
|
|
package_sparkle_unsigned
|
|
;;
|
|
apple)
|
|
Scripts/ci/package-apple-artifacts.sh all
|
|
;;
|
|
ios|macos)
|
|
Scripts/ci/package-apple-artifacts.sh "$platform"
|
|
;;
|
|
*)
|
|
echo "unknown release platform: $platform" >&2
|
|
exit 64
|
|
;;
|
|
esac
|
|
|
|
find "$out_root" -type f -print | sort
|