Skip to content

Update actions/cache action to v5 #249

Update actions/cache action to v5

Update actions/cache action to v5 #249

# Why We Build and Run Without Caching Native Extensions
#
# We intentionally compile the native librdkafka library fresh in each test job
# rather than caching or pre-building it for several reasons:
#
# 1. Architecture Compatibility
# - Pre-built native libraries (.so files) are architecture-specific
# - Can cause "Exec format error" when build/runtime environments differ
# - Building in the same container guarantees compatibility
#
# 2. Container Image Variations
# - Different Ruby Alpine images may have subtle differences in:
# * Base system libraries, compiler toolchains, musl libc versions
# - These differences can cause pre-built libraries to fail at runtime
#
# 3. Simplicity and Reliability
# - Single source of truth: everything builds and runs in same environment
# - No artifact management complexity or potential upload/download failures
# - Easier debugging when issues are contained in one job
#
# Trade-offs: Slightly longer CI times (~2-3 min per job) but much more reliable
# than dealing with architecture mismatches and artifact corruption issues.
name: CI Linux Alpine x86_64 musl
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
pull_request:
branches: [ master ]
schedule:
- cron: '0 1 * * *'
permissions:
contents: read
env:
BUNDLE_RETRY: 6
BUNDLE_JOBS: 4
jobs:
specs_install:
timeout-minutes: 45
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- ruby: '3.2'
alpine_version: '3.21'
- ruby: '3.2'
alpine_version: '3.22'
- ruby: '3.3'
alpine_version: '3.21'
- ruby: '3.3'
alpine_version: '3.22'
- ruby: '3.4'
alpine_version: '3.21'
coverage: 'true'
- ruby: '3.4'
alpine_version: '3.22'
coverage: 'true'
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
- name: Start Kafka with Docker Compose
run: |
docker compose -f docker-compose.yml up -d
echo "Waiting for Kafka to be ready..."
sleep 10
for i in {1..30}; do
if docker compose exec -T kafka kafka-topics --bootstrap-server localhost:9092 --list >/dev/null 2>&1; then
echo "Kafka topics command succeeded!"
break
fi
sleep 2
done
- name: Run all specs in PLAINTEXT
env:
GITHUB_COVERAGE: ${{ matrix.coverage }}
run: |
docker run --rm \
--network host \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
-e "GITHUB_COVERAGE=${{ matrix.coverage }}" \
ruby:${{ matrix.ruby }}-alpine${{ matrix.alpine_version }} \
sh -c 'apk add --no-cache git curl ca-certificates build-base linux-headers \
pkgconf perl autoconf automake libtool bison flex file \
ruby-dev ruby-bundler bash zstd-dev zlib zlib-dev openssl-dev \
cyrus-sasl-dev cyrus-sasl cyrus-sasl-login \
cyrus-sasl-crammd5 cyrus-sasl-digestmd5 cyrus-sasl-gssapiv2 cyrus-sasl-scram \
krb5-libs openssl zlib zstd-libs && \
git config --global --add safe.directory /workspace && \
bundle config set --local path vendor/bundle && \
bundle install && \
cd ext && bundle exec rake && \
cd .. && \
bundle exec ruby -S rspec'
- name: Verify Kafka warnings
run: bin/verify_kafka_warnings
build_precompiled:
timeout-minutes: 45
runs-on: ubuntu-latest
container:
# Similar to GNU, we build on the oldest for ABI compatibility
image: alpine:3.23@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 # renovate: ignore
steps:
- name: Install dependencies
run: |
apk add --no-cache git curl ca-certificates build-base linux-headers \
pkgconf perl autoconf automake libtool bison flex file bash wget zstd-dev \
openssl-dev cyrus-sasl-dev cyrus-sasl cyrus-sasl-login \
cyrus-sasl-crammd5 cyrus-sasl-digestmd5 cyrus-sasl-gssapiv2 cyrus-sasl-scram \
krb5-libs openssl zlib zlib-dev zstd-libs
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
- name: Configure git safe directory
run: git config --global --add safe.directory /__w/karafka-rdkafka/karafka-rdkafka
- name: Cache build-tmp directory
uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # v5.0.0
with:
path: ext/build-tmp-musl
key: build-tmp-musl-${{ runner.os }}-${{ hashFiles('ext/*.sh', 'ext/Rakefile') }}-v2
- name: Build precompiled librdkafka.so
run: |
cd ext
bash ./build_linux_x86_64_musl.sh
- name: Upload precompiled library
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: librdkafka-precompiled-musl
path: ext/
retention-days: 1
specs_precompiled:
timeout-minutes: 30
runs-on: ubuntu-latest
needs: build_precompiled
strategy:
fail-fast: false
matrix:
ruby:
- '3.4'
- '3.3'
- '3.2'
include:
- ruby: '3.4'
coverage: 'true'
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
- name: Download precompiled library
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: librdkafka-precompiled-musl
path: ext/
- name: Start Kafka with Docker Compose
run: |
docker compose -f docker-compose.yml up -d
echo "Waiting for Kafka to be ready..."
sleep 10
for i in {1..30}; do
if docker compose exec -T kafka kafka-topics --bootstrap-server localhost:9092 --list >/dev/null 2>&1; then
echo "Kafka topics command succeeded!"
break
fi
sleep 2
done
- name: Run specs with precompiled library and PLAINTEXT
env:
GITHUB_COVERAGE: ${{ matrix.coverage }}
RDKAFKA_EXT_PATH: ${{ github.workspace }}/ext
RDKAFKA_PRECOMPILED: "true"
run: |
docker run --rm \
--network host \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
-e "GITHUB_COVERAGE=${{ matrix.coverage }}" \
-e "RDKAFKA_EXT_PATH=/workspace/ext" \
-e "RDKAFKA_PRECOMPILED=true" \
ruby:${{ matrix.ruby }}-alpine \
sh -c 'apk add --no-cache git build-base linux-headers bash && \
git config --global --add safe.directory /workspace && \
bundle config set --local path vendor/bundle && \
bundle install && bundle exec ruby -S rspec'
- name: Verify Kafka warnings
run: bin/verify_kafka_warnings
ci-success:
name: CI Linux Alpine x86_64 musl Success
runs-on: ubuntu-latest
if: always()
needs:
- specs_install
- build_precompiled
- specs_precompiled
steps:
- name: Check all jobs passed
if: |
contains(needs.*.result, 'failure') ||
contains(needs.*.result, 'cancelled') ||
contains(needs.*.result, 'skipped')
run: exit 1
- run: echo "All CI checks passed!"