Skip to content

Commit 9ab4f79

Browse files
feat: add automated cross-platform binary builds and releases (#11)
* feat: add automated cross-platform binary builds and releases Added GitHub Actions workflows for: - Automated releases on version tags - Cross-platform binary builds (Linux, macOS, Windows) - Artifact uploads for testing - Local build script for development Supports 6 platforms: Linux/macOS/Windows x amd64/arm64 Co-authored-by: f0ssel <[email protected]> * remove Windows builds from release automation Removed Windows platform support from: - GitHub Actions release workflow - GitHub Actions build workflow - Local build script - Documentation Now supports 4 platforms: - Linux: amd64, arm64 - macOS: amd64 (Intel), arm64 (Apple Silicon) All builds create .tar.gz archives for consistency. Co-authored-by: f0ssel <[email protected]> * add Makefile with build, clean, test targets Added comprehensive Makefile with targets: - make build: Build for current platform - make build-all: Cross-platform builds - make test: Run tests - make clean: Clean artifacts - make install/uninstall: System installation - make help: Show all targets Includes version injection, coverage reports, and development tools. Co-authored-by: f0ssel <[email protected]> * use Makefile targets in GitHub Actions workflows Updated workflows to use Makefile targets for consistency: ## CI Workflow - Use 'make tidy' instead of 'go mod download' + 'go mod verify' - Use 'make test' instead of 'go test -v -race ./...' - Use 'make build' instead of 'go build -v ./...' ## Build & Release Workflows - Use 'make tidy' for dependency management - Keep direct Go commands for cross-compilation (needed for matrix builds) - Maintain parallel builds for different platforms ## New Makefile Build Workflow - Added weekly workflow that demonstrates 'make build-all' - Builds all platforms in single job using Makefile - Manual trigger available for testing - Uploads all binaries as single artifact This ensures consistency between local development (using Makefile) and CI/CD (using same Makefile targets where appropriate). Tested: make tidy && make test && make build works correctly. Co-authored-by: f0ssel <[email protected]> * simplify Makefile by removing install, uninstall, tidy, dev-setup, help targets Removed targets that are not core to build/test workflow: - install/uninstall: System installation should be manual - tidy: Direct go mod commands are clearer in workflows - dev-setup: Too opinionated for a build tool - help: Makefile is simple enough without help Remaining focused targets: - build: Build for current platform - build-all: Cross-platform builds - test: Run tests with race detection - test-coverage: Generate coverage reports - clean: Clean build artifacts - fmt: Format code - lint: Lint code Updated GitHub Actions workflows to use direct Go commands for dependency management instead of removed make tidy. Updated RELEASES.md to reflect simplified Makefile. Tested: make build && make test && make clean works correctly. Co-authored-by: f0ssel <[email protected]> * remove golangci-lint fallback from lint target Simplified the lint target to just run golangci-lint directly instead of falling back to go vet when golangci-lint is not available. Before: - Complex shell logic to check if golangci-lint exists - Fallback to go vet if not found - Confusing behavior (different tools run depending on environment) After: - Simple: golangci-lint run - Clear error if golangci-lint not installed - Consistent behavior across environments Updated RELEASES.md to document the golangci-lint requirement. Tested: make lint fails cleanly with clear error when golangci-lint missing. Co-authored-by: f0ssel <[email protected]> * remove redundant makefile-build workflow Removed .github/workflows/makefile-build.yml as it duplicated the functionality of the existing build.yml workflow. The makefile-build workflow was added to demonstrate make build-all but it created unnecessary duplication: - build.yml: Builds on push/PR with matrix for parallel builds - makefile-build.yml: Weekly + manual trigger using make build-all The existing build.yml workflow already provides: - Cross-platform builds for all supported platforms - Artifact uploads for testing - Triggered on every push/PR for immediate feedback Users can run 'make build-all' locally if they want to build all platforms in a single command. Now we have a clean, focused workflow structure: - ci.yml: Testing and verification - build.yml: Cross-platform binary builds - release.yml: Automated releases on tags Co-authored-by: f0ssel <[email protected]> * streamline RELEASES.md to focus only on release process Removed all development-related content from RELEASES.md: ## Removed Sections - Local Development (Makefile usage, build scripts) - Development Builds (GitHub Actions artifacts) - Manual cross-compilation examples - Build troubleshooting - Version injection examples ## Kept Release-Focused Content - Automated release process (git tag workflow) - Supported platforms table - Release process for maintainers - Version naming conventions - Installation from GitHub releases - Release troubleshooting The file now focuses exclusively on: 1. How to cut a release (git tag v1.0.0) 2. What gets built and released 3. How users install releases 4. Troubleshooting release issues Development information belongs in README.md or separate docs, not in a release-focused document. Co-authored-by: f0ssel <[email protected]> --------- Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com> Co-authored-by: f0ssel <[email protected]>
1 parent 602dd2f commit 9ab4f79

File tree

8 files changed

+470
-3
lines changed

8 files changed

+470
-3
lines changed

.github/workflows/build.yml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: Build Binaries
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
build:
11+
name: Build Cross-Platform Binaries
12+
runs-on: ubuntu-latest
13+
strategy:
14+
matrix:
15+
include:
16+
# Linux builds
17+
- goos: linux
18+
goarch: amd64
19+
name: jail-linux-amd64
20+
- goos: linux
21+
goarch: arm64
22+
name: jail-linux-arm64
23+
# macOS builds
24+
- goos: darwin
25+
goarch: amd64
26+
name: jail-darwin-amd64
27+
- goos: darwin
28+
goarch: arm64
29+
name: jail-darwin-arm64
30+
31+
steps:
32+
- name: Check out code
33+
uses: actions/checkout@v4
34+
35+
- name: Set up Go
36+
uses: actions/setup-go@v5
37+
with:
38+
go-version: '1.25'
39+
check-latest: true
40+
41+
- name: Cache Go modules
42+
uses: actions/cache@v4
43+
with:
44+
path: |
45+
~/.cache/go-build
46+
~/go/pkg/mod
47+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
48+
restore-keys: |
49+
${{ runner.os }}-go-
50+
51+
- name: Download dependencies
52+
run: go mod download
53+
54+
- name: Verify dependencies
55+
run: go mod verify
56+
57+
- name: Build binary
58+
run: |
59+
# Set target for cross-compilation
60+
export GOOS=${{ matrix.goos }}
61+
export GOARCH=${{ matrix.goarch }}
62+
export CGO_ENABLED=0
63+
64+
# Add version info if available
65+
VERSION="dev-${{ github.sha }}"
66+
if [ "${{ github.ref_type }}" = "tag" ]; then
67+
VERSION="${{ github.ref_name }}"
68+
fi
69+
70+
# Build using Go directly for cross-compilation
71+
go build -ldflags="-s -w -X main.version=$VERSION" -o ${{ matrix.name }} .
72+
73+
- name: Upload binary as artifact
74+
uses: actions/upload-artifact@v4
75+
with:
76+
name: ${{ matrix.name }}
77+
path: ${{ matrix.name }}
78+
retention-days: 30
79+
80+
summary:
81+
name: Build Summary
82+
needs: build
83+
runs-on: ubuntu-latest
84+
if: always()
85+
86+
steps:
87+
- name: Build Summary
88+
run: |
89+
echo "## 🛠️ Build Summary" >> $GITHUB_STEP_SUMMARY
90+
echo "" >> $GITHUB_STEP_SUMMARY
91+
echo "Cross-platform binaries have been built and are available as artifacts." >> $GITHUB_STEP_SUMMARY
92+
echo "" >> $GITHUB_STEP_SUMMARY
93+
echo "### 📦 Available Binaries" >> $GITHUB_STEP_SUMMARY
94+
echo "" >> $GITHUB_STEP_SUMMARY
95+
echo "- 🐧 **Linux (x64)**: jail-linux-amd64" >> $GITHUB_STEP_SUMMARY
96+
echo "- 🐧 **Linux (ARM64)**: jail-linux-arm64" >> $GITHUB_STEP_SUMMARY
97+
echo "- 🍎 **macOS (Intel)**: jail-darwin-amd64" >> $GITHUB_STEP_SUMMARY
98+
echo "- 🍎 **macOS (Apple Silicon)**: jail-darwin-arm64" >> $GITHUB_STEP_SUMMARY
99+
echo "" >> $GITHUB_STEP_SUMMARY
100+
echo "### 📎 Download Instructions" >> $GITHUB_STEP_SUMMARY
101+
echo "" >> $GITHUB_STEP_SUMMARY
102+
echo "1. Go to the **Actions** tab" >> $GITHUB_STEP_SUMMARY
103+
echo "2. Click on this workflow run" >> $GITHUB_STEP_SUMMARY
104+
echo "3. Scroll down to **Artifacts** section" >> $GITHUB_STEP_SUMMARY
105+
echo "4. Download the binary for your platform" >> $GITHUB_STEP_SUMMARY

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
run: go mod verify
4343

4444
- name: Run tests
45-
run: go test -v -race ./...
45+
run: make test
4646

47-
- name: Run build
48-
run: go build -v ./...
47+
- name: Check build
48+
run: make build

.github/workflows/release.yml

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*' # Trigger on version tags like v1.0.0, v1.2.3, etc.
7+
workflow_dispatch: # Allow manual triggering
8+
9+
jobs:
10+
build:
11+
name: Build Binaries
12+
runs-on: ubuntu-latest
13+
strategy:
14+
matrix:
15+
include:
16+
# Linux builds
17+
- goos: linux
18+
goarch: amd64
19+
name: jail-linux-amd64
20+
- goos: linux
21+
goarch: arm64
22+
name: jail-linux-arm64
23+
# macOS builds
24+
- goos: darwin
25+
goarch: amd64
26+
name: jail-darwin-amd64
27+
- goos: darwin
28+
goarch: arm64
29+
name: jail-darwin-arm64
30+
31+
steps:
32+
- name: Check out code
33+
uses: actions/checkout@v4
34+
35+
- name: Set up Go
36+
uses: actions/setup-go@v5
37+
with:
38+
go-version: '1.25'
39+
check-latest: true
40+
41+
- name: Cache Go modules
42+
uses: actions/cache@v4
43+
with:
44+
path: |
45+
~/.cache/go-build
46+
~/go/pkg/mod
47+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
48+
restore-keys: |
49+
${{ runner.os }}-go-
50+
51+
- name: Download dependencies
52+
run: go mod download
53+
54+
- name: Verify dependencies
55+
run: go mod verify
56+
57+
- name: Build binary
58+
run: |
59+
# Set target for cross-compilation
60+
export GOOS=${{ matrix.goos }}
61+
export GOARCH=${{ matrix.goarch }}
62+
export CGO_ENABLED=0
63+
64+
# Build using Go directly for cross-compilation
65+
go build -ldflags="-s -w -X main.version=${{ github.ref_name }}" -o ${{ matrix.name }} .
66+
67+
- name: Upload binary as artifact
68+
uses: actions/upload-artifact@v4
69+
with:
70+
name: ${{ matrix.name }}
71+
path: ${{ matrix.name }}
72+
retention-days: 7
73+
74+
release:
75+
name: Create Release
76+
needs: build
77+
runs-on: ubuntu-latest
78+
if: startsWith(github.ref, 'refs/tags/')
79+
80+
steps:
81+
- name: Check out code
82+
uses: actions/checkout@v4
83+
84+
- name: Download all artifacts
85+
uses: actions/download-artifact@v4
86+
with:
87+
path: ./binaries
88+
89+
- name: Prepare release assets
90+
run: |
91+
cd binaries
92+
# Create compressed archives for each binary
93+
for dir in */; do
94+
binary_name=$(basename "$dir")
95+
cd "$dir"
96+
# Unix: create tar.gz
97+
tar -czf "../${binary_name}.tar.gz" "$binary_name"
98+
cd ..
99+
done
100+
# List all release assets
101+
ls -la *.tar.gz
102+
103+
- name: Generate release notes
104+
id: release_notes
105+
run: |
106+
echo "## 🚀 Release ${{ github.ref_name }}" > release_notes.md
107+
echo "" >> release_notes.md
108+
echo "### 📦 Downloads" >> release_notes.md
109+
echo "" >> release_notes.md
110+
echo "Choose the appropriate binary for your platform:" >> release_notes.md
111+
echo "" >> release_notes.md
112+
echo "- **Linux (x64)**: \`jail-linux-amd64.tar.gz\`" >> release_notes.md
113+
echo "- **Linux (ARM64)**: \`jail-linux-arm64.tar.gz\`" >> release_notes.md
114+
echo "- **macOS (Intel)**: \`jail-darwin-amd64.tar.gz\`" >> release_notes.md
115+
echo "- **macOS (Apple Silicon)**: \`jail-darwin-arm64.tar.gz\`" >> release_notes.md
116+
echo "" >> release_notes.md
117+
echo "### 🛠️ Installation" >> release_notes.md
118+
echo "" >> release_notes.md
119+
echo "1. Download the appropriate binary for your platform" >> release_notes.md
120+
echo "2. Extract the archive" >> release_notes.md
121+
echo "3. Make the binary executable (Unix): `chmod +x jail`" >> release_notes.md
122+
echo "4. Move to your PATH: `sudo mv jail /usr/local/bin/` (Unix)" >> release_notes.md
123+
echo "" >> release_notes.md
124+
echo "### ✅ Verification" >> release_notes.md
125+
echo "" >> release_notes.md
126+
echo "Verify installation: `jail --help`" >> release_notes.md
127+
128+
- name: Create GitHub Release
129+
uses: softprops/action-gh-release@v2
130+
with:
131+
files: |
132+
binaries/*.tar.gz
133+
body_path: release_notes.md
134+
env:
135+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,4 @@ Thumbs.db
4646
*.pem
4747
*.crt
4848
*.key
49+
build/

Makefile

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Makefile for jail
2+
3+
# Variables
4+
BINARY_NAME := jail
5+
BUILD_DIR := build
6+
VERSION := $(shell git describe --tags --exact-match 2>/dev/null || echo "dev-$(shell git rev-parse --short HEAD)")
7+
LDFLAGS := -s -w -X main.version=$(VERSION)
8+
9+
# Default target
10+
.PHONY: all
11+
all: build
12+
13+
# Build for current platform
14+
.PHONY: build
15+
build:
16+
@echo "Building $(BINARY_NAME) for current platform..."
17+
@echo "Version: $(VERSION)"
18+
go build -ldflags="$(LDFLAGS)" -o $(BINARY_NAME) .
19+
@echo "✓ Built $(BINARY_NAME)"
20+
21+
# Build for all supported platforms
22+
.PHONY: build-all
23+
build-all:
24+
@echo "Building $(BINARY_NAME) for all platforms..."
25+
@echo "Version: $(VERSION)"
26+
@mkdir -p $(BUILD_DIR)
27+
@echo "Building Linux amd64..."
28+
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 .
29+
@echo "Building Linux arm64..."
30+
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 .
31+
@echo "Building macOS amd64..."
32+
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-amd64 .
33+
@echo "Building macOS arm64..."
34+
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-arm64 .
35+
@echo "✓ All binaries built successfully!"
36+
@echo "Binaries are in the '$(BUILD_DIR)' directory:"
37+
@ls -la $(BUILD_DIR)/
38+
39+
# Run tests
40+
.PHONY: test
41+
test:
42+
@echo "Running tests..."
43+
go test -v -race ./...
44+
@echo "✓ All tests passed!"
45+
46+
# Run tests with coverage
47+
.PHONY: test-coverage
48+
test-coverage:
49+
@echo "Running tests with coverage..."
50+
go test -v -race -coverprofile=coverage.out ./...
51+
go tool cover -html=coverage.out -o coverage.html
52+
@echo "✓ Coverage report generated: coverage.html"
53+
54+
# Clean build artifacts
55+
.PHONY: clean
56+
clean:
57+
@echo "Cleaning build artifacts..."
58+
rm -f $(BINARY_NAME)
59+
rm -rf $(BUILD_DIR)
60+
rm -f coverage.out coverage.html
61+
@echo "✓ Clean complete!"
62+
63+
# Format code
64+
.PHONY: fmt
65+
fmt:
66+
@echo "Formatting code..."
67+
go fmt ./...
68+
@echo "✓ Code formatted!"
69+
70+
# Lint code
71+
.PHONY: lint
72+
lint:
73+
@echo "Linting code..."
74+
golangci-lint run
75+
@echo "✓ Linting complete!"

0 commit comments

Comments
 (0)