feat: add Docker image building and publishing to GitHub Container Registry #147
Workflow file for this run
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 | |
| on: | |
| push: | |
| branches: [master, develop] | |
| pull_request: | |
| branches: [master, develop] | |
| # Allow manual workflow runs | |
| workflow_dispatch: | |
| env: | |
| CARGO_TERM_COLOR: always | |
| # Disable incremental compilation for CI builds (faster clean builds) | |
| CARGO_INCREMENTAL: 0 | |
| # Enable full backtraces for tests | |
| RUST_BACKTRACE: full | |
| jobs: | |
| check: | |
| name: Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Nix | |
| uses: DeterminateSystems/nix-installer-action@v9 | |
| - name: Check Rust formatting | |
| run: nix develop -c cargo fmt --all -- --check | |
| - name: Check code with cargo check | |
| run: nix develop -c just check | |
| - name: Run clippy lints | |
| run: nix develop -c just clippy | |
| - name: Check for typos | |
| run: nix develop -c just typos | |
| # Continue on failure for typos (informational) | |
| continue-on-error: true | |
| test: | |
| name: Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Nix | |
| uses: DeterminateSystems/nix-installer-action@v9 | |
| - name: Build project | |
| run: nix develop -c just build | |
| - name: Run unit tests | |
| run: nix develop -c cargo test --lib | |
| - name: Run integration tests | |
| run: nix develop -c cargo test --test '*' | |
| - name: Run doc tests | |
| run: nix develop -c cargo test --doc | |
| # Integration tests moved to separate workflow: .github/workflows/integration-tests.yml | |
| # They run on push, PR, schedule, and manual trigger | |
| build: | |
| name: Build | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| target: | |
| - x86_64-unknown-linux-gnu | |
| - x86_64-unknown-linux-musl | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Nix | |
| uses: DeterminateSystems/nix-installer-action@v9 | |
| - name: Build for ${{ matrix.target }} | |
| run: | | |
| if [ "${{ matrix.target }}" = "x86_64-unknown-linux-musl" ]; then | |
| nix develop -c cargo build --release --target ${{ matrix.target }} | |
| else | |
| nix develop -c cargo build --release --target ${{ matrix.target }} | |
| fi | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: nostrweet-${{ matrix.target }} | |
| path: target/${{ matrix.target }}/release/nostrweet | |
| retention-days: 7 | |
| # Cross-platform testing for macOS and Windows | |
| test-cross-platform: | |
| name: Test on ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| needs: check | |
| strategy: | |
| matrix: | |
| os: [macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| # macOS: Use Nix for consistent environment | |
| - name: Install Nix (macOS only) | |
| if: matrix.os == 'macos-latest' | |
| uses: DeterminateSystems/nix-installer-action@v9 | |
| # Windows: Use native Rust toolchain | |
| - name: Install Rust (Windows only) | |
| if: matrix.os == 'windows-latest' | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| # Build using appropriate toolchain | |
| - name: Build (macOS) | |
| if: matrix.os == 'macos-latest' | |
| run: nix develop -c cargo build --release | |
| - name: Build (Windows) | |
| if: matrix.os == 'windows-latest' | |
| run: cargo build --release | |
| # Run tests using appropriate toolchain | |
| - name: Run tests (macOS) | |
| if: matrix.os == 'macos-latest' | |
| run: nix develop -c cargo test | |
| - name: Run tests (Windows) | |
| if: matrix.os == 'windows-latest' | |
| run: cargo test | |
| # Test CLI binary | |
| - name: Test CLI (Unix) | |
| if: matrix.os != 'windows-latest' | |
| run: ./target/release/nostrweet --help | |
| - name: Test CLI (Windows) | |
| if: matrix.os == 'windows-latest' | |
| run: .\target\release\nostrweet.exe --help | |
| final-check: | |
| name: Final Check | |
| runs-on: ubuntu-latest | |
| # Only run after all other jobs pass | |
| needs: [check, test, build, test-cross-platform] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Nix | |
| uses: DeterminateSystems/nix-installer-action@v9 | |
| - name: Run final checks (lint + clippy + tests) | |
| run: nix develop -c just final-check | |
| # Security audit job | |
| audit: | |
| name: Security Audit | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Nix | |
| uses: DeterminateSystems/nix-installer-action@v9 | |
| - name: Install cargo-audit | |
| run: nix develop -c cargo install cargo-audit | |
| - name: Run security audit | |
| run: nix develop -c cargo audit | |
| # Continue on failure for security audit (informational) | |
| continue-on-error: true | |
| # Docker build and push job | |
| docker: | |
| name: Build and Push Docker Image | |
| runs-on: ubuntu-latest | |
| if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') | |
| needs: [check, test] | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Nix | |
| uses: DeterminateSystems/nix-installer-action@v9 | |
| - name: Setup Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build Docker image with Nix | |
| run: | | |
| nix build .#dockerImage | |
| docker load < result | |
| - name: Get image info | |
| id: image-info | |
| run: | | |
| echo "IMAGE_ID=$(docker images --format '{{.ID}}' | head -1)" >> $GITHUB_OUTPUT | |
| echo "REPO_LOWER=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT | |
| - name: Generate tags | |
| id: tags | |
| run: | | |
| TAGS="" | |
| REPO_LOWER=${{ steps.image-info.outputs.REPO_LOWER }} | |
| # Always tag with commit SHA | |
| TAGS="ghcr.io/${REPO_LOWER}:sha-${GITHUB_SHA::7}" | |
| # Tag with branch name if not a tag | |
| if [[ "${{ github.ref }}" == "refs/heads/"* ]]; then | |
| BRANCH_NAME=${GITHUB_REF##*/} | |
| TAGS="${TAGS},ghcr.io/${REPO_LOWER}:${BRANCH_NAME}" | |
| if [[ "${BRANCH_NAME}" == "master" ]] || [[ "${BRANCH_NAME}" == "main" ]]; then | |
| TAGS="${TAGS},ghcr.io/${REPO_LOWER}:latest" | |
| fi | |
| fi | |
| # Tag with version if it's a tag | |
| if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then | |
| VERSION=${GITHUB_REF##*/} | |
| TAGS="${TAGS},ghcr.io/${REPO_LOWER}:${VERSION}" | |
| fi | |
| echo "TAGS=${TAGS}" >> $GITHUB_OUTPUT | |
| - name: Tag and push Docker image | |
| run: | | |
| IMAGE_ID=${{ steps.image-info.outputs.IMAGE_ID }} | |
| IFS=',' read -ra TAG_ARRAY <<< "${{ steps.tags.outputs.TAGS }}" | |
| for TAG in "${TAG_ARRAY[@]}"; do | |
| docker tag ${IMAGE_ID} ${TAG} | |
| docker push ${TAG} | |
| done | |
| # Release build job (only on tags) | |
| release: | |
| name: Release Build | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: [check, test, build, docker] | |
| strategy: | |
| matrix: | |
| target: | |
| - x86_64-unknown-linux-gnu | |
| - x86_64-unknown-linux-musl | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Nix | |
| uses: DeterminateSystems/nix-installer-action@v9 | |
| - name: Build release binary | |
| run: nix develop -c cargo build --release --target ${{ matrix.target }} | |
| - name: Strip binary (for musl targets) | |
| if: matrix.target == 'x86_64-unknown-linux-musl' | |
| run: nix develop -c strip target/${{ matrix.target }}/release/nostrweet | |
| - name: Create release archive | |
| run: | | |
| cd target/${{ matrix.target }}/release | |
| tar -czf nostrweet-${{ github.ref_name }}-${{ matrix.target }}.tar.gz nostrweet | |
| mv nostrweet-${{ github.ref_name }}-${{ matrix.target }}.tar.gz ../../../ | |
| - name: Upload release artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: nostrweet-${{ github.ref_name }}-${{ matrix.target }} | |
| path: nostrweet-${{ github.ref_name }}-${{ matrix.target }}.tar.gz | |
| retention-days: 30 | |
| - name: Create GitHub Release | |
| if: matrix.target == 'x86_64-unknown-linux-musl' # Only create release once | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| files: | | |
| nostrweet-${{ github.ref_name }}-x86_64-unknown-linux-gnu.tar.gz | |
| nostrweet-${{ github.ref_name }}-x86_64-unknown-linux-musl.tar.gz | |
| generate_release_notes: true | |
| draft: false | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |