blob: c9fd86dc3285dd1df45af9085906e9093c64aafb [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: Release Ruby Binding
on:
push:
tags:
# Triggers on version tags (v0.54.0, v0.54.0-rc.1, etc.)
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+"
pull_request:
branches:
- main
paths:
- ".github/workflows/release_ruby.yml"
workflow_dispatch: # allow repo collaborators to publish gem
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
permissions:
contents: read
id-token: write # required for workflow to publish gem if releasing
defaults:
run:
working-directory: bindings/ruby
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.summary.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
working-directory: bindings/ruby
- name: Build source gem (Ruby-only)
run: bundle exec rake build
- name: Show built gems
run: ls -la pkg/
- name: Upload artifact (source gem)
uses: actions/upload-artifact@v4
with:
name: opendal-ruby-gem-source
path: bindings/ruby/pkg/*.gem
retention-days: 30
- name: Log Build Summary
id: summary
run: |
# e.g. from `Cargo.toml` to released version:
# - 0.54.0 -> 0.54.0
# - 0.54.0-rc.1 -> 0.54.1.pre.rc.1
VERSION=$(bundle exec rake version)
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "## Ruby gem built successfully! 📦" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Ref:** ${{ github.ref_name || github.ref }}" >> "$GITHUB_STEP_SUMMARY"
echo "**Version:** $VERSION" >> "$GITHUB_STEP_SUMMARY"
# We maintain multiple build targets for native gems.
# We only provide best-effort support for native gems. We could withdraw the support to these builds at any time.
build-native:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
platform: x86_64-linux
rust_target: x86_64-unknown-linux-gnu
- os: ubuntu-24.04-arm
platform: aarch64-linux
rust_target: aarch64-unknown-linux-gnu
- os: macos-latest
platform: arm64-darwin23
rust_target: aarch64-apple-darwin
runs-on: ${{ matrix.os }}
continue-on-error: true
env:
RB_SYS_CARGO_TARGET: ${{ matrix.rust_target }}
steps:
- name: Checkout repository
uses: actions/checkout@v5
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.rust_target }}
- name: Setup Ruby and install dependencies
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
working-directory: bindings/ruby # must repeat because GitHub Actions will not use defaults.run
- name: Show available rake tasks
run: bundle exec rake --tasks
- name: Build native gem
run: bundle exec rake native:opendal:${{ matrix.platform }} gem
- name: Collect built gem
run: |
echo "Built gem file:"
ls -la pkg/
echo ""
mkdir -p pkg_out
cp -r pkg/*.gem pkg_out/
- name: Upload gem artifact
uses: actions/upload-artifact@v4
with:
name: opendal-ruby-gem-${{ matrix.platform }}
path: bindings/ruby/pkg_out/*.gem
retention-days: 30
publish:
# allow:
# - standard tag releases
# - workflow_dispatch:
# - reattempt standard tag releases
# - pre-releases
# if: >-
# startsWith(github.ref, 'refs/tags/v') ||
# (github.event_name == 'workflow_dispatch' && contains(needs.build.outputs.version, 'rc'))
# Don't start publish until we are ready
if: false
needs: [build, build-native]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Setup Ruby and install dependencies
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
working-directory: bindings/ruby
- name: Download gem artifacts
uses: actions/download-artifact@v5
with:
pattern: opendal-ruby-gem-*
path: bindings/ruby/pkg/
merge-multiple: true
- name: List downloaded artifacts
run: |
echo "Downloaded gems:"
ls -lh pkg/*.gem
# Adapted from rubygems/release-gem@v1. Changed:
# 1. publishing git tag
# 2. support custom working directory
#
# TODO: we can consider using rubygems/release-gem when the gem resolves:
# https://github.com/rubygems/release-gem/pull/12
- name: Attribute commits to last committer
run: |
git config --global user.email "$(git log -1 --pretty=format:'%ae')"
git config --global user.name "$(git log -1 --pretty=format:'%an')"
- name: Configure Git using cached credentials
run: |
git credential-cache --timeout=300 store <<EOF
protocol=https
host=github.com
username=x-access-token
password=${{ github.token }}
EOF
git config --local credential.helper 'cache --timeout=300'
# Patch file copied from
# https://github.com/rubygems/release-gem/blob/a25424ba2ba8b387abc8ef40807c2c85b96cbe32/rubygems-attestation-patch.rb
- name: Amend patch file
run: |
cat <<EOF >> rubygems-attestation-patch.rb
# frozen_string_literal: true
return if RUBY_ENGINE == "jruby"
return unless defined?(Gem)
require "rubygems/commands/push_command"
Gem::Commands::PushCommand.prepend(Module.new do
def send_push_request(name, args)
return super if options[:attestations]&.any? || @host != "https://rubygems.org"
begin
send_push_request_with_attestation(name, args)
rescue StandardError => e
alert_warning "Failed to push with attestation, retrying without attestation.\n#{e.full_message}"
super
end
end
def send_push_request_with_attestation(name, args)
attestation = attest!(name)
if options[:attestations]
options[:attestations] << attestation
send_push_request(name, args)
else
rubygems_api_request(*args, scope: get_push_scope) do |request|
request.set_form([
["gem", Gem.read_binary(name), { filename: name, content_type: "application/octet-stream" }],
["attestations", "[#{Gem.read_binary(attestation)}]", { content_type: "application/json" }]
], "multipart/form-data")
request.add_field "Authorization", api_key
end
end
end
def attest!(name)
require "open3"
bundle = "#{name}.sigstore.json"
env = defined?(Bundler.unbundled_env) ? Bundler.unbundled_env : ENV.to_h
out, st = Open3.capture2e(
env,
Gem.ruby, "-S", "gem", "exec",
"sigstore-cli:0.2.1", "sign", name, "--bundle", bundle,
unsetenv_others: true
)
raise Gem::Exception, "Failed to sign gem:\n\n#{out}" unless st.success?
bundle
end
end)
EOF
- name: Configure trusted publishing credentials
uses: rubygems/configure-rubygems-credentials@v1.0.0
- name: Release gem
run: bundle exec rake release
env:
RUBYOPT: "${{ format('-r{0}/bindings/ruby/rubygems-attestation-patch.rb {1}', github.workspace, env.RUBYOPT) || env.RUBYOPT }}"
- name: Wait for release to propagate
run: gem exec rubygems-await pkg/*.gem
- name: Log Release
run: |
echo "## Ruby binding released! 🚀" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Version:** $(bundle exec rake version)" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "Check out the [RubyGems page](https://rubygems.org/gems/opendal) for more details." >> "$GITHUB_STEP_SUMMARY"
- name: Clean up credentials
if: always()
run: git credential-cache exit || true