Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,11 @@ jobs:
submodules: recursive

- name: Install Rust toolchain
if: ${{ !endsWith(matrix.host.TARGET, '-unknown-linux-gnu') }}
uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable

- name: Install protoc (protobuf)
if: ${{ !endsWith(matrix.host.TARGET, '-unknown-linux-gnu') }}
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0
with:
version: "29.1"
Expand Down Expand Up @@ -134,6 +136,7 @@ jobs:
EOF

- name: Build native library
if: ${{ !endsWith(matrix.host.TARGET, '-unknown-linux-gnu') }}
working-directory: valkey-glide/ffi
env:
GLIDE_NAME: GlideRuby
Expand All @@ -146,6 +149,48 @@ jobs:
cargo build --release
fi

# *-unknown-linux-gnu targets are built inside manylinux2014 (glibc
# 2.17) instead of directly on the ubuntu-24.04(-arm) runner (glibc
# 2.39), so the resulting .so loads on older glibc hosts (Amazon Linux
# 1/2, Debian 11, Ubuntu 20.04) as well as anything newer. Runs natively
# on each runner's own architecture — ubuntu-24.04-arm pulls/builds the
# aarch64 manylinux2014 image directly, no QEMU involved. See
# docker/manylinux2014/.
- name: Build native library (manylinux2014, glibc 2.17 floor)
if: ${{ endsWith(matrix.host.TARGET, '-unknown-linux-gnu') }}
env:
GLIDE_VERSION: ${{ env.RELEASE_VERSION }}
TARGET: ${{ matrix.host.TARGET }}
run: |
case "$TARGET" in
x86_64-unknown-linux-gnu)
BASE_IMAGE=quay.io/pypa/manylinux2014_x86_64
PROTOC_ARCH=x86_64
;;
aarch64-unknown-linux-gnu)
BASE_IMAGE=quay.io/pypa/manylinux2014_aarch64
PROTOC_ARCH=aarch_64
;;
*)
echo "No manylinux2014 image mapping for target: $TARGET"
exit 1
;;
esac

docker build \
--build-arg BASE_IMAGE="$BASE_IMAGE" \
--build-arg PROTOC_ARCH="$PROTOC_ARCH" \
-t valkey-glide-manylinux2014 \
-f docker/manylinux2014/Dockerfile .

docker run --rm \
-v "${{ github.workspace }}":/workspace \
-w /workspace/valkey-glide/ffi \
-e GLIDE_NAME=GlideRuby \
-e GLIDE_VERSION="${GLIDE_VERSION}" \
valkey-glide-manylinux2014 \
cargo build --release

- name: Upload native library artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
Expand Down Expand Up @@ -480,3 +525,120 @@ jobs:
run: |
python3 valkey-glide/utils/cluster_manager.py stop --prefix standalone || true
python3 valkey-glide/utils/cluster_manager.py stop --prefix cluster || true

test-gem-al1-smoke:
name: Smoke Test (Amazon Linux 1 / 2018.03)
needs: [set-release-version, build-and-publish-gem]
runs-on: ubuntu-24.04
timeout-minutes: 15
env:
RELEASE_VERSION: ${{ needs.set-release-version.outputs.RELEASE_VERSION }}

# AL1 is EOL and has no path to Ruby >= 2.6 (the gem's required_ruby_version
# floor), so this doesn't install the gem — it only proves libglide_ffi.so
# itself loads under AL1's glibc 2.17, which is what the manylinux2014
# build step exists to guarantee. A .gem file is a plain POSIX tar
# container, so it can be unpacked with `tar` alone, no Ruby needed.
#
# Deliberately no job-level `container:` here. GitHub's own actions (like
# download-artifact) are Node-based and GitHub injects its Node runtime
# into whatever container a job uses — that Node build needs a newer
# glibc than AL1's 2.17, so running the whole job inside amazonlinux:2018.03
# breaks those steps well before the .so is even involved. Instead we stay
# on the normal runner (modern glibc, modern tar, actions work normally)
# and only drop into amazonlinux:2018.03 via `docker run` for the one
# step that actually needs to execute under its old glibc.
steps:
- name: Download gem artifact (unpublished)
if: ${{ needs.build-and-publish-gem.outputs.published != 'true' }}
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: ruby-gem
path: .

- name: Download gem from RubyGems (published)
if: ${{ needs.build-and-publish-gem.outputs.published == 'true' }}
shell: bash
run: |
sleep 30
curl -sSL -o valkey-glide-rb.gem \
"https://rubygems.org/downloads/valkey-glide-rb-${RELEASE_VERSION}.gem"

