Add GoReleaser configuration, CI workflows, and contributing guidelines; update .gitignore and Makefile
This commit is contained in:
80
.github/workflows/main.yml
vendored
Normal file
80
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
name: Build and test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Build
|
||||
run: make build-ci
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
install-mode: goinstall
|
||||
version: v1.64.8
|
||||
|
||||
test:
|
||||
name: Test
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Install Linux dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y bubblewrap socat
|
||||
|
||||
- name: Test
|
||||
run: make test-ci
|
||||
57
.github/workflows/release.yml
vendored
Normal file
57
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
run-name: "Release ${{ github.ref_name }}"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write # Required for SLSA
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
hashes: ${{ steps.hash.outputs.hashes }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: "~> v2"
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Generate hashes for provenance
|
||||
id: hash
|
||||
run: |
|
||||
cd dist
|
||||
echo "hashes=$(sha256sum * | grep -v checksums.txt | base64 -w0)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
provenance:
|
||||
needs: [goreleaser]
|
||||
permissions:
|
||||
actions: read
|
||||
id-token: write
|
||||
contents: write
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
|
||||
with:
|
||||
base64-subjects: "${{ needs.goreleaser.outputs.hashes }}"
|
||||
upload-assets: true
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
# Binary (only at root, not cmd/fence or pkg/fence)
|
||||
/fence
|
||||
/fence_unix
|
||||
/fence_darwin
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
@@ -15,3 +17,6 @@ Thumbs.db
|
||||
*.test
|
||||
coverage.out
|
||||
|
||||
# GoReleaser
|
||||
/dist/
|
||||
|
||||
|
||||
41
.golangci.yml
Normal file
41
.golangci.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
run:
|
||||
timeout: 5m
|
||||
modules-download-mode: readonly
|
||||
|
||||
linters-settings:
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
- default
|
||||
- prefix(github.com/Use-Tusk/fence)
|
||||
gofmt:
|
||||
simplify: true
|
||||
goimports:
|
||||
local-prefixes: github.com/Use-Tusk/fence
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- singleCaseSwitch
|
||||
revive:
|
||||
rules:
|
||||
- name: exported
|
||||
disabled: true
|
||||
|
||||
linters:
|
||||
enable-all: false
|
||||
disable-all: true
|
||||
enable:
|
||||
- staticcheck
|
||||
- errcheck
|
||||
- gosimple
|
||||
- govet
|
||||
- unused
|
||||
- ineffassign
|
||||
- gosec
|
||||
- gocritic
|
||||
- revive
|
||||
- gofumpt
|
||||
- misspell
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
|
||||
83
.goreleaser.yaml
Normal file
83
.goreleaser.yaml
Normal file
@@ -0,0 +1,83 @@
|
||||
version: 2
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
ldflags:
|
||||
- -s -w
|
||||
- -X main.version={{.Version}}
|
||||
- -X main.buildTime={{.Date}}
|
||||
- -X main.gitCommit={{.Commit}}
|
||||
binary: fence
|
||||
main: ./cmd/fence
|
||||
|
||||
archives:
|
||||
- formats: [tar.gz]
|
||||
name_template: >-
|
||||
{{ .ProjectName }}_
|
||||
{{- .Version }}_
|
||||
{{- title .Os }}_
|
||||
{{- if eq .Arch "amd64" }}x86_64
|
||||
{{- else if eq .Arch "386" }}i386
|
||||
{{- else }}{{ .Arch }}{{ end }}
|
||||
{{- if .Arm }}v{{ .Arm }}{{ end }}
|
||||
files:
|
||||
- README.md
|
||||
- LICENSE
|
||||
- ARCHITECTURE.md
|
||||
- CONTRIBUTING.md
|
||||
|
||||
checksum:
|
||||
name_template: "checksums.txt"
|
||||
|
||||
changelog:
|
||||
sort: asc
|
||||
use: github
|
||||
format: "{{ .SHA }}: {{ .Message }}{{ with .AuthorUsername }} (@{{ . }}){{ end }}"
|
||||
filters:
|
||||
exclude:
|
||||
- "^test:"
|
||||
- "^test\\("
|
||||
- "^chore: update$"
|
||||
- "^chore: docs$"
|
||||
- "^docs: update$"
|
||||
- "^chore: typo$"
|
||||
- "^chore\\(deps\\): "
|
||||
- "^(build|ci): "
|
||||
- "merge conflict"
|
||||
- Merge pull request
|
||||
- Merge remote-tracking branch
|
||||
- Merge branch
|
||||
- go mod tidy
|
||||
groups:
|
||||
- title: "New Features"
|
||||
regexp: '^.*?feat(\(.+\))??!?:.+$'
|
||||
order: 100
|
||||
- title: "Security updates"
|
||||
regexp: '^.*?sec(\(.+\))??!?:.+$'
|
||||
order: 150
|
||||
- title: "Bug fixes"
|
||||
regexp: '^.*?(fix|refactor)(\(.+\))??!?:.+$'
|
||||
order: 200
|
||||
- title: "Documentation updates"
|
||||
regexp: ^.*?docs?(\(.+\))??!?:.+$
|
||||
order: 400
|
||||
- title: Other work
|
||||
order: 9999
|
||||
|
||||
release:
|
||||
github:
|
||||
owner: Use-Tusk
|
||||
name: fence
|
||||
draft: false
|
||||
prerelease: auto
|
||||
165
CONTRIBUTING.md
Normal file
165
CONTRIBUTING.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# Contributing
|
||||
|
||||
Thanks for helping improve `fence`!
|
||||
|
||||
If you have any questions, feel free to open an issue.
|
||||
|
||||
## Quick start
|
||||
|
||||
- Requirements:
|
||||
- Go 1.25+
|
||||
- macOS or Linux
|
||||
- Clone and prepare:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Use-Tusk/fence
|
||||
cd fence
|
||||
make setup # Install deps and lint tools
|
||||
make build # Build the binary
|
||||
./fence --help
|
||||
```
|
||||
|
||||
## Dev workflow
|
||||
|
||||
Common targets:
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `make build` | Build the binary (`./fence`) |
|
||||
| `make run` | Build and run |
|
||||
| `make test` | Run tests |
|
||||
| `make test-ci` | Run tests with coverage |
|
||||
| `make deps` | Download/tidy modules |
|
||||
| `make fmt` | Format code with gofumpt |
|
||||
| `make lint` | Run golangci-lint |
|
||||
| `make build-ci` | Build with version info (used in CI) |
|
||||
| `make help` | Show all available targets |
|
||||
|
||||
## Code structure
|
||||
|
||||
See [ARCHITECTURE.md](ARCHITECTURE.md) for the full project structure and component details.
|
||||
|
||||
## Style and conventions
|
||||
|
||||
- Keep edits focused and covered by tests where possible.
|
||||
- Update [ARCHITECTURE.md](ARCHITECTURE.md) when adding features or changing behavior.
|
||||
- Prefer small, reviewable PRs with a clear rationale.
|
||||
- Run `make fmt` and `make lint` before committing.
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
make test
|
||||
|
||||
# Run with verbose output
|
||||
go test -v ./...
|
||||
|
||||
# Run with coverage
|
||||
make test-ci
|
||||
```
|
||||
|
||||
### Testing on macOS
|
||||
|
||||
```bash
|
||||
# Test blocked network request
|
||||
./fence curl https://example.com
|
||||
|
||||
# Test with allowed domain
|
||||
echo '{"network":{"allowedDomains":["example.com"]}}' > /tmp/test.json
|
||||
./fence -s /tmp/test.json curl https://example.com
|
||||
|
||||
# Test monitor mode
|
||||
./fence -m -c "touch /etc/test"
|
||||
```
|
||||
|
||||
### Testing on Linux
|
||||
|
||||
Requires `bubblewrap` and `socat`:
|
||||
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt install bubblewrap socat
|
||||
|
||||
# Test in Colima or VM
|
||||
./fence curl https://example.com
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"command not found" after go install:**
|
||||
|
||||
- Add `$GOPATH/bin` to your PATH
|
||||
- Or use `go env GOPATH` to find the path
|
||||
|
||||
**Module issues:**
|
||||
|
||||
```bash
|
||||
go mod tidy # Clean up dependencies
|
||||
```
|
||||
|
||||
**Build cache issues:**
|
||||
|
||||
```bash
|
||||
go clean -cache
|
||||
go clean -modcache
|
||||
```
|
||||
|
||||
**macOS sandbox issues:**
|
||||
|
||||
- Check `log stream --predicate 'eventMessage ENDSWITH "_SBX"'` for violations
|
||||
- Ensure you're not running as root
|
||||
|
||||
**Linux bwrap issues:**
|
||||
|
||||
- May need `sudo` or `kernel.unprivileged_userns_clone=1`
|
||||
- Check that socat and bwrap are installed
|
||||
|
||||
## For Maintainers
|
||||
|
||||
### Releasing
|
||||
|
||||
Releases are automated using [GoReleaser](https://goreleaser.com/) via GitHub Actions.
|
||||
|
||||
#### Creating a release
|
||||
|
||||
1. Tag the commit with a semantic version:
|
||||
|
||||
```bash
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
2. GitHub Actions will automatically:
|
||||
- Build binaries for all supported platforms
|
||||
- Create archives with README, LICENSE, and ARCHITECTURE.md
|
||||
- Generate checksums
|
||||
- Create a GitHub release with changelog
|
||||
- Upload all artifacts
|
||||
|
||||
#### Supported platforms
|
||||
|
||||
The release workflow builds for:
|
||||
|
||||
- **Linux**: amd64, arm64
|
||||
- **macOS (darwin)**: amd64, arm64
|
||||
|
||||
#### Building locally for distribution
|
||||
|
||||
```bash
|
||||
# Build for current platform
|
||||
make build
|
||||
|
||||
# Cross-compile
|
||||
make build-linux
|
||||
make build-darwin
|
||||
|
||||
# With version info (mimics CI builds)
|
||||
make build-ci
|
||||
```
|
||||
|
||||
To test the GoReleaser configuration locally:
|
||||
|
||||
```bash
|
||||
goreleaser release --snapshot --clean
|
||||
```
|
||||
103
Makefile
Normal file
103
Makefile
Normal file
@@ -0,0 +1,103 @@
|
||||
GOCMD=go
|
||||
GOBUILD=$(GOCMD) build
|
||||
GOCLEAN=$(GOCMD) clean
|
||||
GOTEST=$(GOCMD) test
|
||||
GOMOD=$(GOCMD) mod
|
||||
BINARY_NAME=fence
|
||||
BINARY_UNIX=$(BINARY_NAME)_unix
|
||||
|
||||
.PHONY: all build build-ci build-linux test test-ci clean deps install-lint-tools setup setup-ci run fmt lint release release-minor help
|
||||
|
||||
all: build
|
||||
|
||||
build:
|
||||
@echo "🔨 Building $(BINARY_NAME)..."
|
||||
$(GOBUILD) -o $(BINARY_NAME) -v ./cmd/fence
|
||||
|
||||
build-ci:
|
||||
@echo "🏗️ CI: Building $(BINARY_NAME) with version info..."
|
||||
$(eval VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev"))
|
||||
$(eval BUILD_TIME := $(shell date -u '+%Y-%m-%dT%H:%M:%SZ'))
|
||||
$(eval GIT_COMMIT := $(shell git rev-parse HEAD 2>/dev/null || echo "unknown"))
|
||||
$(GOBUILD) -ldflags "-s -w -X main.version=$(VERSION) -X main.buildTime=$(BUILD_TIME) -X main.gitCommit=$(GIT_COMMIT)" -o $(BINARY_NAME) -v ./cmd/fence
|
||||
|
||||
test:
|
||||
@echo "🧪 Running tests..."
|
||||
$(GOTEST) -v ./...
|
||||
|
||||
test-ci:
|
||||
@echo "🧪 CI: Running tests with coverage..."
|
||||
$(GOTEST) -v -race -coverprofile=coverage.out ./...
|
||||
|
||||
clean:
|
||||
@echo "🧹 Cleaning..."
|
||||
$(GOCLEAN)
|
||||
rm -f $(BINARY_NAME)
|
||||
rm -f $(BINARY_UNIX)
|
||||
rm -f coverage.out
|
||||
|
||||
deps:
|
||||
@echo "📦 Downloading dependencies..."
|
||||
$(GOMOD) download
|
||||
$(GOMOD) tidy
|
||||
|
||||
build-linux:
|
||||
@echo "🐧 Building for Linux..."
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BINARY_UNIX) -v ./cmd/fence
|
||||
|
||||
build-darwin:
|
||||
@echo "🍎 Building for macOS..."
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 $(GOBUILD) -o $(BINARY_NAME)_darwin -v ./cmd/fence
|
||||
|
||||
install-lint-tools:
|
||||
@echo "📦 Installing linting tools..."
|
||||
go install mvdan.cc/gofumpt@latest
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
@echo "✅ Linting tools installed"
|
||||
|
||||
setup: deps install-lint-tools
|
||||
@echo "✅ Development environment ready"
|
||||
|
||||
setup-ci: deps install-lint-tools
|
||||
@echo "✅ CI environment ready"
|
||||
|
||||
run: build
|
||||
./$(BINARY_NAME)
|
||||
|
||||
fmt:
|
||||
@echo "📝 Formatting code..."
|
||||
gofumpt -w .
|
||||
|
||||
lint:
|
||||
@echo "🔍 Linting code..."
|
||||
golangci-lint run --allow-parallel-runners
|
||||
|
||||
release:
|
||||
@echo "🚀 Creating patch release..."
|
||||
./scripts/release.sh patch
|
||||
|
||||
release-minor:
|
||||
@echo "🚀 Creating minor release..."
|
||||
./scripts/release.sh minor
|
||||
|
||||
help:
|
||||
@echo "Available targets:"
|
||||
@echo " all - build (default)"
|
||||
@echo " build - Build the binary"
|
||||
@echo " build-ci - Build for CI with version info"
|
||||
@echo " build-linux - Build for Linux"
|
||||
@echo " build-darwin - Build for macOS"
|
||||
@echo " test - Run tests"
|
||||
@echo " test-ci - Run tests for CI with coverage"
|
||||
@echo " clean - Clean build artifacts"
|
||||
@echo " deps - Download dependencies"
|
||||
@echo " install-lint-tools - Install linting tools"
|
||||
@echo " setup - Setup development environment"
|
||||
@echo " setup-ci - Setup CI environment"
|
||||
@echo " run - Build and run"
|
||||
@echo " fmt - Format code"
|
||||
@echo " lint - Lint code"
|
||||
@echo " release - Create patch release (v0.0.X)"
|
||||
@echo " release-minor - Create minor release (v0.X.0)"
|
||||
@echo " help - Show this help"
|
||||
|
||||
@@ -139,7 +139,7 @@ func parseViolation(line string) string {
|
||||
}
|
||||
|
||||
// Filter out noisy violations
|
||||
if isNoisyViolation(operation, details) {
|
||||
if isNoisyViolation(details) {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ func shouldShowViolation(operation string) bool {
|
||||
}
|
||||
|
||||
// isNoisyViolation returns true if this violation is system noise that should be filtered.
|
||||
func isNoisyViolation(operation, details string) bool {
|
||||
func isNoisyViolation(details string) bool {
|
||||
// Filter out TTY/terminal writes (very noisy from any process that prints output)
|
||||
if strings.HasPrefix(details, "/dev/tty") ||
|
||||
strings.HasPrefix(details, "/dev/pts") {
|
||||
@@ -195,4 +195,3 @@ func isNoisyViolation(operation, details string) bool {
|
||||
func GetSessionSuffix() string {
|
||||
return sessionSuffix // defined in macos.go
|
||||
}
|
||||
|
||||
|
||||
153
scripts/release.sh
Executable file
153
scripts/release.sh
Executable file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Usage: ./scripts/release.sh [patch|minor]
|
||||
# Default: patch
|
||||
|
||||
BUMP_TYPE="${1:-patch}"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
|
||||
|
||||
# Validate bump type
|
||||
if [[ "$BUMP_TYPE" != "patch" && "$BUMP_TYPE" != "minor" ]]; then
|
||||
error "Invalid bump type: $BUMP_TYPE. Use 'patch' or 'minor' (or no argument for minor)."
|
||||
fi
|
||||
|
||||
info "Bump type: $BUMP_TYPE"
|
||||
|
||||
# =============================================================================
|
||||
# Preflight checks
|
||||
# =============================================================================
|
||||
|
||||
info "Running preflight checks..."
|
||||
|
||||
# Check we're in a git repository
|
||||
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
||||
error "Not in a git repository"
|
||||
fi
|
||||
|
||||
# Check we're on the default branch (main)
|
||||
DEFAULT_BRANCH="main"
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
if [[ "$CURRENT_BRANCH" != "$DEFAULT_BRANCH" ]]; then
|
||||
error "Not on default branch. Current: $CURRENT_BRANCH, Expected: $DEFAULT_BRANCH"
|
||||
fi
|
||||
|
||||
# Check for uncommitted changes
|
||||
if ! git diff --quiet || ! git diff --staged --quiet; then
|
||||
error "Working directory has uncommitted changes. Commit or stash them first."
|
||||
fi
|
||||
|
||||
# Check for untracked files (warning only)
|
||||
UNTRACKED=$(git ls-files --others --exclude-standard)
|
||||
if [[ -n "$UNTRACKED" ]]; then
|
||||
warn "Untracked files present (continuing anyway):"
|
||||
echo "$UNTRACKED" | head -5
|
||||
fi
|
||||
|
||||
# Fetch latest from remote
|
||||
info "Fetching latest from origin..."
|
||||
git fetch origin "$DEFAULT_BRANCH" --tags
|
||||
|
||||
# Check if local branch is up to date with remote
|
||||
LOCAL_COMMIT=$(git rev-parse HEAD)
|
||||
REMOTE_COMMIT=$(git rev-parse "origin/$DEFAULT_BRANCH")
|
||||
if [[ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]]; then
|
||||
error "Local branch is not up to date with origin/$DEFAULT_BRANCH. Run 'git pull' first."
|
||||
fi
|
||||
|
||||
# Check if there are commits since last tag
|
||||
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
if [[ -n "$LAST_TAG" ]]; then
|
||||
COMMITS_SINCE_TAG=$(git rev-list "$LAST_TAG"..HEAD --count)
|
||||
if [[ "$COMMITS_SINCE_TAG" -eq 0 ]]; then
|
||||
error "No commits since last tag ($LAST_TAG). Nothing to release."
|
||||
fi
|
||||
info "Commits since $LAST_TAG: $COMMITS_SINCE_TAG"
|
||||
fi
|
||||
|
||||
# Check that tests pass
|
||||
info "Running tests..."
|
||||
if ! make test-ci; then
|
||||
error "Tests failed. Fix them before releasing."
|
||||
fi
|
||||
|
||||
# Check that lint passes
|
||||
info "Running linter..."
|
||||
if ! make lint; then
|
||||
error "Lint failed. Fix issues before releasing."
|
||||
fi
|
||||
|
||||
info "✓ All preflight checks passed"
|
||||
|
||||
# =============================================================================
|
||||
# Calculate new version
|
||||
# =============================================================================
|
||||
|
||||
if [[ -z "$LAST_TAG" ]]; then
|
||||
# No existing tags, start at v0.1.0
|
||||
NEW_VERSION="v0.1.0"
|
||||
info "No existing tags found. Starting at $NEW_VERSION"
|
||||
else
|
||||
# Parse current version (strip 'v' prefix)
|
||||
VERSION="${LAST_TAG#v}"
|
||||
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
|
||||
|
||||
# Validate parsed version
|
||||
if [[ -z "$MAJOR" || -z "$MINOR" || -z "$PATCH" ]]; then
|
||||
error "Failed to parse version from tag: $LAST_TAG"
|
||||
fi
|
||||
|
||||
# Increment based on bump type
|
||||
case "$BUMP_TYPE" in
|
||||
patch)
|
||||
PATCH=$((PATCH + 1))
|
||||
;;
|
||||
minor)
|
||||
MINOR=$((MINOR + 1))
|
||||
PATCH=0
|
||||
;;
|
||||
esac
|
||||
|
||||
NEW_VERSION="v${MAJOR}.${MINOR}.${PATCH}"
|
||||
info "Version bump: $LAST_TAG → $NEW_VERSION"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Confirm and create tag
|
||||
# =============================================================================
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo " Ready to release: $NEW_VERSION"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
read -p "Create and push tag $NEW_VERSION? [y/N] " -n 1 -r
|
||||
echo ""
|
||||
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
info "Aborted."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create annotated tag
|
||||
info "Creating tag $NEW_VERSION..."
|
||||
git tag -a "$NEW_VERSION" -m "Release $NEW_VERSION"
|
||||
|
||||
# Push tag to origin
|
||||
info "Pushing tag to origin..."
|
||||
git push origin "$NEW_VERSION"
|
||||
|
||||
echo ""
|
||||
info "✓ Released $NEW_VERSION"
|
||||
info "GitHub Actions will now build and publish the release."
|
||||
info "Watch progress at: https://github.com/Use-Tusk/fence/actions"
|
||||
Reference in New Issue
Block a user