From 0ead2c37efe34278a859edbce40e8bba7bf021fd Mon Sep 17 00:00:00 2001 From: diogo464 Date: Thu, 10 Jul 2025 22:20:34 +0100 Subject: Add GitHub Actions release workflow and build scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add .github/workflows/release.yml for automated releases on version tags - Add scripts/build-static.sh for building statically linked binaries - Add scripts/prepare-release.sh for preparing release artifacts - Optimize Cargo.toml for smaller binary size (reduced from 4.5MB to 2.9MB) - Add scripts/README.md with usage documentation The workflow automatically builds binaries for Linux (musl) and macOS (Intel/ARM) when a version tag is pushed. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- scripts/README.md | 56 ++++++++++++ scripts/build-static.sh | 218 +++++++++++++++++++++++++++++++++++++++++++++ scripts/prepare-release.sh | 206 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 480 insertions(+) create mode 100644 scripts/README.md create mode 100755 scripts/build-static.sh create mode 100755 scripts/prepare-release.sh (limited to 'scripts') diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..65b69ee --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,56 @@ +# Build Scripts + +This directory contains scripts for building and releasing the oar-p2p binary. + +## Scripts + +### build-static.sh + +Builds statically linked binaries for Linux and macOS. + +```bash +# Build for all platforms (macOS only) +./scripts/build-static.sh all + +# Build for Linux only +./scripts/build-static.sh linux + +# Build for macOS only (macOS only) +./scripts/build-static.sh macos + +# Specify custom output directory +./scripts/build-static.sh linux /path/to/output +``` + +**Note**: Cross-compilation is not supported. Linux binaries must be built on Linux, and macOS binaries must be built on macOS. The GitHub Actions workflow handles this by using different runners. + +### prepare-release.sh + +Prepares a release by building binaries, creating tarballs, and generating checksums. + +```bash +# Prepare release for version v1.0.0 +./scripts/prepare-release.sh v1.0.0 + +# Specify custom output directory +./scripts/prepare-release.sh v1.0.0 /path/to/dist +``` + +The script will: +1. Build static binaries for the current platform +2. Create tarballs with the binary and README +3. Generate SHA256 and SHA512 checksums +4. Create a release notes template + +## GitHub Actions + +The `.github/workflows/release.yml` workflow automatically: +1. Triggers on version tags (e.g., `v1.0.0`) +2. Builds binaries on Linux and macOS runners +3. Creates a GitHub release with all artifacts + +To create a release: +```bash +git tag -a v1.0.0 -m "Release v1.0.0" +git push origin v1.0.0 +``` \ No newline at end of file diff --git a/scripts/build-static.sh b/scripts/build-static.sh new file mode 100755 index 0000000..d835e79 --- /dev/null +++ b/scripts/build-static.sh @@ -0,0 +1,218 @@ +#!/bin/bash +set -euo pipefail + +# Script to build static binaries for Linux and macOS +# Can be run locally or in CI + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +BINARY_NAME="oar-p2p" + +# Parse command line arguments +TARGET_OS="${1:-all}" # linux, macos, or all +OUTPUT_DIR="${2:-$PROJECT_ROOT/target/release-static}" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" >&2 +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +# Ensure we're in the project root +cd "$PROJECT_ROOT" + +# Create output directory +mkdir -p "$OUTPUT_DIR" + +# Function to build for Linux with musl +build_linux() { + local arch="${1:-x86_64}" + local target="${arch}-unknown-linux-musl" + + log_info "Building static binary for Linux ($arch)..." + + # Check if target is installed + if ! rustup target list --installed | grep -q "$target"; then + log_info "Installing Rust target: $target" + rustup target add "$target" + fi + + # Set environment variables for static linking + export RUSTFLAGS="-C target-feature=+crt-static" + + # Build the binary + log_info "Running cargo build for $target..." + cargo build --release --target "$target" --target-dir "$PROJECT_ROOT/target" + + # Copy binary to output directory with platform suffix + local output_name="${BINARY_NAME}-linux-${arch}" + cp "target/$target/release/$BINARY_NAME" "$OUTPUT_DIR/$output_name" + + # Strip the binary to reduce size + if command -v strip >/dev/null 2>&1; then + log_info "Stripping binary to reduce size..." + strip "$OUTPUT_DIR/$output_name" + fi + + # Make it executable + chmod +x "$OUTPUT_DIR/$output_name" + + log_info "Linux binary built: $OUTPUT_DIR/$output_name" + + # Print binary info + if command -v file >/dev/null 2>&1; then + file "$OUTPUT_DIR/$output_name" + fi + + # Check if it's actually statically linked + if command -v ldd >/dev/null 2>&1; then + if ldd "$OUTPUT_DIR/$output_name" 2>&1 | grep -q "not a dynamic executable"; then + log_info "✓ Binary is statically linked" + else + log_warn "Binary appears to be dynamically linked" + fi + fi +} + +# Function to build for macOS +build_macos() { + local arch="${1:-x86_64}" + local target + + case "$arch" in + x86_64) + target="x86_64-apple-darwin" + ;; + aarch64|arm64) + target="aarch64-apple-darwin" + ;; + *) + log_error "Unknown macOS architecture: $arch" + return 1 + ;; + esac + + # Check if we're on macOS + if [[ "$OSTYPE" != "darwin"* ]]; then + log_warn "Cannot build macOS binaries on non-macOS systems" + log_info "macOS binaries must be built on macOS or in CI" + return 0 + fi + + log_info "Building binary for macOS ($arch)..." + + # Check if target is installed + if ! rustup target list --installed | grep -q "$target"; then + log_info "Installing Rust target: $target" + rustup target add "$target" + fi + + # macOS doesn't support fully static binaries, but we can minimize dependencies + export RUSTFLAGS="-C target-feature=+crt-static" + + # Build the binary + log_info "Running cargo build for $target..." + cargo build --release --target "$target" --target-dir "$PROJECT_ROOT/target" + + # Copy binary to output directory with platform suffix + local output_name="${BINARY_NAME}-macos-${arch}" + cp "target/$target/release/$BINARY_NAME" "$OUTPUT_DIR/$output_name" + + # Strip the binary to reduce size (macOS strip is different) + if [[ "$OSTYPE" == "darwin"* ]] && command -v strip >/dev/null 2>&1; then + log_info "Stripping binary to reduce size..." + strip "$OUTPUT_DIR/$output_name" + fi + + # Make it executable + chmod +x "$OUTPUT_DIR/$output_name" + + log_info "macOS binary built: $OUTPUT_DIR/$output_name" + + # Print binary info + if command -v file >/dev/null 2>&1; then + file "$OUTPUT_DIR/$output_name" + fi +} + +# Function to check dependencies +check_dependencies() { + local missing_deps=() + + # Check for Rust + if ! command -v cargo >/dev/null 2>&1; then + missing_deps+=("cargo (Rust)") + fi + + # Check for rustup + if ! command -v rustup >/dev/null 2>&1; then + missing_deps+=("rustup") + fi + + if [ ${#missing_deps[@]} -ne 0 ]; then + log_error "Missing required dependencies:" + for dep in "${missing_deps[@]}"; do + echo " - $dep" + done + exit 1 + fi + + # Check Rust version (nightly required based on Cargo.toml) + if ! rustc --version | grep -q "nightly"; then + log_warn "This project requires Rust nightly. Current version:" + rustc --version + log_info "Attempting to use nightly for this build..." + export RUSTUP_TOOLCHAIN=nightly + fi +} + +# Main execution +main() { + log_info "Starting static build process..." + log_info "Output directory: $OUTPUT_DIR" + + # Check dependencies + check_dependencies + + case "$TARGET_OS" in + linux) + build_linux "x86_64" + # Optionally build for ARM64 + # build_linux "aarch64" + ;; + macos|darwin) + # Build for both Intel and Apple Silicon + build_macos "x86_64" + build_macos "aarch64" + ;; + all) + # Build for all platforms + build_linux "x86_64" + build_macos "x86_64" + build_macos "aarch64" + ;; + *) + log_error "Unknown target OS: $TARGET_OS" + echo "Usage: $0 [linux|macos|all] [output_dir]" + exit 1 + ;; + esac + + log_info "Build complete! Binaries available in: $OUTPUT_DIR" + ls -lh "$OUTPUT_DIR" +} + +# Run main function +main \ No newline at end of file diff --git a/scripts/prepare-release.sh b/scripts/prepare-release.sh new file mode 100755 index 0000000..ba654e2 --- /dev/null +++ b/scripts/prepare-release.sh @@ -0,0 +1,206 @@ +#!/bin/bash +set -euo pipefail + +# Script to prepare release artifacts +# Builds binaries, creates checksums, and prepares release notes + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +BINARY_NAME="oar-p2p" + +# Parse command line arguments +VERSION="${1:-}" +OUTPUT_DIR="${2:-$PROJECT_ROOT/dist}" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" >&2 +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +# Ensure we're in the project root +cd "$PROJECT_ROOT" + +# Check if version is provided +if [ -z "$VERSION" ]; then + log_error "Version not provided" + echo "Usage: $0 [output_dir]" + echo "Example: $0 v1.0.0" + exit 1 +fi + +# Remove 'v' prefix if present for consistency +VERSION_NUMBER="${VERSION#v}" + +log_info "Preparing release for version: $VERSION_NUMBER" + +# Create output directories +BUILD_DIR="$PROJECT_ROOT/target/release-static" +mkdir -p "$OUTPUT_DIR" +mkdir -p "$BUILD_DIR" + +# Build all binaries +log_info "Building static binaries for all platforms..." +if [[ "$OSTYPE" == "darwin"* ]]; then + # On macOS, build all platforms + "$SCRIPT_DIR/build-static.sh" all "$BUILD_DIR" +else + # On Linux, only build Linux binaries + log_warn "Running on Linux - only Linux binaries will be built" + log_info "macOS binaries must be built on macOS or in CI" + "$SCRIPT_DIR/build-static.sh" linux "$BUILD_DIR" +fi + +# Function to create tarball for a binary +create_tarball() { + local binary_path="$1" + local binary_name="$(basename "$binary_path")" + local platform_name="${binary_name#$BINARY_NAME-}" + local tarball_name="${BINARY_NAME}-${VERSION_NUMBER}-${platform_name}.tar.gz" + + log_info "Creating tarball: $tarball_name" + + # Create temporary directory for tarball contents + local temp_dir="$(mktemp -d)" + + # Copy binary to temp directory + cp "$binary_path" "$temp_dir/$BINARY_NAME" + chmod +x "$temp_dir/$BINARY_NAME" + + # Create README for the tarball + cat > "$temp_dir/README.md" << EOF +# $BINARY_NAME v$VERSION_NUMBER + +Platform: ${platform_name} + +## Installation + +1. Extract the binary: + \`\`\`bash + tar -xzf $tarball_name + \`\`\` + +2. Move to a directory in your PATH: + \`\`\`bash + sudo mv $BINARY_NAME /usr/local/bin/ + \`\`\` + +3. Verify installation: + \`\`\`bash + $BINARY_NAME --version + \`\`\` + +## Usage + +Run \`$BINARY_NAME --help\` for usage information. + +EOF + + # Create tarball + tar -czf "$OUTPUT_DIR/$tarball_name" -C "$temp_dir" . + + # Cleanup + rm -rf "$temp_dir" + + return 0 +} + +# Create tarballs for all binaries +log_info "Creating release tarballs..." +for binary in "$BUILD_DIR"/${BINARY_NAME}-*; do + if [ -f "$binary" ]; then + create_tarball "$binary" + fi +done + +# Generate checksums +log_info "Generating checksums..." +cd "$OUTPUT_DIR" + +# Create SHA256 checksums +if command -v sha256sum >/dev/null 2>&1; then + sha256sum *.tar.gz > "checksums-sha256.txt" +elif command -v shasum >/dev/null 2>&1; then + shasum -a 256 *.tar.gz > "checksums-sha256.txt" +else + log_warn "SHA256 checksum tool not found, skipping checksums" +fi + +# Create SHA512 checksums +if command -v sha512sum >/dev/null 2>&1; then + sha512sum *.tar.gz > "checksums-sha512.txt" +elif command -v shasum >/dev/null 2>&1; then + shasum -a 512 *.tar.gz > "checksums-sha512.txt" +fi + +# Generate release notes template +log_info "Generating release notes template..." +cat > "$OUTPUT_DIR/RELEASE_NOTES.md" << EOF +# Release Notes - $BINARY_NAME v$VERSION_NUMBER + +## What's Changed + + + +## Installation + +### Using curl (Linux/macOS) + +\`\`\`bash +# Linux x86_64 +curl -L https://github.com/diogo464/oar-p2p/releases/download/v$VERSION_NUMBER/${BINARY_NAME}-${VERSION_NUMBER}-linux-x86_64.tar.gz | tar -xz +sudo mv $BINARY_NAME /usr/local/bin/ + +# macOS Intel +curl -L https://github.com/diogo464/oar-p2p/releases/download/v$VERSION_NUMBER/${BINARY_NAME}-${VERSION_NUMBER}-macos-x86_64.tar.gz | tar -xz +sudo mv $BINARY_NAME /usr/local/bin/ + +# macOS Apple Silicon +curl -L https://github.com/diogo464/oar-p2p/releases/download/v$VERSION_NUMBER/${BINARY_NAME}-${VERSION_NUMBER}-macos-aarch64.tar.gz | tar -xz +sudo mv $BINARY_NAME /usr/local/bin/ +\`\`\` + +## Checksums + +### SHA256 +\`\`\` +$(cat checksums-sha256.txt 2>/dev/null || echo "Checksums will be generated during release") +\`\`\` + +### SHA512 +\`\`\` +$(cat checksums-sha512.txt 2>/dev/null || echo "Checksums will be generated during release") +\`\`\` + +## Full Changelog + +See the full changelog at: https://github.com/diogo464/oar-p2p/compare/v...v$VERSION_NUMBER + +EOF + +# List all artifacts +log_info "Release artifacts created in: $OUTPUT_DIR" +echo -e "${BLUE}Contents:${NC}" +ls -lh "$OUTPUT_DIR" + +# Print summary +echo +log_info "Release preparation complete!" +echo -e "${BLUE}Next steps:${NC}" +echo "1. Review and edit the release notes: $OUTPUT_DIR/RELEASE_NOTES.md" +echo "2. Create a git tag: git tag -a v$VERSION_NUMBER -m \"Release v$VERSION_NUMBER\"" +echo "3. Push the tag: git push origin v$VERSION_NUMBER" +echo "4. The GitHub Action will automatically create the release and upload artifacts" \ No newline at end of file -- cgit