Ruby - Continuous Deployment #17
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: Ruby - Continuous Deployment | |
| on: | |
| push: | |
| tags: | |
| - "v*.*" | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "The release version of GLIDE, formatted as *.*.* or *.*.*-rc*" | |
| required: true | |
| publish_gem: | |
| description: "Publish to RubyGems" | |
| required: true | |
| type: boolean | |
| default: false | |
| concurrency: | |
| group: ruby-cd-${{ github.head_ref || github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| id-token: write | |
| contents: read | |
| jobs: | |
| load-platform-matrix: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| PLATFORM_MATRIX: ${{ steps.load-platform-matrix.outputs.PLATFORM_MATRIX }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Load platform matrix | |
| id: load-platform-matrix | |
| shell: bash | |
| run: | | |
| export PLATFORM_MATRIX=$(jq -c '.' < .github/json_matrices/build-matrix.json) | |
| echo "PLATFORM_MATRIX=${PLATFORM_MATRIX}" >> $GITHUB_OUTPUT | |
| echo "Loaded platform matrix: ${PLATFORM_MATRIX}" | |
| set-release-version: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| RELEASE_VERSION: ${{ steps.release-version.outputs.RELEASE_VERSION }} | |
| steps: | |
| - name: Set the release version | |
| id: release-version | |
| shell: bash | |
| run: | | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| R_VERSION="${{ github.event.inputs.version }}" | |
| else | |
| # Remove 'v' prefix from tag | |
| R_VERSION="${GITHUB_REF_NAME#v}" | |
| fi | |
| echo "Release version: $R_VERSION" | |
| echo "RELEASE_VERSION=$R_VERSION" >> $GITHUB_OUTPUT | |
| - name: Validate version format | |
| run: | | |
| VERSION="${{ steps.release-version.outputs.RELEASE_VERSION }}" | |
| if ! echo "$VERSION" | grep -Pq '^\d+\.\d+\.\d+(-rc\d+)?$'; then | |
| echo "Invalid version format: $VERSION" | |
| echo "Expected format: X.Y.Z or X.Y.Z-rcN" | |
| exit 1 | |
| fi | |
| build-native-libraries: | |
| needs: [set-release-version, load-platform-matrix] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host: ${{ fromJson(needs.load-platform-matrix.outputs.PLATFORM_MATRIX) }} | |
| runs-on: ${{ matrix.host.RUNNER }} | |
| env: | |
| RELEASE_VERSION: ${{ needs.set-release-version.outputs.RELEASE_VERSION }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install protoc (protobuf) | |
| uses: arduino/setup-protoc@v3 | |
| with: | |
| version: "29.1" | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build native library | |
| working-directory: valkey-glide/ffi | |
| run: | | |
| cargo build --release | |
| - name: Upload native library artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: native-lib-${{ matrix.host.TARGET }} | |
| path: valkey-glide/ffi/target/release/libglide_ffi.so | |
| if-no-files-found: error | |
| build-and-publish-gem: | |
| needs: [set-release-version, load-platform-matrix, build-native-libraries] | |
| runs-on: ubuntu-latest | |
| env: | |
| RELEASE_VERSION: ${{ needs.set-release-version.outputs.RELEASE_VERSION }} | |
| PLATFORM_MATRIX: ${{ needs.load-platform-matrix.outputs.PLATFORM_MATRIX }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Set up Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: "3.3" | |
| bundler-cache: true | |
| - name: Download all native library artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: native-lib-* | |
| path: native-libs | |
| - name: Organize native libraries for gem | |
| run: | | |
| echo "Creating native library directories from matrix..." | |
| for target in $(echo '${{ env.PLATFORM_MATRIX }}' | jq -r '.[].TARGET'); do | |
| echo "Creating directory for $target" | |
| mkdir -p "lib/valkey/native/$target" | |
| echo "Copying native library for $target" | |
| cp "native-libs/native-lib-$target/libglide_ffi.so" "lib/valkey/native/$target/" | |
| done | |
| echo "Native libraries organized:" | |
| find lib/valkey/native -type f -exec ls -lh {} \; | |
| - name: Update gem version | |
| run: | | |
| sed -i "s/VERSION = .*/VERSION = \"${{ env.RELEASE_VERSION }}\"/" lib/valkey/version.rb | |
| echo "Updated version.rb:" | |
| cat lib/valkey/version.rb | |
| - name: Build gem | |
| id: build-gem | |
| run: | | |
| gem build valkey.gemspec | |
| echo "Built gem:" | |
| ls -lh *.gem | |
| # Capture the actual gem filename (RubyGems may transform version format) | |
| GEM_FILE=$(ls *.gem | head -1) | |
| echo "GEM_FILE=${GEM_FILE}" >> $GITHUB_OUTPUT | |
| echo "Gem file: ${GEM_FILE}" | |
| - name: Verify gem contents | |
| run: | | |
| gem unpack ${{ steps.build-gem.outputs.GEM_FILE }} --target=gem-contents | |
| echo "Gem contents:" | |
| find gem-contents -type f | head -50 | |
| echo "" | |
| echo "Native libraries in gem:" | |
| find gem-contents -name "libglide_ffi.*" -exec ls -lh {} \; | |
| - name: Upload gem artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ruby-gem | |
| path: "*.gem" | |
| if-no-files-found: error | |
| - name: Publish to RubyGems | |
| id: publish | |
| if: ${{ github.event_name == 'push' || inputs.publish_gem == true }} | |
| env: | |
| GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }} | |
| run: | | |
| gem push ${{ steps.build-gem.outputs.GEM_FILE }} | |
| echo "published=true" >> $GITHUB_OUTPUT | |
| outputs: | |
| published: ${{ steps.publish.outputs.published || 'false' }} | |
| test-gem: | |
| needs: [set-release-version, load-platform-matrix, build-and-publish-gem] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host: ${{ fromJson(needs.load-platform-matrix.outputs.PLATFORM_MATRIX) }} | |
| runs-on: ${{ matrix.host.RUNNER }} | |
| env: | |
| RELEASE_VERSION: ${{ needs.set-release-version.outputs.RELEASE_VERSION }} | |
| steps: | |
| - name: Checkout (for test files) | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Set up Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: "3.3" | |
| bundler-cache: false # We'll install gems manually | |
| - name: Install test dependencies | |
| run: | | |
| # Install test dependencies as system gems (not via bundler) | |
| # This avoids bundler's gemspec loading which would pull in local lib | |
| # Use specific versions to match Gemfile.lock for consistency | |
| gem install minitest -v 5.27.0 | |
| gem install minitest-reporters -v 1.8.0 | |
| gem install ansi | |
| gem install ruby-progressbar | |
| gem install rake | |
| - name: Start Valkey | |
| run: | | |
| docker run -d --name valkey-test -p 6379:6379 valkey/valkey:8 | |
| sleep 5 | |
| docker exec valkey-test valkey-cli ping | |
| - name: Download gem artifact (unpublished) | |
| if: ${{ needs.build-and-publish-gem.outputs.published != 'true' }} | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ruby-gem | |
| path: . | |
| - name: Install gem from artifact (unpublished) | |
| if: ${{ needs.build-and-publish-gem.outputs.published != 'true' }} | |
| run: | | |
| GEM_FILE=$(ls *.gem | head -1) | |
| echo "Installing gem from artifact: ${GEM_FILE}" | |
| gem install "${GEM_FILE}" | |
| echo "Installed gem:" | |
| gem list valkey | |
| - name: Install gem from RubyGems (published) | |
| if: ${{ needs.build-and-publish-gem.outputs.published == 'true' }} | |
| run: | | |
| echo "Installing published gem from RubyGems..." | |
| # Wait a bit for RubyGems to index the new version | |
| sleep 30 | |
| gem install valkey-rb --version "${{ env.RELEASE_VERSION }}" || gem install valkey-rb --pre | |
| echo "Installed gem:" | |
| gem list valkey | |
| - name: Test gem loading | |
| run: | | |
| ruby -e " | |
| require 'valkey' | |
| puts 'Valkey gem loaded successfully!' | |
| puts 'Platform info:' | |
| info = Valkey::Bindings.platform_info | |
| puts \" OS: #{info[:os]}\" | |
| puts \" Arch: #{info[:arch]}\" | |
| puts \" Platform dir: #{info[:platform_dir]}\" | |
| " | |
| - name: Run standalone tests | |
| env: | |
| TEST_INSTALLED_GEM: "true" | |
| run: | | |
| # Remove local lib to ensure we use the installed gem | |
| # The installed gem has the native library, local lib doesn't | |
| rm -rf lib/ | |
| # Run tests - they will use the installed gem | |
| rake test:valkey | |
| - name: Stop Valkey | |
| if: always() | |
| run: docker stop valkey-test && docker rm valkey-test || true |