Release 2.7.8 #19
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: Release | |
| run-name: Release ${{ inputs.version }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Ruby version to release (e.g., 3.4.7)' | |
| required: true | |
| type: string | |
| latest: | |
| description: 'Mark as latest release' | |
| required: false | |
| type: boolean | |
| default: false | |
| # Prevent multiple releases of the same version from running simultaneously | |
| concurrency: | |
| group: release-${{ inputs.version }} | |
| cancel-in-progress: false | |
| env: | |
| HOMEBREW_DEVELOPER: 1 | |
| HOMEBREW_NO_AUTO_UPDATE: 1 | |
| # Runner images lack a rootless bwrap; newer Homebrew otherwise refuses | |
| # to build from source on Linux (CI runners are throwaway anyway). | |
| HOMEBREW_NO_SANDBOX_LINUX: 1 | |
| permissions: | |
| contents: read | |
| id-token: write | |
| attestations: write | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Linux runners must satisfy Homebrew 6's glibc baseline (2.39, | |
| # i.e. ubuntu-24.04) from the host: on older hosts every bottle | |
| # pour drags in Homebrew's own glibc + gcc, and the resulting | |
| # ruby links .linuxbrew/glibc, failing the portability check. | |
| - runner: macos-14 | |
| yjit: true | |
| - runner: ubuntu-24.04 | |
| yjit: true | |
| - runner: ubuntu-24.04 | |
| yjit: false | |
| - runner: ubuntu-24.04-arm | |
| yjit: true | |
| - runner: ubuntu-24.04-arm | |
| yjit: false | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # main | |
| # Disabled: Code signing causes issues with native gems compiled locally | |
| # See: https://github.com/jdx/mise/discussions/7268 | |
| # - name: Import codesign certs | |
| # if: runner.os == 'macOS' | |
| # uses: apple-actions/import-codesign-certs@63fff01cd422d4b7b855d40ca1e9d34d2de9427d # v3 | |
| # with: | |
| # p12-file-base64: ${{ secrets.CERTIFICATES_P12 }} | |
| # p12-password: ${{ secrets.CERTIFICATES_P12_PASS }} | |
| - uses: ruby/setup-ruby@v1 | |
| id: setup-ruby | |
| with: | |
| ruby-version: ${{ inputs.version }} | |
| - name: Install Homebrew | |
| run: | | |
| /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
| echo "/home/linuxbrew/.linuxbrew/bin" >> $GITHUB_PATH | |
| eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" | |
| - name: Tap repo | |
| run: bin/setup | |
| - name: Fix Bundler permissions (ARM Linux) | |
| if: runner.os == 'Linux' && runner.arch == 'ARM64' | |
| run: chmod -R go-w /home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/vendor/bundle || true | |
| - name: Build jdx Ruby | |
| uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4 | |
| with: | |
| timeout_minutes: 30 | |
| max_attempts: 3 | |
| retry_wait_seconds: 30 | |
| command: | | |
| if [[ -n "${{ steps.setup-ruby.outputs.ruby-prefix }}" ]]; then | |
| export HOMEBREW_BASERUBY="${{ steps.setup-ruby.outputs.ruby-prefix }}/bin/ruby" | |
| fi | |
| YJIT_FLAG="" | |
| if [[ "${{ matrix.yjit }}" == "false" ]]; then | |
| YJIT_FLAG="--without-yjit" | |
| fi | |
| mkdir -p rubies/ | |
| cd rubies | |
| brew jdx-package --verbose $YJIT_FLAG jdx-ruby@${{ inputs.version }} | |
| # Disabled: Code signing causes issues with native gems compiled locally | |
| # See: https://github.com/jdx/mise/discussions/7268 | |
| # - name: Codesign macOS binaries | |
| # if: runner.os == 'macOS' | |
| # working-directory: rubies | |
| # run: | | |
| # tarball=$(ls *.tar.gz) | |
| # echo "Signing binaries in $tarball" | |
| # | |
| # # Extract | |
| # mkdir -p extracted | |
| # tar -xzf "$tarball" -C extracted | |
| # | |
| # # Sign Mach-O executables and bundles (skip .dSYM, .o, .a files) | |
| # find extracted -type f \( -name "*.bundle" -o -name "*.dylib" -o -perm +111 \) \ | |
| # -not -path "*.dSYM/*" \ | |
| # -not -name "*.o" \ | |
| # -not -name "*.a" | while read -r file; do | |
| # if file "$file" | grep -q "Mach-O"; then | |
| # echo "Signing $file" | |
| # codesign --sign "Developer ID Application: Jeffrey Dickey (4993Y37DX6)" \ | |
| # --identifier "dev.jdx.ruby" \ | |
| # --options runtime \ | |
| # --force \ | |
| # "$file" | |
| # fi | |
| # done | |
| # | |
| # # Re-create tarball | |
| # rm "$tarball" | |
| # tar -czf "$tarball" -C extracted . | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: ruby-${{ inputs.version }}-${{ matrix.runner }}-yjit-${{ matrix.yjit }} | |
| path: rubies/ | |
| create-release: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| outputs: | |
| revision_tag: ${{ steps.revision.outputs.tag }} | |
| permissions: | |
| contents: write | |
| env: | |
| VERSION: ${{ inputs.version }} | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # main | |
| - name: Determine build revision | |
| id: revision | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| # Find existing revision tags (e.g., 3.4.5-1, 3.4.5-2, ...) | |
| # Use git ls-remote to get all tags β not truncated like gh release list | |
| last_revision=$(git ls-remote --tags origin "refs/tags/${VERSION}-*" | \ | |
| sed 's|.*refs/tags/||' | \ | |
| { grep -E "^${VERSION}-[0-9]+$" || true; } | \ | |
| sed "s/^${VERSION}-//" | \ | |
| sort -n | tail -1) | |
| if [[ -z "$last_revision" ]]; then | |
| revision=1 | |
| else | |
| revision=$((last_revision + 1)) | |
| fi | |
| echo "tag=${VERSION}-${revision}" >> "$GITHUB_OUTPUT" | |
| echo "Build revision: ${VERSION}-${revision}" | |
| - name: Get Ruby release info | |
| id: ruby-release | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| # Convert version format: 3.4.1 -> v3_4_1 (but Ruby 4.x uses v4.0.0 format) | |
| ruby_tag="v${VERSION//./_}" | |
| # Fetch release info from ruby/ruby repo (try underscore format first, then dot format) | |
| release_info=$(gh release view "$ruby_tag" --repo ruby/ruby --json publishedAt,body 2>/dev/null || \ | |
| gh release view "v${VERSION}" --repo ruby/ruby --json publishedAt,body 2>/dev/null || echo "{}") | |
| release_date=$(echo "$release_info" | jq -r '.publishedAt // empty') | |
| if [[ -n "$release_date" ]]; then | |
| # Format as YYYY-MM-DD | |
| formatted_date=$(date -d "$release_date" '+%Y-%m-%d' 2>/dev/null || date -j -f '%Y-%m-%dT%H:%M:%SZ' "$release_date" '+%Y-%m-%d' 2>/dev/null || echo "${release_date:0:10}") | |
| echo "date=$formatted_date" >> "$GITHUB_OUTPUT" | |
| echo "Found Ruby $VERSION release date: $formatted_date" | |
| else | |
| echo "date=" >> "$GITHUB_OUTPUT" | |
| echo "Could not find Ruby release date for $ruby_tag" | |
| fi | |
| # Save changelog body to file (handles multiline content) | |
| changelog=$(echo "$release_info" | jq -r '.body // empty') | |
| if [[ -n "$changelog" ]]; then | |
| echo "$changelog" > /tmp/ruby_changelog.md | |
| echo "has_changelog=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "has_changelog=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Create releases | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} | |
| RUBY_RELEASE_DATE: ${{ steps.ruby-release.outputs.date }} | |
| HAS_CHANGELOG: ${{ steps.ruby-release.outputs.has_changelog }} | |
| REVISION_TAG: ${{ steps.revision.outputs.tag }} | |
| run: | | |
| if [[ "${{ inputs.latest }}" == "true" ]]; then | |
| latest_flag="--latest" | |
| else | |
| latest_flag="--latest=false" | |
| fi | |
| # Mark as prerelease if version contains preview or rc | |
| if echo "${VERSION}" | grep -qiE '(preview|rc)'; then | |
| prerelease_flag="--prerelease" | |
| else | |
| prerelease_flag="" | |
| fi | |
| # Build release notes file | |
| echo "Ruby ${VERSION} portable binaries" > /tmp/release_notes.md | |
| if [[ -n "$RUBY_RELEASE_DATE" ]]; then | |
| echo "" >> /tmp/release_notes.md | |
| echo "**Released by Ruby:** ${RUBY_RELEASE_DATE}" >> /tmp/release_notes.md | |
| fi | |
| if [[ "$HAS_CHANGELOG" == "true" ]]; then | |
| echo "" >> /tmp/release_notes.md | |
| echo "---" >> /tmp/release_notes.md | |
| echo "" >> /tmp/release_notes.md | |
| cat /tmp/ruby_changelog.md >> /tmp/release_notes.md | |
| fi | |
| TARGET="$(git rev-parse --verify HEAD)" | |
| # Delete ALL existing floating releases matching this version (handles orphaned releases) | |
| for release_id in $(gh api repos/${{ github.repository }}/releases --paginate --jq ".[] | select(.name == \"${VERSION}\" or .tag_name == \"${VERSION}\") | .id"); do | |
| echo "Deleting release $release_id" | |
| gh api -X DELETE "repos/${{ github.repository }}/releases/$release_id" || true | |
| done | |
| # Also delete the tag if it exists | |
| gh api -X DELETE "repos/${{ github.repository }}/git/refs/tags/${VERSION}" 2>/dev/null || true | |
| # Create floating release (e.g., 3.4.5) β always updated to latest build | |
| gh release create "${VERSION}" \ | |
| --draft \ | |
| --notes-file /tmp/release_notes.md \ | |
| --target "$TARGET" \ | |
| --title "${VERSION}" \ | |
| $latest_flag \ | |
| $prerelease_flag | |
| # Create pinned revision release (e.g., 3.4.5-1) β immutable snapshot | |
| echo "" >> /tmp/release_notes.md | |
| echo "**Build revision:** ${REVISION_TAG}" >> /tmp/release_notes.md | |
| gh release create "${REVISION_TAG}" \ | |
| --draft \ | |
| --notes-file /tmp/release_notes.md \ | |
| --target "$TARGET" \ | |
| --title "${REVISION_TAG}" \ | |
| --latest=false \ | |
| $prerelease_flag | |
| upload-assets: | |
| needs: [build, create-release] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| id-token: write | |
| attestations: write | |
| env: | |
| VERSION: ${{ inputs.version }} | |
| steps: | |
| - name: Download artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| pattern: ruby-${{ inputs.version }}-* | |
| path: rubies | |
| merge-multiple: true | |
| - name: Upload tarballs to GitHub Release | |
| working-directory: rubies | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} | |
| REVISION_TAG: ${{ needs.create-release.outputs.revision_tag }} | |
| run: | | |
| gh release upload "${VERSION}" *.tar.gz --clobber --repo "${{ github.repository }}" | |
| gh release upload "${REVISION_TAG}" *.tar.gz --clobber --repo "${{ github.repository }}" | |
| - name: Attest build provenance | |
| # Attestation is advisory (mise skips verification for custom | |
| # precompiled_url templates); never block the release on it. | |
| continue-on-error: true | |
| uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4 | |
| with: | |
| subject-path: 'rubies/*.tar.gz' | |
| publish-release: | |
| needs: [create-release, upload-assets] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| env: | |
| VERSION: ${{ inputs.version }} | |
| steps: | |
| - name: Publish release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} | |
| REVISION_TAG: ${{ needs.create-release.outputs.revision_tag }} | |
| run: | | |
| # Mark as prerelease if version contains preview or rc | |
| if echo "${VERSION}" | grep -qiE '(preview|rc)'; then | |
| prerelease_flag="--prerelease" | |
| else | |
| prerelease_flag="" | |
| fi | |
| # Publish floating release | |
| if [[ "${{ inputs.latest }}" == "true" ]]; then | |
| gh release edit "${VERSION}" --draft=false --latest $prerelease_flag --repo "${{ github.repository }}" | |
| else | |
| gh release edit "${VERSION}" --draft=false --latest=false $prerelease_flag --repo "${{ github.repository }}" | |
| fi | |
| # Publish pinned revision release | |
| gh release edit "${REVISION_TAG}" --draft=false --latest=false $prerelease_flag --repo "${{ github.repository }}" |