- name: Extract native library from gem
shell: bash
run: |
GEM_FILE=$(ls *.gem | head -1)
echo "Gem file: ${GEM_FILE}"
mkdir -p gem-extract
tar -xf "${GEM_FILE}" -C gem-extract
tar -xzf gem-extract/data.tar.gz -C gem-extract lib/valkey/native/x86_64-unknown-linux-gnu/libglide_ffi.so

- name: Verify libglide_ffi.so loads under glibc 2.17 (amazonlinux:2018.03)
shell: bash
run: |
docker run --rm -v "${{ github.workspace }}":/workspace -w /workspace amazonlinux:2018.03 bash -c '
set -e
yum install -y binutils >/dev/null
SO=gem-extract/lib/valkey/native/x86_64-unknown-linux-gnu/libglide_ffi.so
echo "Container glibc:"
ldd --version | head -1
echo "GLIBC symbol versions referenced by the library:"
objdump -T "$SO" | grep -o "GLIBC_[0-9.]*" | sort -Vu
echo "Dynamic linker resolution (fails with a GLIBC version error if incompatible):"
ldd "$SO"
'

test-gem-al2-arm64-smoke:
name: Smoke Test (Amazon Linux 2, arm64)
needs: [set-release-version, build-and-publish-gem]
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
env:
RELEASE_VERSION: ${{ needs.set-release-version.outputs.RELEASE_VERSION }}

# Amazon Linux 1 was never published for arm64 (it predates Graviton),
# so amazonlinux:2 (glibc 2.26) is the oldest arm64 target we actually
# have to test against — same no-container-at-job-level pattern as
# test-gem-al1-smoke, for the same reason (GitHub's Node-based actions
# need a newer glibc than very old containers provide). ubuntu-24.04-arm
# is a native arm64 runner, so `docker run amazonlinux:2` here pulls the
# arm64 image directly, no QEMU involved.
steps:
- name: Download gem artifact (unpublished)
if: ${{ needs.build-and-publish-gem.outputs.published != 'true' }}
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: ruby-gem
path: .

- name: Download gem from RubyGems (published)
if: ${{ needs.build-and-publish-gem.outputs.published == 'true' }}
shell: bash
run: |
sleep 30
curl -sSL -o valkey-glide-rb.gem \
"https://rubygems.org/downloads/valkey-glide-rb-${RELEASE_VERSION}.gem"

- name: Extract native library from gem
shell: bash
run: |
GEM_FILE=$(ls *.gem | head -1)
echo "Gem file: ${GEM_FILE}"
mkdir -p gem-extract
tar -xf "${GEM_FILE}" -C gem-extract
tar -xzf gem-extract/data.tar.gz -C gem-extract lib/valkey/native/aarch64-unknown-linux-gnu/libglide_ffi.so

- name: Verify libglide_ffi.so loads under glibc 2.26 (amazonlinux:2, arm64)
shell: bash
run: |
docker run --rm -v "${{ github.workspace }}":/workspace -w /workspace amazonlinux:2 bash -c '
set -e
yum install -y binutils >/dev/null
SO=gem-extract/lib/valkey/native/aarch64-unknown-linux-gnu/libglide_ffi.so
echo "Container glibc:"
ldd --version | head -1
echo "GLIBC symbol versions referenced by the library:"
objdump -T "$SO" | grep -o "GLIBC_[0-9.]*" | sort -Vu
echo "Dynamic linker resolution (fails with a GLIBC version error if incompatible):"
ldd "$SO"
'
27 changes: 27 additions & 0 deletions docker/manylinux2014/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Builds libglide_ffi.so against glibc 2.17 (CentOS 7 baseline), so the
# resulting binary loads on anything with glibc >= 2.17 — covers
# amazonlinux:2018.03 (2.17), amazonlinux:2 (2.26), amazonlinux:2023 (2.34),
# for both x86_64 and aarch64.
#
# Build with:
# docker build --build-arg BASE_IMAGE=quay.io/pypa/manylinux2014_x86_64 \
# --build-arg PROTOC_ARCH=x86_64 ...
# docker build --build-arg BASE_IMAGE=quay.io/pypa/manylinux2014_aarch64 \
# --build-arg PROTOC_ARCH=aarch_64 ...
ARG BASE_IMAGE=quay.io/pypa/manylinux2014_x86_64
FROM ${BASE_IMAGE}

ARG PROTOC_VERSION=29.1
ARG PROTOC_ARCH=x86_64

RUN yum install -y unzip && yum clean all

RUN curl -sSL -o /tmp/protoc.zip \
"https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip" \
&& unzip -q /tmp/protoc.zip -d /usr/local \
&& rm /tmp/protoc.zip

ENV PATH="/root/.cargo/bin:${PATH}"
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable

WORKDIR /workspace
Loading