Skip to content

CD

CD #173

Workflow file for this run

---
name: CD
on:
workflow_run:
workflows: [CI]
types: [completed]
branches: [main]
workflow_dispatch:
inputs:
dry_run:
type: boolean
default: false
description: "Build gems but don't publish or release"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check-release:
name: Check if release needed
runs-on: ubuntu-latest
# Only proceed when the triggering CI run succeeded (auto path) or on manual dispatch.
if: >-
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'
outputs:
should_release: ${{ steps.check.outputs.should_release }}
version: ${{ steps.check.outputs.version }}
steps:
- uses: actions/checkout@v6
with:
sparse-checkout: lib/code_ownership/version.rb
sparse-checkout-cone-mode: false
fetch-depth: 1
- id: check
run: |
VERSION=$(ruby -r ./lib/code_ownership/version.rb -e "puts CodeOwnership::VERSION")
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
# Manual dispatch always proceeds (dry-run testing / forced release);
# the publish step still skips versions already on RubyGems.
SHOULD_RELEASE=true
REASON="manual dispatch (dry_run=${{ inputs.dry_run }})"
elif curl -sf -o /dev/null "https://rubygems.org/api/v2/rubygems/code_ownership/versions/${VERSION}.json"; then
SHOULD_RELEASE=false
REASON="${VERSION} already on RubyGems — skipping release"
else
SHOULD_RELEASE=true
REASON="${VERSION} not published — will release"
fi
echo "should_release=${SHOULD_RELEASE}" >> "$GITHUB_OUTPUT"
echo "::notice::code_ownership ${REASON}."
ci-data:
needs: check-release
if: needs.check-release.outputs.should_release == 'true'
runs-on: ubuntu-latest
outputs:
result: ${{ steps.fetch.outputs.result }}
steps:
- id: fetch
uses: oxidize-rb/actions/fetch-ci-data@v1
with:
supported-ruby-platforms: |
# Excluding:
# `arm-linux`: Cranelift doesn't support 32-bit architectures
# `x64-mingw32`: `x64-mingw-ucrt` should be used for Ruby 3.1+ (https://github.com/rake-compiler/rake-compiler-dock?tab=readme-ov-file#windows)
# 3.0 is deprecated as stable ruby version according to:
# https://github.com/oxidize-rb/actions/blob/main/fetch-ci-data/evaluate.rb#L54
exclude: [arm-linux, x64-mingw32]
stable-ruby-versions: |
only: ['3.3', '3.4', '4.0']
build:
name: Build native gems
needs: ci-data
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ruby-platform: ${{ fromJSON(needs.ci-data.outputs.result).supported-ruby-platforms }}
steps:
- uses: actions/checkout@v6
- uses: ruby/setup-ruby@v1
with:
ruby-version: '4.0'
- uses: oxidize-rb/actions/cross-gem@v1
id: cross-gem
with:
platform: ${{ matrix.ruby-platform }}
ruby-versions: ${{ join(fromJSON(needs.ci-data.outputs.result).stable-ruby-versions, ',') }}
cache-save-always: false
cargo-cache-clean: false # Add this to disable cargo-cache usage
env:
# Add a unique identifier to prevent cache conflicts
ACTIONS_CACHE_KEY_SUFFIX: "-${{ matrix.ruby-platform }}-${{ github.run_id }}"
- uses: actions/upload-artifact@v4
with:
name: cross-gem-${{ matrix.ruby-platform }}
path: pkg/*-${{ matrix.ruby-platform }}.gem
if-no-files-found: error
retention-days: 30 # Keep artifacts for 30 days
- name: Smoke test gem install
if: matrix.ruby-platform == 'x86_64-linux' # Enable for Linux x64
run: |
# Install the platform-specific gem
gem install pkg/code_ownership-*-${{ matrix.ruby-platform }}.gem --verbose
# Test that it works
ruby -e "require 'code_ownership'; puts 'Version: ' + CodeOwnership::VERSION"
# Run a simple functionality test that exercises the Rust native extension
ruby -e "require 'code_ownership'; puts CodeOwnership.version"
echo "✅ Successfully tested ${{ matrix.ruby-platform }} gem"
release:
name: Release
needs: build
runs-on: ubuntu-latest
permissions:
contents: write # Required for creating releases
steps:
- uses: actions/checkout@v6
- uses: oxidize-rb/actions/setup-ruby-and-rust@v1
with:
bundler-cache: true
cargo-cache: false
- uses: actions/download-artifact@v4
with:
pattern: cross-gem-*
merge-multiple: true
path: pkg/
- name: Package source gem
run: bundle exec rake pkg:ruby
- name: Push Gem
id: push-gem
working-directory: pkg/
env:
GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
run: |
set -e # Exit on error
# Setup credentials
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
# List all gems to be pushed
echo "📦 Gems to be pushed:"
ls -la *.gem
# Extract version from the Ruby version file
GEM_VERSION=$(ruby -r ../lib/code_ownership/version.rb -e "puts CodeOwnership::VERSION")
echo "gem_version=${GEM_VERSION}" >> $GITHUB_OUTPUT
echo "🏷️ Detected gem version: ${GEM_VERSION}"
# Track results
NEW_VERSION=false
PUSHED_GEMS=()
SKIPPED_GEMS=()
for i in *.gem; do
if [ -f "$i" ]; then
echo "⏳ Attempting to push $i..."
if [ "${{ inputs.dry_run }}" = "true" ]; then
echo "🧪 dry-run: would push $i (skipping)"
SKIPPED_GEMS+=("$i")
continue
fi
if ! gem push "$i" >push.out 2>&1; then
gemerr=$?
if grep -q "Repushing of gem" push.out; then
echo "⏭️ Gem $i already exists on RubyGems, skipping..."
SKIPPED_GEMS+=("$i")
else
echo "❌ Failed to push $i:"
cat push.out
exit $gemerr
fi
else
echo "✅ Successfully pushed $i"
PUSHED_GEMS+=("$i")
NEW_VERSION=true
fi
fi
done
# Summary
echo "📊 Push Summary:"
echo " - Pushed: ${#PUSHED_GEMS[@]} gems"
echo " - Skipped: ${#SKIPPED_GEMS[@]} gems"
# Set outputs
echo "new_version=${NEW_VERSION}" >> $GITHUB_OUTPUT
echo "pushed_count=${#PUSHED_GEMS[@]}" >> $GITHUB_OUTPUT
echo "skipped_count=${#SKIPPED_GEMS[@]}" >> $GITHUB_OUTPUT
- name: Create GitHub Release
if: ${{ steps.push-gem.outputs.new_version == 'true' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Create release with more detailed information
RELEASE_NOTES="## CodeOwnership v${{ steps.push-gem.outputs.gem_version }}
### 📦 Published Gems
- Source gem: code_ownership-${{ steps.push-gem.outputs.gem_version }}.gem
- Platform gems: Published for all supported platforms
### 🎯 Supported Platforms
$(ls pkg/*.gem | grep -E '\-(x86|arm|aarch)' | sed 's/.*-\([^-]*\)\.gem/- \1/')
---
"
gh release create "v${{ steps.push-gem.outputs.gem_version }}" \
--title "v${{ steps.push-gem.outputs.gem_version }}" \
--notes "$RELEASE_NOTES" \
--generate-notes \
pkg/*.gem
notify_on_release:
runs-on: ubuntu-latest
needs: [check-release, release]
if: ${{ needs.release.result == 'success' }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
steps:
- uses: slackapi/slack-github-action@v1.25.0
with:
payload: |
{
"text": "🎉 Released ${{ github.repository }} v${{ needs.check-release.outputs.version }}"
}