diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..3f38a1d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,105 @@ +name: Build Binaries + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + name: Build Cross-Platform Binaries + runs-on: ubuntu-latest + strategy: + matrix: + include: + # Linux builds + - goos: linux + goarch: amd64 + name: jail-linux-amd64 + - goos: linux + goarch: arm64 + name: jail-linux-arm64 + # macOS builds + - goos: darwin + goarch: amd64 + name: jail-darwin-amd64 + - goos: darwin + goarch: arm64 + name: jail-darwin-arm64 + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.25' + check-latest: true + + - name: Cache Go modules + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download dependencies + run: go mod download + + - name: Verify dependencies + run: go mod verify + + - name: Build binary + run: | + # Set target for cross-compilation + export GOOS=${{ matrix.goos }} + export GOARCH=${{ matrix.goarch }} + export CGO_ENABLED=0 + + # Add version info if available + VERSION="dev-${{ github.sha }}" + if [ "${{ github.ref_type }}" = "tag" ]; then + VERSION="${{ github.ref_name }}" + fi + + # Build using Go directly for cross-compilation + go build -ldflags="-s -w -X main.version=$VERSION" -o ${{ matrix.name }} . + + - name: Upload binary as artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.name }} + path: ${{ matrix.name }} + retention-days: 30 + + summary: + name: Build Summary + needs: build + runs-on: ubuntu-latest + if: always() + + steps: + - name: Build Summary + run: | + echo "## 🛠️ Build Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Cross-platform binaries have been built and are available as artifacts." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### 📦 Available Binaries" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- 🐧 **Linux (x64)**: jail-linux-amd64" >> $GITHUB_STEP_SUMMARY + echo "- 🐧 **Linux (ARM64)**: jail-linux-arm64" >> $GITHUB_STEP_SUMMARY + echo "- 🍎 **macOS (Intel)**: jail-darwin-amd64" >> $GITHUB_STEP_SUMMARY + echo "- 🍎 **macOS (Apple Silicon)**: jail-darwin-arm64" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### 📎 Download Instructions" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "1. Go to the **Actions** tab" >> $GITHUB_STEP_SUMMARY + echo "2. Click on this workflow run" >> $GITHUB_STEP_SUMMARY + echo "3. Scroll down to **Artifacts** section" >> $GITHUB_STEP_SUMMARY + echo "4. Download the binary for your platform" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c860749..0777bd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: run: go mod verify - name: Run tests - run: go test -v -race ./... + run: make test - - name: Run build - run: go build -v ./... \ No newline at end of file + - name: Check build + run: make build \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..891841f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,135 @@ +name: Release + +on: + push: + tags: + - 'v*' # Trigger on version tags like v1.0.0, v1.2.3, etc. + workflow_dispatch: # Allow manual triggering + +jobs: + build: + name: Build Binaries + runs-on: ubuntu-latest + strategy: + matrix: + include: + # Linux builds + - goos: linux + goarch: amd64 + name: jail-linux-amd64 + - goos: linux + goarch: arm64 + name: jail-linux-arm64 + # macOS builds + - goos: darwin + goarch: amd64 + name: jail-darwin-amd64 + - goos: darwin + goarch: arm64 + name: jail-darwin-arm64 + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.25' + check-latest: true + + - name: Cache Go modules + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download dependencies + run: go mod download + + - name: Verify dependencies + run: go mod verify + + - name: Build binary + run: | + # Set target for cross-compilation + export GOOS=${{ matrix.goos }} + export GOARCH=${{ matrix.goarch }} + export CGO_ENABLED=0 + + # Build using Go directly for cross-compilation + go build -ldflags="-s -w -X main.version=${{ github.ref_name }}" -o ${{ matrix.name }} . + + - name: Upload binary as artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.name }} + path: ${{ matrix.name }} + retention-days: 7 + + release: + name: Create Release + needs: build + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: ./binaries + + - name: Prepare release assets + run: | + cd binaries + # Create compressed archives for each binary + for dir in */; do + binary_name=$(basename "$dir") + cd "$dir" + # Unix: create tar.gz + tar -czf "../${binary_name}.tar.gz" "$binary_name" + cd .. + done + # List all release assets + ls -la *.tar.gz + + - name: Generate release notes + id: release_notes + run: | + echo "## 🚀 Release ${{ github.ref_name }}" > release_notes.md + echo "" >> release_notes.md + echo "### 📦 Downloads" >> release_notes.md + echo "" >> release_notes.md + echo "Choose the appropriate binary for your platform:" >> release_notes.md + echo "" >> release_notes.md + echo "- **Linux (x64)**: \`jail-linux-amd64.tar.gz\`" >> release_notes.md + echo "- **Linux (ARM64)**: \`jail-linux-arm64.tar.gz\`" >> release_notes.md + echo "- **macOS (Intel)**: \`jail-darwin-amd64.tar.gz\`" >> release_notes.md + echo "- **macOS (Apple Silicon)**: \`jail-darwin-arm64.tar.gz\`" >> release_notes.md + echo "" >> release_notes.md + echo "### 🛠️ Installation" >> release_notes.md + echo "" >> release_notes.md + echo "1. Download the appropriate binary for your platform" >> release_notes.md + echo "2. Extract the archive" >> release_notes.md + echo "3. Make the binary executable (Unix): `chmod +x jail`" >> release_notes.md + echo "4. Move to your PATH: `sudo mv jail /usr/local/bin/` (Unix)" >> release_notes.md + echo "" >> release_notes.md + echo "### ✅ Verification" >> release_notes.md + echo "" >> release_notes.md + echo "Verify installation: `jail --help`" >> release_notes.md + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: | + binaries/*.tar.gz + body_path: release_notes.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index f83a2fd..1a517a5 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ Thumbs.db *.pem *.crt *.key +build/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1051767 --- /dev/null +++ b/Makefile @@ -0,0 +1,75 @@ +# Makefile for jail + +# Variables +BINARY_NAME := jail +BUILD_DIR := build +VERSION := $(shell git describe --tags --exact-match 2>/dev/null || echo "dev-$(shell git rev-parse --short HEAD)") +LDFLAGS := -s -w -X main.version=$(VERSION) + +# Default target +.PHONY: all +all: build + +# Build for current platform +.PHONY: build +build: + @echo "Building $(BINARY_NAME) for current platform..." + @echo "Version: $(VERSION)" + go build -ldflags="$(LDFLAGS)" -o $(BINARY_NAME) . + @echo "✓ Built $(BINARY_NAME)" + +# Build for all supported platforms +.PHONY: build-all +build-all: + @echo "Building $(BINARY_NAME) for all platforms..." + @echo "Version: $(VERSION)" + @mkdir -p $(BUILD_DIR) + @echo "Building Linux amd64..." + GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 . + @echo "Building Linux arm64..." + GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 . + @echo "Building macOS amd64..." + GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-amd64 . + @echo "Building macOS arm64..." + GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-arm64 . + @echo "✓ All binaries built successfully!" + @echo "Binaries are in the '$(BUILD_DIR)' directory:" + @ls -la $(BUILD_DIR)/ + +# Run tests +.PHONY: test +test: + @echo "Running tests..." + go test -v -race ./... + @echo "✓ All tests passed!" + +# Run tests with coverage +.PHONY: test-coverage +test-coverage: + @echo "Running tests with coverage..." + go test -v -race -coverprofile=coverage.out ./... + go tool cover -html=coverage.out -o coverage.html + @echo "✓ Coverage report generated: coverage.html" + +# Clean build artifacts +.PHONY: clean +clean: + @echo "Cleaning build artifacts..." + rm -f $(BINARY_NAME) + rm -rf $(BUILD_DIR) + rm -f coverage.out coverage.html + @echo "✓ Clean complete!" + +# Format code +.PHONY: fmt +fmt: + @echo "Formatting code..." + go fmt ./... + @echo "✓ Code formatted!" + +# Lint code +.PHONY: lint +lint: + @echo "Linting code..." + golangci-lint run + @echo "✓ Linting complete!" \ No newline at end of file diff --git a/RELEASES.md b/RELEASES.md new file mode 100644 index 0000000..ca39813 --- /dev/null +++ b/RELEASES.md @@ -0,0 +1,83 @@ +# Releases + +This document describes how jail binaries are built and released. + +## Automated Releases + +### GitHub Releases + +Binaries are automatically built and released when you push a version tag: + +```bash +# Create and push a version tag +git tag v1.0.0 +git push origin v1.0.0 +``` + +This triggers the **Release** workflow which: +1. Builds binaries for all supported platforms +2. Creates compressed archives (`.tar.gz` for Unix) +3. Creates a GitHub release with all binaries attached +4. Generates release notes with download instructions + +### Supported Platforms + +| Platform | Architecture | Binary Name | Archive | +|----------|--------------|-------------|----------| +| Linux | x64 | `jail-linux-amd64` | `.tar.gz` | +| Linux | ARM64 | `jail-linux-arm64` | `.tar.gz` | +| macOS | Intel | `jail-darwin-amd64` | `.tar.gz` | +| macOS | Apple Silicon | `jail-darwin-arm64` | `.tar.gz` | + +## Release Process + +### For Maintainers + +1. **Prepare Release**: + - Ensure all changes are merged to `main` + - Update version in relevant files if needed + - Test the build locally + +2. **Create Release**: + ```bash + # Create and push version tag + git tag v1.2.3 + git push origin v1.2.3 + ``` + +3. **Verify Release**: + - Check GitHub Actions completed successfully + - Verify release appears in GitHub Releases + - Test download and installation of binaries + +### Version Naming + +- **Stable releases**: `v1.0.0`, `v1.2.3` +- **Pre-releases**: `v1.0.0-beta.1`, `v1.0.0-rc.1` +- **Development**: `dev-{git-hash}` (automatic) + +Pre-releases (containing `-`) are automatically marked as "pre-release" on GitHub. + +## Installation + +### From GitHub Releases + +1. Go to [Releases](https://github.com/coder/jail/releases) +2. Download the appropriate binary for your platform +3. Extract the archive +4. Make executable (Unix): `chmod +x jail` +5. Move to PATH: `sudo mv jail /usr/local/bin/` + +### Verify Installation + +```bash +jail --help +``` + +## Troubleshooting + +### Release Issues + +- **Tag not triggering release**: Ensure tag follows `v*` pattern +- **Build failures**: Check GitHub Actions logs +- **Missing binaries**: Verify all matrix builds completed successfully diff --git a/main.go b/main.go index 6a7bb59..ae17de6 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,11 @@ import ( "github.com/coder/jail/cli" ) +// Version information injected at build time +var ( + version = "dev" // Set via -ldflags "-X main.version=v1.0.0" +) + func main() { cmd := cli.NewCommand() diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..dc597f6 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Build script for jail - creates binaries for all supported platforms + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Get version from git tag or use dev +VERSION=$(git describe --tags --exact-match 2>/dev/null || echo "dev-$(git rev-parse --short HEAD)") + +echo -e "${BLUE}Building jail binaries...${NC}" +echo -e "${YELLOW}Version: $VERSION${NC}" +echo + +# Create build directory +BUILD_DIR="build" +rm -rf "$BUILD_DIR" +mkdir -p "$BUILD_DIR" + +# Build configurations: OS:ARCH:NAME +configs=( + "linux:amd64:jail-linux-amd64" + "linux:arm64:jail-linux-arm64" + "darwin:amd64:jail-darwin-amd64" + "darwin:arm64:jail-darwin-arm64" +) + +# Build each configuration +for config in "${configs[@]}"; do + IFS=':' read -r goos goarch name <<< "$config" + + echo -e "${YELLOW}Building $name...${NC}" + + env GOOS="$goos" GOARCH="$goarch" CGO_ENABLED=0 go build \ + -ldflags="-s -w -X main.version=$VERSION" \ + -o "$BUILD_DIR/$name" . + + if [ $? -eq 0 ]; then + size=$(du -h "$BUILD_DIR/$name" | cut -f1) + echo -e "${GREEN}✓ Built $name ($size)${NC}" + else + echo -e "${RED}✗ Failed to build $name${NC}" + exit 1 + fi +done + +echo +echo -e "${GREEN}All binaries built successfully!${NC}" +echo -e "${BLUE}Binaries are in the '$BUILD_DIR' directory:${NC}" +ls -la "$BUILD_DIR"/ + +echo +echo -e "${YELLOW}To create release archives:${NC}" +echo " cd $BUILD_DIR" +echo " tar -czf jail-linux-amd64.tar.gz jail-linux-amd64" +echo " tar -czf jail-darwin-amd64.tar.gz jail-darwin-amd64" +echo " # ... etc for other platforms" \ No newline at end of file