Skip to content

feat: add Docker image building and publishing to GitHub Container Registry #147

feat: add Docker image building and publishing to GitHub Container Registry

feat: add Docker image building and publishing to GitHub Container Registry #147

Workflow file for this run

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 }}