fix: make ban duration log message dynamic based on configuration #22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI/CD Pipeline | |
| on: | |
| push: | |
| branches: [ main ] | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - '.gitignore' | |
| - 'LICENSE' | |
| pull_request: | |
| branches: [ main ] | |
| permissions: | |
| contents: write | |
| packages: write | |
| pull-requests: read | |
| jobs: | |
| # ============================================================================ | |
| # STAGE 1: TEST | |
| # ============================================================================ | |
| test-unit: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| go-version: ['1.20', '1.21'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Go ${{ matrix.go-version }} | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ matrix.go-version }} | |
| cache: true | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libpcap-dev | |
| - name: Run unit tests | |
| run: go test ./... -v -race -coverprofile=coverage.out -covermode=atomic | |
| - name: Upload coverage | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| file: ./coverage.out | |
| flags: unittests | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| test-integration: | |
| name: Integration Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: '1.20' | |
| cache: true | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libpcap-dev | |
| - name: Run integration tests | |
| run: go test -tags=integration ./test/integration -v | |
| test-e2e: | |
| name: E2E Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: '1.20' | |
| cache: true | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libpcap-dev | |
| - name: Build binary | |
| run: make build | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Run E2E tests | |
| working-directory: test/e2e | |
| run: | | |
| docker compose build | |
| docker compose up -d | |
| sleep 10 | |
| chmod +x run-simple-e2e.sh | |
| bash run-simple-e2e.sh | |
| - name: Show logs on failure | |
| if: failure() | |
| working-directory: test/e2e | |
| run: | | |
| docker logs btblocker-e2e-server || true | |
| docker logs btblocker-e2e-client || true | |
| - name: Cleanup | |
| if: always() | |
| working-directory: test/e2e | |
| run: docker compose down -v | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: '1.20' | |
| cache: true | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libpcap-dev | |
| - name: golangci-lint | |
| uses: golangci/golangci-lint-action@v4 | |
| with: | |
| version: latest | |
| args: --timeout=5m | |
| # ============================================================================ | |
| # STAGE 2: VERSION PREPARATION (determine version and update files) | |
| # ============================================================================ | |
| prepare-version: | |
| name: Prepare Version | |
| runs-on: ubuntu-latest | |
| needs: [test-unit, test-integration, test-e2e, lint] | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| tag: ${{ steps.version.outputs.tag }} | |
| should_release: ${{ steps.check.outputs.should_release }} | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Check if skip release | |
| id: check | |
| run: | | |
| COMMIT_MSG=$(git log -1 --pretty=%B) | |
| if echo "$COMMIT_MSG" | grep -qE "(chore: bump version|Bump version to)"; then | |
| echo "should_release=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| - name: Determine version bump | |
| id: bump | |
| if: steps.check.outputs.should_release == 'true' | |
| run: | | |
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") | |
| COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=format:"%s") | |
| BUMP="patch" | |
| if echo "$COMMITS" | grep -qiE "^(feat|feature)(\(.+\))?!:|^BREAKING CHANGE:"; then | |
| BUMP="major" | |
| elif echo "$COMMITS" | grep -qiE "^(feat|feature)(\(.+\))?:"; then | |
| BUMP="minor" | |
| elif echo "$COMMITS" | grep -qiE "^(fix|perf|refactor|optimize)(\(.+\))?:"; then | |
| BUMP="patch" | |
| fi | |
| echo "bump_type=$BUMP" >> $GITHUB_OUTPUT | |
| echo "last_tag=$LAST_TAG" >> $GITHUB_OUTPUT | |
| - name: Calculate new version | |
| id: version | |
| if: steps.check.outputs.should_release == 'true' | |
| run: | | |
| LAST_TAG=${{ steps.bump.outputs.last_tag }} | |
| LAST_VERSION=${LAST_TAG#v} | |
| IFS='.' read -ra PARTS <<< "$LAST_VERSION" | |
| MAJOR="${PARTS[0]:-0}" | |
| MINOR="${PARTS[1]:-0}" | |
| PATCH="${PARTS[2]:-0}" | |
| case "${{ steps.bump.outputs.bump_type }}" in | |
| major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;; | |
| minor) MINOR=$((MINOR + 1)); PATCH=0 ;; | |
| patch) PATCH=$((PATCH + 1)) ;; | |
| esac | |
| NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" | |
| echo "version=${NEW_VERSION}" >> $GITHUB_OUTPUT | |
| echo "tag=v${NEW_VERSION}" >> $GITHUB_OUTPUT | |
| # ============================================================================ | |
| # STAGE 3: BUILD (with updated version) | |
| # ============================================================================ | |
| build-binaries: | |
| name: Build ${{ matrix.goos }}-${{ matrix.goarch }} | |
| runs-on: ubuntu-latest | |
| needs: [prepare-version] | |
| if: needs.prepare-version.outputs.should_release == 'true' | |
| strategy: | |
| matrix: | |
| goos: [linux] | |
| goarch: [amd64] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: '1.20' | |
| - name: Install Linux dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libpcap-dev | |
| - name: Build binary | |
| env: | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| CGO_ENABLED: 1 | |
| VERSION: ${{ needs.prepare-version.outputs.version }} | |
| COMMIT: ${{ github.sha }} | |
| run: | | |
| BINARY_NAME="btblocker-${{ matrix.goos }}-${{ matrix.goarch }}" | |
| go build -v \ | |
| -ldflags="-s -w -X main.Version=${VERSION} -X main.Commit=${COMMIT}" \ | |
| -o "bin/${BINARY_NAME}" \ | |
| ./cmd/btblocker | |
| shell: bash | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: binary-${{ matrix.goos }}-${{ matrix.goarch }} | |
| path: bin/* | |
| retention-days: 1 | |
| build-nix: | |
| name: Build Nix Package | |
| runs-on: ubuntu-latest | |
| needs: [prepare-version] | |
| if: needs.prepare-version.outputs.should_release == 'true' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Inject version into flake.nix | |
| run: | | |
| VERSION="${{ needs.prepare-version.outputs.version }}" | |
| sed -i "s/version = \"[^\"]*\";/version = \"${VERSION}\";/" flake.nix | |
| echo "Updated flake.nix to version ${VERSION}" | |
| grep "version =" flake.nix | |
| - name: Install Nix | |
| uses: cachix/install-nix-action@v25 | |
| with: | |
| extra_nix_config: | | |
| experimental-features = nix-command flakes | |
| accept-flake-config = true | |
| - name: Setup Cachix | |
| uses: cachix/cachix-action@v14 | |
| with: | |
| name: btblocker | |
| authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' | |
| - name: Build Nix package | |
| run: nix build .#btblocker --print-build-logs | |
| - name: Push to Cachix | |
| run: | | |
| nix path-info .#btblocker --closure-size --json | jq -r '.[].path' | cachix push btblocker | |
| # ============================================================================ | |
| # STAGE 4: CREATE RELEASE (after builds) | |
| # ============================================================================ | |
| create-release: | |
| name: Create Release | |
| runs-on: ubuntu-latest | |
| needs: [prepare-version, build-binaries, build-nix] | |
| if: needs.prepare-version.outputs.should_release == 'true' | |
| outputs: | |
| version: ${{ needs.prepare-version.outputs.version }} | |
| tag: ${{ needs.prepare-version.outputs.tag }} | |
| created: ${{ steps.create_release.outputs.created }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create GitHub Release | |
| id: create_release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG="${{ needs.prepare-version.outputs.tag }}" | |
| # Create tag | |
| git tag "$TAG" | |
| git push origin "$TAG" | |
| # Create release | |
| gh release create "$TAG" \ | |
| --title "Release $TAG" \ | |
| --notes "Automated release $TAG" | |
| echo "created=true" >> $GITHUB_OUTPUT | |
| # ============================================================================ | |
| # STAGE 5: PUBLISH (upload artifacts to release, push Docker) | |
| # ============================================================================ | |
| publish-artifacts: | |
| name: Publish Artifacts | |
| runs-on: ubuntu-latest | |
| needs: [prepare-version, create-release] | |
| if: needs.prepare-version.outputs.should_release == 'true' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Create archives and checksums | |
| run: | | |
| cd artifacts | |
| for dir in binary-*; do | |
| platform=$(echo $dir | sed 's/binary-//') | |
| cd "$dir" | |
| # Create archive | |
| if [[ "$platform" == *"windows"* ]]; then | |
| zip "btblocker-${{ needs.create-release.outputs.version }}-${platform}.zip" * | |
| sha256sum *.zip > *.zip.sha256 | |
| else | |
| tar czf "btblocker-${{ needs.create-release.outputs.version }}-${platform}.tar.gz" * | |
| sha256sum *.tar.gz > *.tar.gz.sha256 | |
| fi | |
| cd .. | |
| done | |
| - name: Upload to release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| cd artifacts | |
| find . -name "*.tar.gz" -o -name "*.zip" -o -name "*.sha256" | while read file; do | |
| gh release upload ${{ needs.create-release.outputs.tag }} "$file" --clobber | |
| done | |
| publish-docker: | |
| name: Publish Docker Image | |
| runs-on: ubuntu-latest | |
| needs: [prepare-version, create-release] | |
| if: needs.prepare-version.outputs.should_release == 'true' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push Docker image | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: | | |
| ghcr.io/${{ github.repository_owner }}/btblocker:latest | |
| ghcr.io/${{ github.repository_owner }}/btblocker:${{ needs.create-release.outputs.version }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # ============================================================================ | |
| # PR CHECKS (on pull requests, only run tests - no build/release) | |
| # ============================================================================ | |
| pr-summary: | |
| name: PR Summary | |
| runs-on: ubuntu-latest | |
| needs: [test-unit, test-integration, test-e2e, lint] | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Check results | |
| run: | | |
| echo "✅ All PR checks passed!" | |
| echo "Unit Tests: ${{ needs.test-unit.result }}" | |
| echo "Integration Tests: ${{ needs.test-integration.result }}" | |
| echo "E2E Tests: ${{ needs.test-e2e.result }}" | |
| echo "Lint: ${{ needs.lint.result }}" |