mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-23 08:20:26 +00:00
40ba104838
This commit introduces major enhancements to the CI/CD pipeline and testing infrastructure: CI/CD Improvements: - Consolidated modern and legacy CI workflows into a single comprehensive pipeline - Removed all publishing functionality from CI (no longer needed) - Added 8 new advanced testing jobs for pull requests: * advanced-coverage: Detailed coverage analysis with base branch comparison * performance-profile: CPU and memory profiling with benchmarks * fuzz-test: Automated fuzz testing for supported packages * deep-analysis: Multiple static analysis tools (shadow, ineffassign, gosec, staticcheck) * mutation-test: Tests effectiveness of test suite on changed files * dependency-audit: Security vulnerabilities and outdated dependency checks * stress-test: Race detection with 100 iterations and parallel testing * test-report-summary: Aggregates all reports into a single PR comment - Enabled RUN_LONG_TESTS by default for thorough testing - Added automatic PR comment generation with all test results Testing Infrastructure: - Added comprehensive test files across all packages to improve coverage - Implemented unit tests for previously untested packages - Added race condition tests for concurrent operations - Created integration tests for API endpoints - Added storage backend tests (etcd, goleveldb) - Implemented command-line interface tests Local Testing Support: - Added act configuration for testing GitHub Actions locally - Created docker-compose.ci.yml for full CI environment simulation - Updated CONTRIBUTING.md with detailed local testing instructions Documentation Updates: - Added comprehensive CI documentation to CONTRIBUTING.md - Removed obsolete references to Travis CI - Updated Go version requirements to 1.24 - Added act usage instructions and examples Other Improvements: - Updated .gitignore to exclude coverage reports and build artifacts - Added test-act.yml workflow for testing act functionality - Created CI_SUMMARY.md documenting all CI capabilities These changes transform aptly's CI from a basic testing pipeline into a comprehensive quality assurance system that provides immediate feedback on code quality, performance, security, and test effectiveness.
1336 lines
43 KiB
YAML
1336 lines
43 KiB
YAML
name: CI Pipeline
|
||
|
||
on:
|
||
pull_request:
|
||
push:
|
||
tags:
|
||
- 'v*'
|
||
branches:
|
||
- 'master'
|
||
schedule:
|
||
# Run security checks daily
|
||
- cron: '0 2 * * *'
|
||
|
||
env:
|
||
GOLANGCI_LINT_VERSION: v1.64.5
|
||
|
||
defaults:
|
||
run:
|
||
shell: bash --noprofile --norc -eo pipefail {0}
|
||
|
||
jobs:
|
||
# Quick checks that should fail fast
|
||
quick-checks:
|
||
name: Quick Checks
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Check formatting
|
||
run: |
|
||
if [ -n "$(gofmt -l .)" ]; then
|
||
echo "Go code is not formatted:"
|
||
gofmt -d .
|
||
exit 1
|
||
fi
|
||
|
||
- name: Run go vet
|
||
run: go vet ./...
|
||
|
||
- name: Check go mod tidy
|
||
run: |
|
||
go mod tidy
|
||
git diff --exit-code go.mod go.sum
|
||
|
||
- name: Run flake8
|
||
run: |
|
||
sudo apt-get update && sudo apt-get install -y flake8
|
||
make flake8
|
||
|
||
# Security scanning
|
||
security:
|
||
name: Security Scan
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Run govulncheck
|
||
run: |
|
||
go install golang.org/x/vuln/cmd/govulncheck@latest
|
||
govulncheck ./...
|
||
|
||
- name: Run Trivy vulnerability scanner
|
||
uses: aquasecurity/trivy-action@master
|
||
with:
|
||
scan-type: 'fs'
|
||
scan-ref: '.'
|
||
format: 'sarif'
|
||
output: 'trivy-results.sarif'
|
||
|
||
- name: Upload Trivy scan results
|
||
uses: github/codeql-action/upload-sarif@v3
|
||
if: always()
|
||
with:
|
||
sarif_file: 'trivy-results.sarif'
|
||
|
||
# Linting
|
||
lint:
|
||
name: Lint
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: golangci-lint
|
||
uses: golangci/golangci-lint-action@v6
|
||
with:
|
||
version: ${{ env.GOLANGCI_LINT_VERSION }}
|
||
args: --timeout=5m
|
||
|
||
# Unit tests with coverage
|
||
test-unit:
|
||
name: Unit Tests
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
strategy:
|
||
matrix:
|
||
go: ['1.23', '1.24']
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ matrix.go }}
|
||
cache: true
|
||
|
||
- name: Install etcd
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y etcd
|
||
|
||
- name: Run tests
|
||
run: |
|
||
go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
|
||
env:
|
||
RUN_LONG_TESTS: yes
|
||
|
||
- name: Upload coverage
|
||
uses: codecov/codecov-action@v4
|
||
if: matrix.go == '1.24'
|
||
with:
|
||
file: ./coverage.out
|
||
flags: unittests
|
||
name: codecov-umbrella
|
||
|
||
# Integration tests
|
||
test-integration:
|
||
name: Integration Tests
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Set up Python
|
||
uses: actions/setup-python@v5
|
||
with:
|
||
python-version: '3.x'
|
||
|
||
- name: Install system dependencies
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y \
|
||
bzip2 \
|
||
xz-utils \
|
||
graphviz \
|
||
gnupg2 \
|
||
gpgv2 \
|
||
etcd \
|
||
azurite \
|
||
git \
|
||
gcc \
|
||
make \
|
||
devscripts \
|
||
python3 \
|
||
python3-requests-unixsocket \
|
||
python3-termcolor \
|
||
python3-swiftclient \
|
||
python3-boto \
|
||
python3-azure-storage \
|
||
python3-etcd3 \
|
||
python3-plyvel \
|
||
faketime
|
||
|
||
- name: Install Python dependencies
|
||
run: |
|
||
pip install -r system/requirements.txt
|
||
|
||
- name: Download test fixtures
|
||
run: |
|
||
git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/
|
||
git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/
|
||
|
||
- name: Run system tests
|
||
run: |
|
||
make system-test
|
||
env:
|
||
RUN_LONG_TESTS: yes
|
||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||
AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }}
|
||
AZURE_STORAGE_KEY: ${{ secrets.AZURE_STORAGE_KEY }}
|
||
|
||
# Benchmarks
|
||
benchmarks:
|
||
name: Benchmarks
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Install etcd
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y etcd
|
||
|
||
- name: Run benchmarks
|
||
run: |
|
||
make bench
|
||
|
||
# Extended test job with coverage merging
|
||
test-extended:
|
||
name: Extended Tests with Coverage
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Install dependencies
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y etcd
|
||
go install github.com/wadey/gocovmerge@latest
|
||
|
||
- name: Run unit tests with coverage
|
||
run: |
|
||
go test -v -coverprofile=unit.coverage -covermode=count ./...
|
||
env:
|
||
RUN_LONG_TESTS: yes
|
||
|
||
- name: Run benchmarks with coverage
|
||
run: |
|
||
go test -v -bench=. -benchmem -coverprofile=bench.coverage -covermode=count ./...
|
||
|
||
- name: Merge coverage files
|
||
run: |
|
||
gocovmerge unit.coverage bench.coverage > coverage.out
|
||
|
||
- name: Upload merged coverage
|
||
uses: codecov/codecov-action@v4
|
||
with:
|
||
file: ./coverage.out
|
||
flags: extended
|
||
name: codecov-extended
|
||
|
||
# Advanced coverage analysis with PR comments
|
||
advanced-coverage:
|
||
name: Advanced Coverage Analysis
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
if: github.event_name == 'pull_request'
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Checkout base branch
|
||
run: |
|
||
git fetch origin ${{ github.base_ref }}:base
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Install dependencies
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y etcd
|
||
go install github.com/jandelgado/gcov2lcov@latest
|
||
go install github.com/nikolaydubina/go-cover-treemap@latest
|
||
|
||
- name: Run tests with coverage on PR branch
|
||
run: |
|
||
go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
|
||
go tool cover -func=coverage.out > coverage-summary.txt
|
||
go tool cover -html=coverage.out -o coverage.html
|
||
|
||
# Generate treemap
|
||
go-cover-treemap -coverprofile coverage.out > coverage-treemap.svg
|
||
|
||
# Calculate total coverage
|
||
TOTAL_COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
|
||
echo "TOTAL_COVERAGE=$TOTAL_COVERAGE" >> $GITHUB_ENV
|
||
|
||
- name: Run tests with coverage on base branch
|
||
run: |
|
||
git checkout base
|
||
go test -coverprofile=base-coverage.out -covermode=atomic ./... || true
|
||
BASE_COVERAGE=$(go tool cover -func=base-coverage.out | grep total | awk '{print $3}' | sed 's/%//' || echo "0")
|
||
echo "BASE_COVERAGE=$BASE_COVERAGE" >> $GITHUB_ENV
|
||
git checkout -
|
||
|
||
- name: Generate coverage report
|
||
run: |
|
||
# Generate detailed package coverage
|
||
echo "# Coverage Report" > coverage-report.md
|
||
echo "" >> coverage-report.md
|
||
echo "## Summary" >> coverage-report.md
|
||
echo "- **Total Coverage**: ${{ env.TOTAL_COVERAGE }}%" >> coverage-report.md
|
||
echo "- **Base Coverage**: ${{ env.BASE_COVERAGE }}%" >> coverage-report.md
|
||
COVERAGE_DIFF=$(echo "${{ env.TOTAL_COVERAGE }} - ${{ env.BASE_COVERAGE }}" | bc)
|
||
echo "- **Change**: ${COVERAGE_DIFF}%" >> coverage-report.md
|
||
echo "" >> coverage-report.md
|
||
echo "## Package Coverage" >> coverage-report.md
|
||
echo '```' >> coverage-report.md
|
||
cat coverage-summary.txt >> coverage-report.md
|
||
echo '```' >> coverage-report.md
|
||
|
||
- name: Upload coverage artifacts
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: coverage-report
|
||
path: |
|
||
coverage.html
|
||
coverage-treemap.svg
|
||
coverage-report.md
|
||
coverage-summary.txt
|
||
|
||
- name: Comment PR
|
||
uses: peter-evans/create-or-update-comment@v4
|
||
with:
|
||
issue-number: ${{ github.event.pull_request.number }}
|
||
body-path: coverage-report.md
|
||
|
||
# Performance profiling
|
||
performance-profile:
|
||
name: Performance Profiling
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
if: github.event_name == 'pull_request'
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Install dependencies
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y etcd graphviz
|
||
go install github.com/google/pprof@latest
|
||
|
||
- name: Run benchmarks with profiling
|
||
run: |
|
||
# Run benchmarks with CPU and memory profiling
|
||
go test -bench=. -benchmem -cpuprofile=cpu.prof -memprofile=mem.prof -benchtime=10s ./deb || true
|
||
|
||
# Generate reports
|
||
go tool pprof -svg cpu.prof > cpu-profile.svg || true
|
||
go tool pprof -svg mem.prof > mem-profile.svg || true
|
||
|
||
# Generate text reports
|
||
go tool pprof -text cpu.prof > cpu-profile.txt || true
|
||
go tool pprof -text mem.prof > mem-profile.txt || true
|
||
|
||
# Create summary
|
||
echo "# Performance Profile Report" > performance-report.md
|
||
echo "" >> performance-report.md
|
||
echo "## CPU Profile Top Functions" >> performance-report.md
|
||
echo '```' >> performance-report.md
|
||
head -20 cpu-profile.txt >> performance-report.md || echo "No CPU profile data" >> performance-report.md
|
||
echo '```' >> performance-report.md
|
||
echo "" >> performance-report.md
|
||
echo "## Memory Profile Top Allocations" >> performance-report.md
|
||
echo '```' >> performance-report.md
|
||
head -20 mem-profile.txt >> performance-report.md || echo "No memory profile data" >> performance-report.md
|
||
echo '```' >> performance-report.md
|
||
|
||
- name: Upload profile artifacts
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: performance-profiles
|
||
path: |
|
||
*.prof
|
||
*.svg
|
||
performance-report.md
|
||
|
||
# Fuzz testing
|
||
fuzz-test:
|
||
name: Fuzz Testing
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
if: github.event_name == 'pull_request'
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Run fuzz tests
|
||
run: |
|
||
echo "# Fuzz Testing Report" > fuzz-report.md
|
||
echo "" >> fuzz-report.md
|
||
echo "## Results" >> fuzz-report.md
|
||
|
||
# Find and run any fuzz tests
|
||
FUZZ_FOUND=false
|
||
for pkg in $(go list ./...); do
|
||
if go test -list "^Fuzz" $pkg 2>/dev/null | grep -q "^Fuzz"; then
|
||
FUZZ_FOUND=true
|
||
echo "Running fuzz tests in $pkg..." >> fuzz-report.md
|
||
if go test -fuzz=. -fuzztime=30s $pkg 2>&1 | tee fuzz-output.txt; then
|
||
echo "✅ Passed" >> fuzz-report.md
|
||
else
|
||
echo "❌ Failed" >> fuzz-report.md
|
||
cat fuzz-output.txt >> fuzz-report.md
|
||
fi
|
||
echo "" >> fuzz-report.md
|
||
fi
|
||
done
|
||
|
||
if [ "$FUZZ_FOUND" = false ]; then
|
||
echo "ℹ️ No fuzz tests found in the codebase" >> fuzz-report.md
|
||
fi
|
||
|
||
- name: Upload fuzz artifacts
|
||
uses: actions/upload-artifact@v4
|
||
if: always()
|
||
with:
|
||
name: fuzz-test-results
|
||
path: |
|
||
fuzz-report.md
|
||
testdata/fuzz/
|
||
|
||
# Static analysis suite
|
||
deep-analysis:
|
||
name: Deep Static Analysis
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
if: github.event_name == 'pull_request'
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
security-events: write
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Install analysis tools
|
||
run: |
|
||
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest
|
||
go install github.com/gordonklaus/ineffassign@latest
|
||
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||
go install github.com/nishanths/exhaustive/cmd/exhaustive@latest
|
||
|
||
- name: Run analysis suite
|
||
run: |
|
||
echo "# Static Analysis Report" > analysis-report.md
|
||
echo "" >> analysis-report.md
|
||
|
||
# Shadow detection
|
||
echo "## Shadow Variable Detection" >> analysis-report.md
|
||
if go vet -vettool=$(which shadow) ./... 2>&1 | tee shadow.txt | grep -q "shadowed variable"; then
|
||
echo "⚠️ Shadow variables detected:" >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
cat shadow.txt >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
else
|
||
echo "✅ No shadow variables detected" >> analysis-report.md
|
||
fi
|
||
echo "" >> analysis-report.md
|
||
|
||
# Ineffectual assignments
|
||
echo "## Ineffectual Assignments" >> analysis-report.md
|
||
if ineffassign ./... 2>&1 | tee ineffassign.txt | grep -q ".go:"; then
|
||
echo "⚠️ Ineffectual assignments found:" >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
cat ineffassign.txt >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
else
|
||
echo "✅ No ineffectual assignments" >> analysis-report.md
|
||
fi
|
||
echo "" >> analysis-report.md
|
||
|
||
# Security scan
|
||
echo "## Security Scan (gosec)" >> analysis-report.md
|
||
gosec -fmt=json -out=gosec.json ./... || true
|
||
if [ -s gosec.json ] && [ $(jq '.Issues | length' gosec.json) -gt 0 ]; then
|
||
echo "⚠️ Security issues found:" >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
jq -r '.Issues[] | "[\(.severity)] \(.file):\(.line) - \(.details)"' gosec.json >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
else
|
||
echo "✅ No security issues found" >> analysis-report.md
|
||
fi
|
||
echo "" >> analysis-report.md
|
||
|
||
# Staticcheck
|
||
echo "## Staticcheck Analysis" >> analysis-report.md
|
||
if staticcheck ./... 2>&1 | tee staticcheck.txt | grep -q ".go:"; then
|
||
echo "ℹ️ Staticcheck suggestions:" >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
cat staticcheck.txt >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
else
|
||
echo "✅ No staticcheck issues" >> analysis-report.md
|
||
fi
|
||
echo "" >> analysis-report.md
|
||
|
||
# Exhaustive enum checks
|
||
echo "## Exhaustive Enum Switch Analysis" >> analysis-report.md
|
||
if exhaustive ./... 2>&1 | tee exhaustive.txt | grep -q ".go:"; then
|
||
echo "⚠️ Non-exhaustive switches found:" >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
cat exhaustive.txt >> analysis-report.md
|
||
echo '```' >> analysis-report.md
|
||
else
|
||
echo "✅ All enum switches are exhaustive" >> analysis-report.md
|
||
fi
|
||
|
||
- name: Upload analysis artifacts
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: static-analysis-results
|
||
path: |
|
||
analysis-report.md
|
||
*.json
|
||
*.txt
|
||
|
||
- name: Upload SARIF if available
|
||
uses: github/codeql-action/upload-sarif@v3
|
||
if: always()
|
||
continue-on-error: true
|
||
with:
|
||
sarif_file: gosec.sarif
|
||
|
||
# Mutation testing
|
||
mutation-test:
|
||
name: Mutation Testing
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
if: github.event_name == 'pull_request'
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Install mutation testing tool
|
||
run: |
|
||
go install github.com/zimmski/go-mutesting/cmd/go-mutesting@latest
|
||
sudo apt-get update && sudo apt-get install -y etcd
|
||
|
||
- name: Run mutation tests on changed files
|
||
run: |
|
||
echo "# Mutation Testing Report" > mutation-report.md
|
||
echo "" >> mutation-report.md
|
||
|
||
# Get changed Go files
|
||
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep '\.go$' | grep -v '_test\.go$' || true)
|
||
|
||
if [ -z "$CHANGED_FILES" ]; then
|
||
echo "ℹ️ No Go source files changed" >> mutation-report.md
|
||
else
|
||
echo "## Mutation Testing Results" >> mutation-report.md
|
||
echo "" >> mutation-report.md
|
||
|
||
TOTAL_MUTANTS=0
|
||
KILLED_MUTANTS=0
|
||
|
||
for file in $CHANGED_FILES; do
|
||
if [ -f "$file" ]; then
|
||
echo "Testing mutations in $file..." >> mutation-report.md
|
||
|
||
# Run mutation testing with timeout
|
||
timeout 300 go-mutesting -verbose -include="$file" . 2>&1 | tee mutation-output.txt || true
|
||
|
||
# Parse results
|
||
KILLED=$(grep -c "PASS" mutation-output.txt || echo "0")
|
||
TOTAL=$(grep -c "MUTATION" mutation-output.txt || echo "0")
|
||
|
||
TOTAL_MUTANTS=$((TOTAL_MUTANTS + TOTAL))
|
||
KILLED_MUTANTS=$((KILLED_MUTANTS + KILLED))
|
||
|
||
if [ "$TOTAL" -gt 0 ]; then
|
||
SCORE=$((KILLED * 100 / TOTAL))
|
||
echo "- $file: $KILLED/$TOTAL mutants killed (${SCORE}%)" >> mutation-report.md
|
||
fi
|
||
fi
|
||
done
|
||
|
||
if [ "$TOTAL_MUTANTS" -gt 0 ]; then
|
||
TOTAL_SCORE=$((KILLED_MUTANTS * 100 / TOTAL_MUTANTS))
|
||
echo "" >> mutation-report.md
|
||
echo "**Total: $KILLED_MUTANTS/$TOTAL_MUTANTS mutants killed (${TOTAL_SCORE}%)**" >> mutation-report.md
|
||
fi
|
||
fi
|
||
|
||
- name: Upload mutation artifacts
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: mutation-test-results
|
||
path: mutation-report.md
|
||
|
||
# Dependency audit
|
||
dependency-audit:
|
||
name: Dependency Audit
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
if: github.event_name == 'pull_request'
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Install audit tools
|
||
run: |
|
||
go install github.com/sonatype-nexus-community/nancy@latest
|
||
go install github.com/Zxilly/go-size-analyzer/cmd/gsa@latest
|
||
|
||
- name: Run dependency audit
|
||
run: |
|
||
echo "# Dependency Audit Report" > dependency-report.md
|
||
echo "" >> dependency-report.md
|
||
|
||
# Check for outdated dependencies
|
||
echo "## Outdated Dependencies" >> dependency-report.md
|
||
go list -u -m all | grep '\[' > outdated.txt || true
|
||
if [ -s outdated.txt ]; then
|
||
echo "⚠️ Found outdated dependencies:" >> dependency-report.md
|
||
echo '```' >> dependency-report.md
|
||
cat outdated.txt >> dependency-report.md
|
||
echo '```' >> dependency-report.md
|
||
else
|
||
echo "✅ All dependencies are up to date" >> dependency-report.md
|
||
fi
|
||
echo "" >> dependency-report.md
|
||
|
||
# Vulnerability scan
|
||
echo "## Vulnerability Scan (Nancy)" >> dependency-report.md
|
||
go list -json -m all | nancy sleuth 2>&1 | tee nancy.txt || true
|
||
if grep -q "Vulnerable" nancy.txt; then
|
||
echo "⚠️ Vulnerabilities found:" >> dependency-report.md
|
||
echo '```' >> dependency-report.md
|
||
grep -A5 "Vulnerable" nancy.txt >> dependency-report.md
|
||
echo '```' >> dependency-report.md
|
||
else
|
||
echo "✅ No known vulnerabilities" >> dependency-report.md
|
||
fi
|
||
echo "" >> dependency-report.md
|
||
|
||
# Dependency graph
|
||
echo "## Dependency Statistics" >> dependency-report.md
|
||
DIRECT_DEPS=$(go list -m all | grep -v "^github.com/aptly-dev/aptly" | wc -l)
|
||
echo "- Direct dependencies: $DIRECT_DEPS" >> dependency-report.md
|
||
|
||
# Binary size analysis
|
||
echo "" >> dependency-report.md
|
||
echo "## Binary Size Analysis" >> dependency-report.md
|
||
go build -o aptly-binary || true
|
||
if [ -f aptly-binary ]; then
|
||
SIZE=$(du -h aptly-binary | cut -f1)
|
||
echo "- Binary size: $SIZE" >> dependency-report.md
|
||
|
||
# Analyze size
|
||
gsa aptly-binary -o size-analysis.txt || true
|
||
if [ -f size-analysis.txt ]; then
|
||
echo "### Top packages by size:" >> dependency-report.md
|
||
echo '```' >> dependency-report.md
|
||
head -20 size-analysis.txt >> dependency-report.md
|
||
echo '```' >> dependency-report.md
|
||
fi
|
||
fi
|
||
|
||
- name: Upload dependency artifacts
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: dependency-audit-results
|
||
path: |
|
||
dependency-report.md
|
||
*.txt
|
||
|
||
# Stress testing
|
||
stress-test:
|
||
name: Stress Testing
|
||
runs-on: ubuntu-latest
|
||
needs: quick-checks
|
||
if: github.event_name == 'pull_request'
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Install dependencies
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y etcd
|
||
|
||
- name: Run stress tests
|
||
run: |
|
||
echo "# Stress Testing Report" > stress-report.md
|
||
echo "" >> stress-report.md
|
||
|
||
# Run race detection with multiple iterations
|
||
echo "## Race Detection (100 iterations)" >> stress-report.md
|
||
if go test -race -count=100 -timeout=30m ./utils ./database/goleveldb ./context 2>&1 | tee race-stress.txt; then
|
||
echo "✅ No races detected in 100 iterations" >> stress-report.md
|
||
else
|
||
echo "❌ Race conditions detected:" >> stress-report.md
|
||
echo '```' >> stress-report.md
|
||
grep -A10 "WARNING: DATA RACE" race-stress.txt | head -50 >> stress-report.md
|
||
echo '```' >> stress-report.md
|
||
fi
|
||
echo "" >> stress-report.md
|
||
|
||
# Parallel stress test
|
||
echo "## Parallel Execution Test" >> stress-report.md
|
||
if go test -parallel=10 -count=10 ./deb 2>&1 | tee parallel-stress.txt; then
|
||
echo "✅ Parallel tests passed" >> stress-report.md
|
||
else
|
||
echo "❌ Parallel test failures" >> stress-report.md
|
||
tail -50 parallel-stress.txt >> stress-report.md
|
||
fi
|
||
echo "" >> stress-report.md
|
||
|
||
# Memory stress test
|
||
echo "## Memory Stress Test" >> stress-report.md
|
||
GOGC=10 go test -run=TestPackageCollection -count=50 ./deb 2>&1 | tee memory-stress.txt || true
|
||
echo "✅ Memory stress test completed" >> stress-report.md
|
||
|
||
- name: Upload stress test artifacts
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: stress-test-results
|
||
path: |
|
||
stress-report.md
|
||
*-stress.txt
|
||
|
||
# Aggregate all reports into a single PR comment
|
||
test-report-summary:
|
||
name: Test Report Summary
|
||
runs-on: ubuntu-latest
|
||
needs: [advanced-coverage, performance-profile, fuzz-test, deep-analysis, mutation-test, dependency-audit, stress-test]
|
||
if: always() && github.event_name == 'pull_request'
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
steps:
|
||
- name: Download all artifacts
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
path: reports
|
||
|
||
- name: Create combined report
|
||
run: |
|
||
echo "# 📊 Comprehensive Test Report for PR #${{ github.event.pull_request.number }}" > combined-report.md
|
||
echo "" >> combined-report.md
|
||
echo "*Generated at $(date -u)*" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
|
||
# Coverage section
|
||
if [ -f reports/coverage-report/coverage-report.md ]; then
|
||
cat reports/coverage-report/coverage-report.md >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
echo "[📄 Full HTML Report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
fi
|
||
|
||
# Performance section
|
||
if [ -f reports/performance-profiles/performance-report.md ]; then
|
||
echo "<details>" >> combined-report.md
|
||
echo "<summary>🔥 Performance Profile</summary>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
cat reports/performance-profiles/performance-report.md >> combined-report.md
|
||
echo "</details>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
fi
|
||
|
||
# Fuzz testing section
|
||
if [ -f reports/fuzz-test-results/fuzz-report.md ]; then
|
||
echo "<details>" >> combined-report.md
|
||
echo "<summary>🧬 Fuzz Testing</summary>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
cat reports/fuzz-test-results/fuzz-report.md >> combined-report.md
|
||
echo "</details>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
fi
|
||
|
||
# Static analysis section
|
||
if [ -f reports/static-analysis-results/analysis-report.md ]; then
|
||
echo "<details>" >> combined-report.md
|
||
echo "<summary>🔍 Static Analysis</summary>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
cat reports/static-analysis-results/analysis-report.md >> combined-report.md
|
||
echo "</details>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
fi
|
||
|
||
# Mutation testing section
|
||
if [ -f reports/mutation-test-results/mutation-report.md ]; then
|
||
echo "<details>" >> combined-report.md
|
||
echo "<summary>🦠 Mutation Testing</summary>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
cat reports/mutation-test-results/mutation-report.md >> combined-report.md
|
||
echo "</details>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
fi
|
||
|
||
# Dependency audit section
|
||
if [ -f reports/dependency-audit-results/dependency-report.md ]; then
|
||
echo "<details>" >> combined-report.md
|
||
echo "<summary>📦 Dependency Audit</summary>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
cat reports/dependency-audit-results/dependency-report.md >> combined-report.md
|
||
echo "</details>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
fi
|
||
|
||
# Stress test section
|
||
if [ -f reports/stress-test-results/stress-report.md ]; then
|
||
echo "<details>" >> combined-report.md
|
||
echo "<summary>💪 Stress Testing</summary>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
cat reports/stress-test-results/stress-report.md >> combined-report.md
|
||
echo "</details>" >> combined-report.md
|
||
echo "" >> combined-report.md
|
||
fi
|
||
|
||
echo "---" >> combined-report.md
|
||
echo "*View detailed artifacts in the [Actions run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})*" >> combined-report.md
|
||
|
||
- name: Find Comment
|
||
uses: peter-evans/find-comment@v3
|
||
id: fc
|
||
with:
|
||
issue-number: ${{ github.event.pull_request.number }}
|
||
comment-author: 'github-actions[bot]'
|
||
body-includes: Comprehensive Test Report
|
||
|
||
- name: Create or Update Comment
|
||
uses: peter-evans/create-or-update-comment@v4
|
||
with:
|
||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||
issue-number: ${{ github.event.pull_request.number }}
|
||
body-path: combined-report.md
|
||
edit-mode: replace
|
||
# Build artifacts
|
||
build:
|
||
name: Build
|
||
runs-on: ubuntu-latest
|
||
needs: [lint, test-unit]
|
||
strategy:
|
||
matrix:
|
||
include:
|
||
- os: linux
|
||
arch: amd64
|
||
- os: linux
|
||
arch: arm64
|
||
- os: darwin
|
||
arch: amd64
|
||
- os: darwin
|
||
arch: arm64
|
||
- os: windows
|
||
arch: amd64
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Build
|
||
run: |
|
||
GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} go build \
|
||
-ldflags "-X main.Version=${GITHUB_SHA::8}" \
|
||
-o aptly-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.os == 'windows' && '.exe' || '' }}
|
||
|
||
- name: Upload artifact
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: aptly-${{ matrix.os }}-${{ matrix.arch }}
|
||
path: aptly-${{ matrix.os }}-${{ matrix.arch }}*
|
||
|
||
# Docker build
|
||
docker:
|
||
name: Docker Build
|
||
runs-on: ubuntu-latest
|
||
needs: [lint, test-unit]
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Set up Docker Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
|
||
- name: Build Docker image
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
context: .
|
||
platforms: linux/amd64,linux/arm64
|
||
push: false
|
||
tags: |
|
||
aptly/aptly:latest
|
||
aptly/aptly:${{ github.sha }}
|
||
cache-from: type=gha
|
||
cache-to: type=gha,mode=max
|
||
|
||
# Debian package building
|
||
debian-packages:
|
||
name: Build Debian Packages
|
||
runs-on: ubuntu-22.04
|
||
needs: [lint, test-unit]
|
||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||
strategy:
|
||
matrix:
|
||
include:
|
||
- distribution: debian
|
||
release: buster
|
||
arch: amd64
|
||
- distribution: debian
|
||
release: bullseye
|
||
arch: amd64
|
||
- distribution: debian
|
||
release: bookworm
|
||
arch: amd64
|
||
- distribution: debian
|
||
release: trixie
|
||
arch: amd64
|
||
- distribution: ubuntu
|
||
release: focal
|
||
arch: amd64
|
||
- distribution: ubuntu
|
||
release: jammy
|
||
arch: amd64
|
||
- distribution: ubuntu
|
||
release: noble
|
||
arch: amd64
|
||
# ARM builds
|
||
- distribution: debian
|
||
release: bullseye
|
||
arch: arm64
|
||
- distribution: debian
|
||
release: bookworm
|
||
arch: arm64
|
||
- distribution: ubuntu
|
||
release: jammy
|
||
arch: arm64
|
||
- distribution: ubuntu
|
||
release: noble
|
||
arch: arm64
|
||
# 32-bit builds
|
||
- distribution: debian
|
||
release: bullseye
|
||
arch: i386
|
||
- distribution: debian
|
||
release: bookworm
|
||
arch: i386
|
||
- distribution: debian
|
||
release: bullseye
|
||
arch: armhf
|
||
- distribution: debian
|
||
release: bookworm
|
||
arch: armhf
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Set up QEMU
|
||
if: matrix.arch != 'amd64' && matrix.arch != 'i386'
|
||
uses: docker/setup-qemu-action@v3
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
|
||
- name: Setup CI version suffix
|
||
if: github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/')
|
||
run: |
|
||
echo "CI_VERSION_SUFFIX=+ci" >> $GITHUB_ENV
|
||
|
||
- name: Build Debian package
|
||
run: |
|
||
export DEBIAN_FRONTEND=noninteractive
|
||
|
||
# Install build dependencies
|
||
sudo apt-get update
|
||
sudo apt-get install -y devscripts dpkg-dev
|
||
|
||
# Install cross-compilation tools if needed
|
||
if [[ "${{ matrix.arch }}" != "amd64" && "${{ matrix.arch }}" != "i386" ]]; then
|
||
sudo apt-get install -y gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf
|
||
fi
|
||
|
||
# Set up environment for cross-compilation
|
||
case "${{ matrix.arch }}" in
|
||
i386)
|
||
export GOARCH=386
|
||
;;
|
||
arm64)
|
||
export GOARCH=arm64
|
||
export CC=aarch64-linux-gnu-gcc
|
||
;;
|
||
armhf)
|
||
export GOARCH=arm
|
||
export GOARM=7
|
||
export CC=arm-linux-gnueabihf-gcc
|
||
;;
|
||
*)
|
||
export GOARCH=amd64
|
||
;;
|
||
esac
|
||
|
||
# Build the package
|
||
make dpkg DEBIAN_RELEASE=${{ matrix.release }} ARCHITECTURE=${{ matrix.arch }}
|
||
|
||
- name: Upload packages
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: debian-${{ matrix.distribution }}-${{ matrix.release }}-${{ matrix.arch }}
|
||
path: build/*.deb
|
||
retention-days: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && 90 || 7 }}
|
||
|
||
# Binary builds with expanded platform support
|
||
binary-builds:
|
||
name: Build Binaries
|
||
runs-on: ubuntu-latest
|
||
needs: [lint, test-unit]
|
||
strategy:
|
||
matrix:
|
||
include:
|
||
# 64-bit builds
|
||
- os: linux
|
||
arch: amd64
|
||
- os: linux
|
||
arch: arm64
|
||
- os: darwin
|
||
arch: amd64
|
||
- os: darwin
|
||
arch: arm64
|
||
- os: windows
|
||
arch: amd64
|
||
- os: freebsd
|
||
arch: amd64
|
||
# 32-bit builds
|
||
- os: linux
|
||
arch: 386
|
||
- os: linux
|
||
arch: arm
|
||
- os: windows
|
||
arch: 386
|
||
- os: freebsd
|
||
arch: 386
|
||
- os: freebsd
|
||
arch: arm
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
|
||
- name: Setup version
|
||
run: |
|
||
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||
VERSION=${GITHUB_REF#refs/tags/}
|
||
else
|
||
VERSION=$(make version)
|
||
fi
|
||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||
|
||
- name: Build binary
|
||
run: |
|
||
# Set architecture-specific variables
|
||
case "${{ matrix.arch }}" in
|
||
386)
|
||
export GOARCH=386
|
||
;;
|
||
arm)
|
||
export GOARCH=arm
|
||
export GOARM=7
|
||
;;
|
||
*)
|
||
export GOARCH=${{ matrix.arch }}
|
||
;;
|
||
esac
|
||
|
||
export GOOS=${{ matrix.os }}
|
||
|
||
# Build with static linking for Linux
|
||
if [[ "${{ matrix.os }}" == "linux" ]]; then
|
||
export CGO_ENABLED=0
|
||
LDFLAGS="-extldflags=-static"
|
||
else
|
||
LDFLAGS=""
|
||
fi
|
||
|
||
# Build the binary
|
||
go build -ldflags "$LDFLAGS -X main.Version=$VERSION" -o aptly${{ matrix.os == 'windows' && '.exe' || '' }}
|
||
|
||
- name: Build man pages
|
||
if: matrix.os == 'linux' && matrix.arch == 'amd64'
|
||
run: |
|
||
make man
|
||
|
||
- name: Build completion files
|
||
if: matrix.os == 'linux' && matrix.arch == 'amd64'
|
||
run: |
|
||
make completion
|
||
|
||
- name: Create archive
|
||
run: |
|
||
ARCHIVE_NAME="aptly_${VERSION}_${{ matrix.os }}_${{ matrix.arch }}.zip"
|
||
|
||
# Include binary
|
||
FILES="aptly${{ matrix.os == 'windows' && '.exe' || '' }}"
|
||
|
||
# Include man pages and completions for main Linux build
|
||
if [[ "${{ matrix.os }}" == "linux" && "${{ matrix.arch }}" == "amd64" ]]; then
|
||
FILES="$FILES man completion"
|
||
fi
|
||
|
||
zip -r $ARCHIVE_NAME $FILES
|
||
echo "ARCHIVE_NAME=$ARCHIVE_NAME" >> $GITHUB_ENV
|
||
|
||
- name: Upload artifact
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: binary-${{ matrix.os }}-${{ matrix.arch }}
|
||
path: ${{ env.ARCHIVE_NAME }}
|
||
retention-days: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && 90 || 7 }}
|
||
|
||
# Dependency check
|
||
dependencies:
|
||
name: Check Dependencies
|
||
runs-on: ubuntu-latest
|
||
if: github.event_name == 'schedule'
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Read Go Version
|
||
run: |
|
||
gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod)
|
||
echo "Go Version: $gover"
|
||
echo "GOVER=$gover" >> $GITHUB_OUTPUT
|
||
id: goversion
|
||
|
||
- name: Set up Go
|
||
uses: actions/setup-go@v5
|
||
with:
|
||
go-version: ${{ steps.goversion.outputs.GOVER }}
|
||
cache: true
|
||
|
||
- name: Check for updates
|
||
run: |
|
||
echo "## Outdated Dependencies" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
go list -u -m all | grep '\[' >> $GITHUB_STEP_SUMMARY || echo "All dependencies are up to date!" >> $GITHUB_STEP_SUMMARY |