From 85e5dcfd83696acbc9d33529694b25961bafceac Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Fri, 6 Jun 2025 10:58:03 -0600 Subject: [PATCH 01/34] pass release notes to publish action, and make it idempotent --- ruby/publish/action.yml | 71 ++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index 711e99d..b931da4 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -32,8 +32,8 @@ inputs: product_id: description: The identifier of the product being published (e.g. "mongo-ruby-driver") required: true - release_message_template: - description: The template for the release message. Use "{0}" in the text to refer to the current version. + release_notes: + description: The release notes to post as the description of the new release required: true rubygems_version: description: The version of Rubygems to use (see setup-ruby/action.yml) @@ -94,35 +94,58 @@ runs: dist_filenames: ${{ env.GEM_FILE_NAME }} silk_asset_group: ${{ inputs.silk_asset_group }} + - name: Look for existing tag + id: tag_exists + shell: bash + run: | + if git rev-parse "v${{ env.RELEASE_VERSION }}" >/dev/null 2>&1; then + echo "Tag v${{ env.RELEASE_VERSION }} already exists." + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "Tag v${{ env.RELEASE_VERSION }} does not exist." + echo "exists=false" >> "$GITHUB_OUTPUT" + fi + - name: Create the tag uses: mongodb-labs/drivers-github-tools/tag-version@v2 + if: steps.tag_exists.outputs.exists == 'false' with: version: ${{ env.RELEASE_VERSION }} tag_template: "v${VERSION}" tag_message_template: "Release tag for v${VERSION}" - - name: Create a new release + - name: Prepare release message shell: bash - run: gh release create v${{ env.RELEASE_VERSION }} --title ${{ env.RELEASE_VERSION }} --generate-notes --draft + run: | + cat <<'__EOF__' > release-message + ${{ inputs.release_notes }} + __EOF__ - - name: Capture the changelog + - name: Look for existing release + id: release_exists shell: bash - run: gh release view v${{ env.RELEASE_VERSION }} --json body --template '{{ .body }}' >> changelog + run: | + if gh release view "v${{ env.RELEASE_VERSION }}" >/dev/null 2>&1; then + echo "Release v${{ env.RELEASE_VERSION }} already exists." + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "Release v${{ env.RELEASE_VERSION }} does not exist." + echo "exists=false" >> "$GITHUB_OUTPUT" + fi - - name: Prepare release message + - name: Create a new release + if: steps.release_exists.outputs.exists == 'false' shell: bash - run: | - echo "${{ format(inputs.release_message_template, env.RELEASE_VERSION) }}" > release-message - cat changelog >> release-message + run: gh release create v${{ env.RELEASE_VERSION }} --title ${{ env.RELEASE_VERSION }} --notes-file release-message --draft - - name: Update release information + - name: Else update the existing release + if: steps.release_exists.outputs.exists == 'true' shell: bash - run: | - echo "RELEASE_URL=$(gh release edit v${{ env.RELEASE_VERSION }} --notes-file release-message)" >> "$GITHUB_ENV" + run: gh release edit v${{ env.RELEASE_VERSION }} --notes-file release-message - name: Upload release artifacts shell: bash - run: gh release upload v${{ env.RELEASE_VERSION }} ${{ env.GEM_FILE_NAME }} ${{ env.RELEASE_ASSETS }}/${{ env.GEM_FILE_NAME }}.sig + run: gh release upload --clobber v${{ env.RELEASE_VERSION }} ${{ env.GEM_FILE_NAME }} ${{ env.RELEASE_ASSETS }}/${{ env.GEM_FILE_NAME }}.sig - name: Upload S3 assets uses: mongodb-labs/drivers-github-tools/upload-s3-assets@v2 @@ -131,8 +154,26 @@ runs: product_name: ${{ inputs.product_id }} dry_run: ${{ inputs.dry_run }} + - name: Look for existing gem + id: gem_exists + shell: bash + run: | + if gem search --remote ${{ inputs.gem_name }} --version ${{ env.RELEASE_VERSION }} | grep -q "${{ env.RELEASE_VERSION }}"; then + echo "Gem ${{ inputs.gem_name }} version ${{ env.RELEASE_VERSION }} already exists." + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "Gem ${{ inputs.gem_name }} version ${{ env.RELEASE_VERSION }} does not exist." + echo "exists=false" >> "$GITHUB_OUTPUT" + fi + - name: Publish the gem uses: rubygems/release-gem@a25424ba2ba8b387abc8ef40807c2c85b96cbe32 # v1 - if: inputs.dry_run == 'false' + if: inputs.dry_run == 'false' && steps.gem_exists.outputs.exists == 'false' with: await-release: false + + - name: Publish the release + if: inputs.dry_run == 'false' + shell: bash + run: gh release edit v${{ env.RELEASE_VERSION }} --draft=false + From 3e526e9f68372750226c707e3ba2c3dea783790d Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 9 Jun 2025 16:20:55 -0600 Subject: [PATCH 02/34] split build & publish --- ruby/build/action.yml | 68 ++++++++++++++++++++++++++++++++++++ ruby/build/gem_name.rb | 21 ++++++++++++ ruby/publish/action.yml | 76 +++++++++++++++++++---------------------- 3 files changed, 124 insertions(+), 41 deletions(-) create mode 100644 ruby/build/action.yml create mode 100644 ruby/build/gem_name.rb diff --git a/ruby/build/action.yml b/ruby/build/action.yml new file mode 100644 index 0000000..65cefbf --- /dev/null +++ b/ruby/build/action.yml @@ -0,0 +1,68 @@ +name: Build Gem +description: Build a gem for a DBX Ruby project +inputs: + app_id: + description: The APP_ID defined for this project + required: true + app_private_key: + description: The APP_PRIVATE_KEY defined for this project + required: true + artifact: + description: The name to give the generated artifact (e.g. "ruby" or "jruby") + required: false + default: ruby + bundler_cache_version: + description: The cache-version to use for the bundler cache + required: false + default: '0' + gem_name: + description: The name (sans extension) of the gemspec file (e.g. "mongo") + required: true + ruby_version: + description: The version of Ruby to use (see setup-ruby/action.yml) + default: '3.2' + required: false + rubygems_version: + description: The version of Rubygems to use (see setup-ruby/action.yml) + required: false + default: latest + +runs: + using: composite + steps: + - name: Check out the repository + uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 + with: + app_id: ${{ inputs.app_id }} + private_key: ${{ inputs.app_private_key }} + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ inputs.ruby_version }} + rubygems: ${{ inputs.rubygems_version }} + bundler-cache: true + cache-version: ${{ inputs.bundler_cache_version }} + + - name: Get the release version + id: release_version + shell: bash + run: echo "version=$(bundle exec rake version)" >> "$GITHUB_OUTPUT" + + - name: Get the gem file name + shell: bash + id: gem_name + run: echo "name=$(ruby ${{ github.action_path }}/gem_name.rb ${{ inputs.gem_name }} ${{ steps.release_version.outputs.version }})" >> "$GITHUB_OUTPUT" + + - name: Build the gem + shell: bash + run: | + gem build --output=${{ steps.gem_name.outputs.name }} ${{ inputs.gem_name }}.gemspec + + - name: Save the generated gem file for later + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifact }} + path: ${{ steps.gem_name.outputs.name }} + retention-days: 1 + overwrite: true diff --git a/ruby/build/gem_name.rb b/ruby/build/gem_name.rb new file mode 100644 index 0000000..a99284a --- /dev/null +++ b/ruby/build/gem_name.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# This script generates the name of a gem file based on the provided +# gem name and version. It takes into account whether it is running +# under JRuby to append "-java" to the gem name if necessary. +# +# Usage: +# ruby gem_name.rb + +if ARGV.length != 2 + puts "Usage: ruby gem_name.rb " + exit 1 +end + +gem_name = ARGV.first +gem_version = ARGV.last + +base_name = "#{gem_name}-#{gem_version}" +base_name = "#{base_name}-java" if defined?(JRUBY_VERSION) + +puts "#{base_name}.gem" diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index b931da4..91771b7 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -1,5 +1,5 @@ name: Publish Ruby -description: Generate and publish gems, signatures, and assets for MongoDB Ruby projects +description: Publish gems, signatures, and assets for MongoDB Ruby projects inputs: app_id: description: The APP_ID defined for this project @@ -32,13 +32,17 @@ inputs: product_id: description: The identifier of the product being published (e.g. "mongo-ruby-driver") required: true - release_notes: - description: The release notes to post as the description of the new release + release_notes_path: + description: The path to a file containing the release notes to post as the description of the new release required: true rubygems_version: description: The version of Rubygems to use (see setup-ruby/action.yml) required: false default: latest + ruby_version: + description: The version of Ruby to use (see setup-ruby/action.yml) + default: '3.2' + required: false silk_asset_group: description: The Silk asset group for the project required: true @@ -53,16 +57,17 @@ runs: private_key: ${{ inputs.app_private_key }} - name: Setup Ruby - uses: ruby/setup-ruby@dffc446db9ba5a0c4446edb5bca1c5c473a806c5 # v1 + uses: ruby/setup-ruby@v1 with: - ruby-version: '3.2' + ruby-version: ${{ inputs.ruby_version }} rubygems: ${{ inputs.rubygems_version }} bundler-cache: true cache-version: ${{ inputs.bundler_cache_version }} - name: Get the release version + id: release_version shell: bash - run: echo "RELEASE_VERSION=$(bundle exec rake version)" >> "$GITHUB_ENV" + run: echo "version=$(bundle exec rake version)" >> "$GITHUB_OUTPUT" - name: Setup GitHub tooling for DBX Drivers uses: mongodb-labs/drivers-github-tools/setup@v2 @@ -71,38 +76,34 @@ runs: aws_region_name: ${{ inputs.aws_region_name }} aws_secret_id: ${{ inputs.aws_secret_id }} - - name: Set output gem file name - shell: bash - run: | - echo "GEM_FILE_NAME=${{ inputs.gem_name }}-${{ env.RELEASE_VERSION }}.gem" >> "$GITHUB_ENV" - - - name: Build the gem - shell: bash - run: | - gem build --output=${{ env.GEM_FILE_NAME }} ${{ inputs.gem_name }}.gemspec + - name: Fetch the gem artifacts + uses: actions/download-artifact@v4 + with: + pattern: '*.gem' + merge-multiple: true - name: Sign the gem uses: mongodb-labs/drivers-github-tools/gpg-sign@v2 with: - filenames: '${{ env.GEM_FILE_NAME }}' + filenames: '*.gem' - name: Generate SSDLC Reports uses: mongodb-labs/drivers-github-tools/full-report@v2 with: product_name: ${{ inputs.product_name }} - release_version: ${{ env.RELEASE_VERSION }} - dist_filenames: ${{ env.GEM_FILE_NAME }} + release_version: ${{ steps.release_version.outputs.version }} + dist_filenames: '*.gem' silk_asset_group: ${{ inputs.silk_asset_group }} - name: Look for existing tag id: tag_exists shell: bash run: | - if git rev-parse "v${{ env.RELEASE_VERSION }}" >/dev/null 2>&1; then - echo "Tag v${{ env.RELEASE_VERSION }} already exists." + if git rev-parse "v${{ steps.release_version.outputs.version }}" >/dev/null 2>&1; then + echo "Tag v${{ steps.release_version.outputs.version }} already exists." echo "exists=true" >> "$GITHUB_OUTPUT" else - echo "Tag v${{ env.RELEASE_VERSION }} does not exist." + echo "Tag v${{ steps.release_version.outputs.version }} does not exist." echo "exists=false" >> "$GITHUB_OUTPUT" fi @@ -110,47 +111,40 @@ runs: uses: mongodb-labs/drivers-github-tools/tag-version@v2 if: steps.tag_exists.outputs.exists == 'false' with: - version: ${{ env.RELEASE_VERSION }} + version: ${{ steps.release_version.outputs.version }} tag_template: "v${VERSION}" tag_message_template: "Release tag for v${VERSION}" - - name: Prepare release message - shell: bash - run: | - cat <<'__EOF__' > release-message - ${{ inputs.release_notes }} - __EOF__ - - name: Look for existing release id: release_exists shell: bash run: | - if gh release view "v${{ env.RELEASE_VERSION }}" >/dev/null 2>&1; then - echo "Release v${{ env.RELEASE_VERSION }} already exists." + if gh release view "v${{ steps.release_version.outputs.version }}" >/dev/null 2>&1; then + echo "Release v${{ steps.release_version.outputs.version }} already exists." echo "exists=true" >> "$GITHUB_OUTPUT" else - echo "Release v${{ env.RELEASE_VERSION }} does not exist." + echo "Release v${{ steps.release_version.outputs.version }} does not exist." echo "exists=false" >> "$GITHUB_OUTPUT" fi - name: Create a new release if: steps.release_exists.outputs.exists == 'false' shell: bash - run: gh release create v${{ env.RELEASE_VERSION }} --title ${{ env.RELEASE_VERSION }} --notes-file release-message --draft + run: gh release create v${{ steps.release_version.outputs.version }} --title ${{ steps.release_version.outputs.version }} --notes-file ${{ inputs.release_notes_path }} --draft - name: Else update the existing release if: steps.release_exists.outputs.exists == 'true' shell: bash - run: gh release edit v${{ env.RELEASE_VERSION }} --notes-file release-message + run: gh release edit v${{ steps.release_version.outputs.version }} --notes-file ${{ inputs.release_notes_path }} - name: Upload release artifacts shell: bash - run: gh release upload --clobber v${{ env.RELEASE_VERSION }} ${{ env.GEM_FILE_NAME }} ${{ env.RELEASE_ASSETS }}/${{ env.GEM_FILE_NAME }}.sig + run: gh release upload --clobber v${{ steps.release_version.outputs.version }} *.gem ${{ env.RELEASE_ASSETS }}/*.sig - name: Upload S3 assets uses: mongodb-labs/drivers-github-tools/upload-s3-assets@v2 with: - version: ${{ env.RELEASE_VERSION }} + version: ${{ steps.release_version.outputs.version }} product_name: ${{ inputs.product_id }} dry_run: ${{ inputs.dry_run }} @@ -158,16 +152,16 @@ runs: id: gem_exists shell: bash run: | - if gem search --remote ${{ inputs.gem_name }} --version ${{ env.RELEASE_VERSION }} | grep -q "${{ env.RELEASE_VERSION }}"; then - echo "Gem ${{ inputs.gem_name }} version ${{ env.RELEASE_VERSION }} already exists." + if gem search --remote ${{ inputs.gem_name }} --version ${{ steps.release_version.outputs.version }} | grep -q "${{ steps.release_version.outputs.version }}"; then + echo "Gem ${{ inputs.gem_name }} version ${{ steps.release_version.outputs.version }} already exists." echo "exists=true" >> "$GITHUB_OUTPUT" else - echo "Gem ${{ inputs.gem_name }} version ${{ env.RELEASE_VERSION }} does not exist." + echo "Gem ${{ inputs.gem_name }} version ${{ steps.release_version.outputs.version }} does not exist." echo "exists=false" >> "$GITHUB_OUTPUT" fi - name: Publish the gem - uses: rubygems/release-gem@a25424ba2ba8b387abc8ef40807c2c85b96cbe32 # v1 + uses: rubygems/release-gem@v1 if: inputs.dry_run == 'false' && steps.gem_exists.outputs.exists == 'false' with: await-release: false @@ -175,5 +169,5 @@ runs: - name: Publish the release if: inputs.dry_run == 'false' shell: bash - run: gh release edit v${{ env.RELEASE_VERSION }} --draft=false + run: gh release edit v${{ steps.release_version.outputs.version }} --draft=false From 84b5369fca3584585dba70c8f4b48e23d5c02a04 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 12 Jun 2025 11:10:33 -0600 Subject: [PATCH 03/34] add PR-check action --- ruby/pr-check/action.yml | 73 ++++++++++++++++++++++++++++++++++++++++ ruby/publish/action.yml | 15 ++++++--- 2 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 ruby/pr-check/action.yml diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml new file mode 100644 index 0000000..f92be5f --- /dev/null +++ b/ruby/pr-check/action.yml @@ -0,0 +1,73 @@ +name: PR Check +description: Check that a PR is eligible for release + +outputs: + message: + description: The body of the pull request that is being released. + value: ${{ steps.check_pr.outputs.message }} + ref: + description: The ref of the pull request that is being released. + value: ${{ steps.check_pr.outputs.ref }} + +runs: + using: composite + steps: + - name: "Check PR Eligibility" + id: check_pr + uses: actions/github-script@v7 + with: + script: | + let pr; + + // if the event is a pull request, then we don't need to check + // the actors permissions, because they'll have had permissions + // to merge the PR in the first place. + if (context.pull_request) { + pr = context.pull_request; + + // if the event is a comment, then we need to check that the + // comment is in the correct format, and that the user has + // admin permissions on the repository. + } else if (context.issue) { + const comment = context.payload.comment; + + // first, is the message in the correct format? + const body = comment.body.trim(); + if (body != '/release') { + throw new Error('Command not detected in comment body.'); + } + + // if the event is an issue comment, we need to check the + // comment author has admin permissions on the repository, + // before we let them proceed. + const username = comment.user.login; + const { data: results } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username, + }); + if (results.permission !== 'admin') { + throw new Error(`User ${username} must have admin permissions to initiate the release process.`); + } + + const result = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }); + + pr = result.data + } + + if (!pr) { + throw new Error('No pull request found for the triggered event.'); + } + if (!pr.merged) { + throw new Error('Pull request is not merged.'); + } + if (!pr.labels.some(label => label.name == 'release-candidate')) { + throw new Error('Pull request is not a release candidate.'); + } + + core.setOutput('message', pr.body); + core.setOutput('ref', pr.merge_commit_sha); diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index 91771b7..e4f46d1 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -32,8 +32,8 @@ inputs: product_id: description: The identifier of the product being published (e.g. "mongo-ruby-driver") required: true - release_notes_path: - description: The path to a file containing the release notes to post as the description of the new release + release_message: + description: The (markdown-formatted) text to post as the description of the new release required: true rubygems_version: description: The version of Rubygems to use (see setup-ruby/action.yml) @@ -127,15 +127,22 @@ runs: echo "exists=false" >> "$GITHUB_OUTPUT" fi + - name: Write release notes to file + shell: bash + run: | + echo <<'__RELEASE_NOTES_IKDJAIELD__' > release_notes.txt + ${{ inputs.release_message }} + __RELEASE_NOTES_IKDJAIELD__ + - name: Create a new release if: steps.release_exists.outputs.exists == 'false' shell: bash - run: gh release create v${{ steps.release_version.outputs.version }} --title ${{ steps.release_version.outputs.version }} --notes-file ${{ inputs.release_notes_path }} --draft + run: gh release create v${{ steps.release_version.outputs.version }} --title ${{ steps.release_version.outputs.version }} --notes-file release_notes.txt --draft - name: Else update the existing release if: steps.release_exists.outputs.exists == 'true' shell: bash - run: gh release edit v${{ steps.release_version.outputs.version }} --notes-file ${{ inputs.release_notes_path }} + run: gh release edit v${{ steps.release_version.outputs.version }} --notes-file release_notes.txt - name: Upload release artifacts shell: bash From 040fd64ebf1a7f532532881e8f71ada56803a890 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Fri, 13 Jun 2025 09:54:08 -0600 Subject: [PATCH 04/34] add some debugging for troubleshooting --- ruby/pr-check/action.yml | 3 +++ ruby/publish/action.yml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index f92be5f..45a86e1 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -19,6 +19,9 @@ runs: script: | let pr; + console.log('context keys:', Object.keys(context)); + console.log('context payload keys:', Object.keys(context.payload)); + // if the event is a pull request, then we don't need to check // the actors permissions, because they'll have had permissions // to merge the PR in the first place. diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index e4f46d1..38ffbf5 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -82,7 +82,7 @@ runs: pattern: '*.gem' merge-multiple: true - - name: Sign the gem + - name: Sign the gems uses: mongodb-labs/drivers-github-tools/gpg-sign@v2 with: filenames: '*.gem' From fde9f93a9658090155b380d76b103e152172e43e Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Fri, 13 Jun 2025 09:58:43 -0600 Subject: [PATCH 05/34] more debugging --- ruby/pr-check/action.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 45a86e1..23cdf6a 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -19,14 +19,11 @@ runs: script: | let pr; - console.log('context keys:', Object.keys(context)); - console.log('context payload keys:', Object.keys(context.payload)); - // if the event is a pull request, then we don't need to check // the actors permissions, because they'll have had permissions // to merge the PR in the first place. - if (context.pull_request) { - pr = context.pull_request; + if (context.payload.pull_request) { + pr = context.payload.pull_request; // if the event is a comment, then we need to check that the // comment is in the correct format, and that the user has @@ -72,5 +69,8 @@ runs: throw new Error('Pull request is not a release candidate.'); } + console.log('body: >>', pr.body, '<<'); + console.log('ref: >>', pr.merge_commit_sha, '<<); + core.setOutput('message', pr.body); core.setOutput('ref', pr.merge_commit_sha); From d0e0dec229bb829ac827247c5fe4791adda1a9f3 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Fri, 13 Jun 2025 10:01:04 -0600 Subject: [PATCH 06/34] typo --- ruby/pr-check/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 23cdf6a..0ffdd0c 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -70,7 +70,7 @@ runs: } console.log('body: >>', pr.body, '<<'); - console.log('ref: >>', pr.merge_commit_sha, '<<); + console.log('ref: >>', pr.merge_commit_sha, '<<'); core.setOutput('message', pr.body); core.setOutput('ref', pr.merge_commit_sha); From 066352c4e0f62878ce0315fa9a52bb7c19bf8a14 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 16 Jun 2025 09:30:09 -0600 Subject: [PATCH 07/34] add `ref` input parameter --- ruby/build/action.yml | 4 ++++ ruby/publish/action.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ruby/build/action.yml b/ruby/build/action.yml index 65cefbf..5585332 100644 --- a/ruby/build/action.yml +++ b/ruby/build/action.yml @@ -18,6 +18,9 @@ inputs: gem_name: description: The name (sans extension) of the gemspec file (e.g. "mongo") required: true + ref: + description: The reference to checkout (branch, tag, sha, etc) + required: true ruby_version: description: The version of Ruby to use (see setup-ruby/action.yml) default: '3.2' @@ -35,6 +38,7 @@ runs: with: app_id: ${{ inputs.app_id }} private_key: ${{ inputs.app_private_key }} + ref: ${{ inputs.ref }} - name: Setup Ruby uses: ruby/setup-ruby@v1 diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index 38ffbf5..071028f 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -32,6 +32,9 @@ inputs: product_id: description: The identifier of the product being published (e.g. "mongo-ruby-driver") required: true + ref: + description: The reference to checkout (branch, tag, sha, etc) + required: true release_message: description: The (markdown-formatted) text to post as the description of the new release required: true @@ -55,6 +58,7 @@ runs: with: app_id: ${{ inputs.app_id }} private_key: ${{ inputs.app_private_key }} + ref: ${{ inputs.ref }} - name: Setup Ruby uses: ruby/setup-ruby@v1 From 057146a097aec1dc4f99e4332afb0b70050afa6e Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 16 Jun 2025 11:20:55 -0600 Subject: [PATCH 08/34] permit write access to publish as well --- ruby/pr-check/action.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 0ffdd0c..99639c8 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -27,7 +27,7 @@ runs: // if the event is a comment, then we need to check that the // comment is in the correct format, and that the user has - // admin permissions on the repository. + // admin/write permissions on the repository. } else if (context.issue) { const comment = context.payload.comment; @@ -38,7 +38,7 @@ runs: } // if the event is an issue comment, we need to check the - // comment author has admin permissions on the repository, + // comment author has admin/write permissions on the repository, // before we let them proceed. const username = comment.user.login; const { data: results } = await github.rest.repos.getCollaboratorPermissionLevel({ @@ -46,8 +46,8 @@ runs: repo: context.repo.repo, username, }); - if (results.permission !== 'admin') { - throw new Error(`User ${username} must have admin permissions to initiate the release process.`); + if (results.permission !== 'admin' || results.permission !== 'write') { + throw new Error(`User ${username} must have admin or write permissions to initiate the release process.`); } const result = await github.rest.pulls.get({ From 023a472b86c1842a64f8ed06b39f710bf3849583 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 16 Jun 2025 11:22:42 -0600 Subject: [PATCH 09/34] troubleshooting: show the permissions of the current user --- ruby/pr-check/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 99639c8..d7c20e0 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -46,6 +46,8 @@ runs: repo: context.repo.repo, username, }); +console.log(results.permission); +console.log(results); if (results.permission !== 'admin' || results.permission !== 'write') { throw new Error(`User ${username} must have admin or write permissions to initiate the release process.`); } From 73e39058ec7b92140e38f274b3be93f62be818b9 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 16 Jun 2025 11:23:12 -0600 Subject: [PATCH 10/34] fix indentation --- ruby/pr-check/action.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index d7c20e0..7195efd 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -46,8 +46,9 @@ runs: repo: context.repo.repo, username, }); -console.log(results.permission); -console.log(results); + + console.log(results.permission); + console.log(results); if (results.permission !== 'admin' || results.permission !== 'write') { throw new Error(`User ${username} must have admin or write permissions to initiate the release process.`); } From bdbbe4dc7074aad0a5f41d7341ec90ce99e13faa Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 16 Jun 2025 11:26:25 -0600 Subject: [PATCH 11/34] use role_name instead of permissions --- ruby/pr-check/action.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 7195efd..1f69a6d 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -27,7 +27,7 @@ runs: // if the event is a comment, then we need to check that the // comment is in the correct format, and that the user has - // admin/write permissions on the repository. + // acceptible access to the repository. } else if (context.issue) { const comment = context.payload.comment; @@ -38,7 +38,7 @@ runs: } // if the event is an issue comment, we need to check the - // comment author has admin/write permissions on the repository, + // comment author has necessary access to the repository, // before we let them proceed. const username = comment.user.login; const { data: results } = await github.rest.repos.getCollaboratorPermissionLevel({ @@ -47,10 +47,8 @@ runs: username, }); - console.log(results.permission); - console.log(results); - if (results.permission !== 'admin' || results.permission !== 'write') { - throw new Error(`User ${username} must have admin or write permissions to initiate the release process.`); + if (results.role_name !== 'admin' && results.role_name !== 'maintain') { + throw new Error(`User ${username} must have `admin` or `maintain` role to initiate the release process.`); } const result = await github.rest.pulls.get({ From 96dfd8682d61371a9571eb81c01e888366f2eee0 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 16 Jun 2025 11:27:38 -0600 Subject: [PATCH 12/34] wrong quotes --- ruby/pr-check/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 1f69a6d..d41e14b 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -48,7 +48,7 @@ runs: }); if (results.role_name !== 'admin' && results.role_name !== 'maintain') { - throw new Error(`User ${username} must have `admin` or `maintain` role to initiate the release process.`); + throw new Error(`User ${username} must have 'admin' or 'maintain' role to initiate the release process.`); } const result = await github.rest.pulls.get({ From fb201adf42261c07c735642540d91b57160a49fc Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 16 Jun 2025 11:32:07 -0600 Subject: [PATCH 13/34] checkout submodules -- so the candidate.rake tasks can load --- ruby/build/action.yml | 1 + ruby/publish/action.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/ruby/build/action.yml b/ruby/build/action.yml index 5585332..9a7712f 100644 --- a/ruby/build/action.yml +++ b/ruby/build/action.yml @@ -39,6 +39,7 @@ runs: app_id: ${{ inputs.app_id }} private_key: ${{ inputs.app_private_key }} ref: ${{ inputs.ref }} + submodules: true - name: Setup Ruby uses: ruby/setup-ruby@v1 diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index 071028f..7f75782 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -59,6 +59,7 @@ runs: app_id: ${{ inputs.app_id }} private_key: ${{ inputs.app_private_key }} ref: ${{ inputs.ref }} + submodules: true - name: Setup Ruby uses: ruby/setup-ruby@v1 From ff75009d895f36446b8217d191f017d69820b69f Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 16 Jun 2025 11:47:30 -0600 Subject: [PATCH 14/34] can't use pattern with merge-multiple --- ruby/publish/action.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index 7f75782..798d627 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -84,7 +84,6 @@ runs: - name: Fetch the gem artifacts uses: actions/download-artifact@v4 with: - pattern: '*.gem' merge-multiple: true - name: Sign the gems From 1eb56ea145d4b08c25d15477ff74de9c6b565216 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 16 Jun 2025 13:46:00 -0600 Subject: [PATCH 15/34] use `cat`, not `echo`, when writing a heredoc to a file --- ruby/publish/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index 798d627..5abc680 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -134,7 +134,7 @@ runs: - name: Write release notes to file shell: bash run: | - echo <<'__RELEASE_NOTES_IKDJAIELD__' > release_notes.txt + cat <<'__RELEASE_NOTES_IKDJAIELD__' > release_notes.txt ${{ inputs.release_message }} __RELEASE_NOTES_IKDJAIELD__ From 3178251053da37cfecca286367635484aa1154d3 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Tue, 17 Jun 2025 10:57:10 -0600 Subject: [PATCH 16/34] build using a rake task, to accommodate gems that need a compile step --- ruby/build/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/build/action.yml b/ruby/build/action.yml index 9a7712f..9c8f51a 100644 --- a/ruby/build/action.yml +++ b/ruby/build/action.yml @@ -62,7 +62,7 @@ runs: - name: Build the gem shell: bash run: | - gem build --output=${{ steps.gem_name.outputs.name }} ${{ inputs.gem_name }}.gemspec + bundle exec rake build GEMSPEC="${{ inputs.gem_name }}.gemspec" GEM_FILE_NAME="${{ steps.gem_name.outputs.name }}" - name: Save the generated gem file for later uses: actions/upload-artifact@v4 From 2752ec67c0f700809f4c145bb4a36c0c5eda7d60 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 08:41:21 -0600 Subject: [PATCH 17/34] pr-check action only works with push & workflow_dispatch --- ruby/pr-check/action.yml | 86 ++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index d41e14b..5c2f89e 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -1,3 +1,12 @@ +# PRs are only eligible for release if they are merged and have +# the `release-candidate` label. +# +# The only events allowed to trigger this action are: +# - push (in which case the commit sha is used to find the corresponding +# PR) +# - workflow_dispatch (in which case the PR is found from the inputs +# on the event) + name: PR Check description: Check that a PR is eligible for release @@ -19,53 +28,78 @@ runs: script: | let pr; - // if the event is a pull request, then we don't need to check - // the actors permissions, because they'll have had permissions - // to merge the PR in the first place. - if (context.payload.pull_request) { - pr = context.payload.pull_request; - - // if the event is a comment, then we need to check that the - // comment is in the correct format, and that the user has - // acceptible access to the repository. - } else if (context.issue) { - const comment = context.payload.comment; - - // first, is the message in the correct format? - const body = comment.body.trim(); - if (body != '/release') { - throw new Error('Command not detected in comment body.'); + // was this triggered by a push event? + if (context.payload.push) { + // if so, we need to find the PR that corresponds to the commit + // that was pushed. + // + // because only maintainers can push to protected branches, + // we can assume the user has the correct permissions to do + // this. + const { data: results } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'all', + head: `${context.repo.owner}:${context.payload.ref}`, + }); + + if (results.length == 0) { + throw new Error(`Workflow aborted: No pull request found for the pushed commit (${context.payload.ref}).`); } - // if the event is an issue comment, we need to check the - // comment author has necessary access to the repository, - // before we let them proceed. - const username = comment.user.login; - const { data: results } = await github.rest.repos.getCollaboratorPermissionLevel({ + pr = results[0]; + + // if it wasn't triggered by a push event, was it triggered by + // a workflow_dispatch event? + } else if (context.payload.workflow_dispatch) { + // it is technically possible for users with only write access + // to trigger workflows; we need to make sure that the user + // who triggered this has either admin or maintain access to the + // repository. + const username = context.triggering_actor || context.actor; + + const { data: perms } = await github.rest.repos.getCollaboratorPermissionLevel({ owner: context.repo.owner, repo: context.repo.repo, username, }); - if (results.role_name !== 'admin' && results.role_name !== 'maintain') { - throw new Error(`User ${username} must have 'admin' or 'maintain' role to initiate the release process.`); + if (perms.role_name !== 'admin' && perms.role_name !== 'maintain') { + throw new Error(`User ${username} must have 'admin' or 'maintain' role to initiate the release process. (${perms.role_name})`); + } + + // if so, we grab the PR with the number that was passed in with + // the inputs. + const number = context.payload.inputs.pr; + if (!number) { + throw new Error('Workflow aborted: No pull request number provided. (need `pr` input)'); } - const result = await github.rest.pulls.get({ + const { data: prs } = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, - pull_number: context.issue.number, + pull_number: number, }); - pr = result.data + if (prs.length == 0) { + throw new Error(`Workflow aborted: No pull request found with the requested number. (${number})`); + } + + pr = prs[0]; + + // workflow was triggered by an unrecognized/unsupported event + } else { + throw new Error('Workflow aborted: Unsupported event type.'); } if (!pr) { throw new Error('No pull request found for the triggered event.'); } + if (!pr.merged) { throw new Error('Pull request is not merged.'); } + if (!pr.labels.some(label => label.name == 'release-candidate')) { throw new Error('Pull request is not a release candidate.'); } From f89b3ee05b81880443d3eefd51e76716256c6c34 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 09:45:16 -0600 Subject: [PATCH 18/34] some debugging output to help troubleshooting --- ruby/pr-check/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 5c2f89e..b719ee1 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -89,6 +89,7 @@ runs: // workflow was triggered by an unrecognized/unsupported event } else { + console.log('payload keys:', Object.keys(context.payload)); throw new Error('Workflow aborted: Unsupported event type.'); } From cccd2b1edc26e78ebc98f1b9259a3b1001ca0aa4 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 09:50:17 -0600 Subject: [PATCH 19/34] a bit more debug output --- ruby/pr-check/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index b719ee1..48e2f77 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -28,6 +28,8 @@ runs: script: | let pr; + console.log('context keys:', Object.keys(context)); + // was this triggered by a push event? if (context.payload.push) { // if so, we need to find the PR that corresponds to the commit From d35fd277a1c78fe0192492904c9251fae73547d2 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 09:53:06 -0600 Subject: [PATCH 20/34] okay, possibly checking the right things now --- ruby/pr-check/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 48e2f77..5456f1e 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -31,7 +31,7 @@ runs: console.log('context keys:', Object.keys(context)); // was this triggered by a push event? - if (context.payload.push) { + if (context.eventName == 'push') { // if so, we need to find the PR that corresponds to the commit // that was pushed. // @@ -53,7 +53,7 @@ runs: // if it wasn't triggered by a push event, was it triggered by // a workflow_dispatch event? - } else if (context.payload.workflow_dispatch) { + } else if (context.eventName == 'workflow_dispatch') { // it is technically possible for users with only write access // to trigger workflows; we need to make sure that the user // who triggered this has either admin or maintain access to the From 5e584254030e4528a83d0ead44c50a256c58ece9 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 09:59:37 -0600 Subject: [PATCH 21/34] try again --- ruby/pr-check/action.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 5456f1e..4e2cece 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -38,15 +38,14 @@ runs: // because only maintainers can push to protected branches, // we can assume the user has the correct permissions to do // this. - const { data: results } = await github.rest.pulls.list({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'all', - head: `${context.repo.owner}:${context.payload.ref}`, + const { data: results } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ + context.repo.owner, + context.repo.repo, + context.payload.after, }); if (results.length == 0) { - throw new Error(`Workflow aborted: No pull request found for the pushed commit (${context.payload.ref}).`); + throw new Error(`Workflow aborted: No pull request found for the pushed commit (${context.payload.after}).`); } pr = results[0]; From 85472de4d7e0744816371b71804f4fd4dce2232f Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 10:02:17 -0600 Subject: [PATCH 22/34] fix syntax error --- ruby/pr-check/action.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 4e2cece..d399fac 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -39,9 +39,9 @@ runs: // we can assume the user has the correct permissions to do // this. const { data: results } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ - context.repo.owner, - context.repo.repo, - context.payload.after, + owner: context.repo.owner, + repo: context.repo.repo, + commit_sha: context.payload.after, }); if (results.length == 0) { From 7c3926f92a8b3c2b55af5544d1503b2cffcbee68 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 10:13:43 -0600 Subject: [PATCH 23/34] more debugging --- ruby/pr-check/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index d399fac..f2885f8 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -94,6 +94,8 @@ runs: throw new Error('Workflow aborted: Unsupported event type.'); } + console.log('pr:', pr); + if (!pr) { throw new Error('No pull request found for the triggered event.'); } From 10239c3069bd1945f49eb41ea2d323cd45b0cdef Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 10:16:42 -0600 Subject: [PATCH 24/34] need to get the actual PR record once we know its number --- ruby/pr-check/action.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index f2885f8..6cbebe3 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -38,17 +38,27 @@ runs: // because only maintainers can push to protected branches, // we can assume the user has the correct permissions to do // this. - const { data: results } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ + const { data: listing } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ owner: context.repo.owner, repo: context.repo.repo, commit_sha: context.payload.after, }); - if (results.length == 0) { + if (listing.length == 0) { throw new Error(`Workflow aborted: No pull request found for the pushed commit (${context.payload.after}).`); } - pr = results[0]; + const { data: prs } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: listing[0].number, + }); + + if (prs.length == 0) { + throw new Error(`Workflow aborted: No pull request found with the requested number. (${number})`); + } + + pr = prs[0]; // if it wasn't triggered by a push event, was it triggered by // a workflow_dispatch event? From 339da5f4c0842b791bd49ca3d221fa72fab1e8f1 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 10:20:00 -0600 Subject: [PATCH 25/34] pulls/get doesn't return a list --- ruby/pr-check/action.yml | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 6cbebe3..4a3b836 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -48,18 +48,12 @@ runs: throw new Error(`Workflow aborted: No pull request found for the pushed commit (${context.payload.after}).`); } - const { data: prs } = await github.rest.pulls.get({ + pr = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: listing[0].number, }); - if (prs.length == 0) { - throw new Error(`Workflow aborted: No pull request found with the requested number. (${number})`); - } - - pr = prs[0]; - // if it wasn't triggered by a push event, was it triggered by // a workflow_dispatch event? } else if (context.eventName == 'workflow_dispatch') { @@ -86,18 +80,12 @@ runs: throw new Error('Workflow aborted: No pull request number provided. (need `pr` input)'); } - const { data: prs } = await github.rest.pulls.get({ + pr = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: number, }); - if (prs.length == 0) { - throw new Error(`Workflow aborted: No pull request found with the requested number. (${number})`); - } - - pr = prs[0]; - // workflow was triggered by an unrecognized/unsupported event } else { console.log('payload keys:', Object.keys(context.payload)); From 7c38a002d0b0b0530e1eba142b8f82530631d7e7 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 10:22:24 -0600 Subject: [PATCH 26/34] it's not a list, but it's still wrapped --- ruby/pr-check/action.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 4a3b836..476b2bc 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -48,12 +48,14 @@ runs: throw new Error(`Workflow aborted: No pull request found for the pushed commit (${context.payload.after}).`); } - pr = await github.rest.pulls.get({ + const response = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: listing[0].number, }); + pr = response.data; + // if it wasn't triggered by a push event, was it triggered by // a workflow_dispatch event? } else if (context.eventName == 'workflow_dispatch') { @@ -80,12 +82,14 @@ runs: throw new Error('Workflow aborted: No pull request number provided. (need `pr` input)'); } - pr = await github.rest.pulls.get({ + const response = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: number, }); + pr = response.data; + // workflow was triggered by an unrecognized/unsupported event } else { console.log('payload keys:', Object.keys(context.payload)); From 6da6fb7e1a6ee029e4d731e17ea6d579ed8e5d19 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 19 Jun 2025 10:25:53 -0600 Subject: [PATCH 27/34] remove debugging output --- ruby/pr-check/action.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 476b2bc..7fead78 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -28,8 +28,6 @@ runs: script: | let pr; - console.log('context keys:', Object.keys(context)); - // was this triggered by a push event? if (context.eventName == 'push') { // if so, we need to find the PR that corresponds to the commit @@ -92,12 +90,9 @@ runs: // workflow was triggered by an unrecognized/unsupported event } else { - console.log('payload keys:', Object.keys(context.payload)); - throw new Error('Workflow aborted: Unsupported event type.'); + throw new Error(`Workflow aborted: Unsupported event type: ${context.eventName}.`); } - console.log('pr:', pr); - if (!pr) { throw new Error('No pull request found for the triggered event.'); } From 3eece64ab829759900d02856fee960964fe04bd6 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 24 Jul 2025 11:59:31 -0600 Subject: [PATCH 28/34] remove trailing whitespace --- ruby/pr-check/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 7fead78..90b882f 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -72,7 +72,7 @@ runs: if (perms.role_name !== 'admin' && perms.role_name !== 'maintain') { throw new Error(`User ${username} must have 'admin' or 'maintain' role to initiate the release process. (${perms.role_name})`); } - + // if so, we grab the PR with the number that was passed in with // the inputs. const number = context.payload.inputs.pr; From e8adfe6c177fd9925712cca3be10f2095f822d22 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 24 Jul 2025 12:04:51 -0600 Subject: [PATCH 29/34] pin to specific commit --- ruby/build/action.yml | 2 +- ruby/cleanup/action.yml | 2 +- ruby/publish/action.yml | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ruby/build/action.yml b/ruby/build/action.yml index 9c8f51a..0558086 100644 --- a/ruby/build/action.yml +++ b/ruby/build/action.yml @@ -34,7 +34,7 @@ runs: using: composite steps: - name: Check out the repository - uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 + uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909 with: app_id: ${{ inputs.app_id }} private_key: ${{ inputs.app_private_key }} diff --git a/ruby/cleanup/action.yml b/ruby/cleanup/action.yml index 1f144a1..7788230 100644 --- a/ruby/cleanup/action.yml +++ b/ruby/cleanup/action.yml @@ -15,7 +15,7 @@ runs: using: composite steps: - name: 'Check out the repository' - uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 + uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909 with: app_id: ${{ inputs.app_id }} private_key: ${{ inputs.app_private_key }} diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index 5abc680..740dc1d 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -54,7 +54,7 @@ runs: using: composite steps: - name: Check out the repository - uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 + uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909 with: app_id: ${{ inputs.app_id }} private_key: ${{ inputs.app_private_key }} @@ -75,7 +75,7 @@ runs: run: echo "version=$(bundle exec rake version)" >> "$GITHUB_OUTPUT" - name: Setup GitHub tooling for DBX Drivers - uses: mongodb-labs/drivers-github-tools/setup@v2 + uses: mongodb-labs/drivers-github-tools/setup@58501b85eae697e451b5d1d7dba53f69f65d1909 with: aws_role_arn: ${{ inputs.aws_role_arn }} aws_region_name: ${{ inputs.aws_region_name }} @@ -87,12 +87,12 @@ runs: merge-multiple: true - name: Sign the gems - uses: mongodb-labs/drivers-github-tools/gpg-sign@v2 + uses: mongodb-labs/drivers-github-tools/gpg-sign@58501b85eae697e451b5d1d7dba53f69f65d1909 with: filenames: '*.gem' - name: Generate SSDLC Reports - uses: mongodb-labs/drivers-github-tools/full-report@v2 + uses: mongodb-labs/drivers-github-tools/full-report@58501b85eae697e451b5d1d7dba53f69f65d1909 with: product_name: ${{ inputs.product_name }} release_version: ${{ steps.release_version.outputs.version }} @@ -112,7 +112,7 @@ runs: fi - name: Create the tag - uses: mongodb-labs/drivers-github-tools/tag-version@v2 + uses: mongodb-labs/drivers-github-tools/tag-version@58501b85eae697e451b5d1d7dba53f69f65d1909 if: steps.tag_exists.outputs.exists == 'false' with: version: ${{ steps.release_version.outputs.version }} @@ -153,7 +153,7 @@ runs: run: gh release upload --clobber v${{ steps.release_version.outputs.version }} *.gem ${{ env.RELEASE_ASSETS }}/*.sig - name: Upload S3 assets - uses: mongodb-labs/drivers-github-tools/upload-s3-assets@v2 + uses: mongodb-labs/drivers-github-tools/upload-s3-assets@58501b85eae697e451b5d1d7dba53f69f65d1909 with: version: ${{ steps.release_version.outputs.version }} product_name: ${{ inputs.product_id }} From 29475879ab015f177ce7359546696c1f14797923 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 24 Jul 2025 12:12:02 -0600 Subject: [PATCH 30/34] pin all action references --- ruby/build/action.yml | 4 ++-- ruby/pr-check/action.yml | 2 +- ruby/publish/action.yml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ruby/build/action.yml b/ruby/build/action.yml index 0558086..e6132d0 100644 --- a/ruby/build/action.yml +++ b/ruby/build/action.yml @@ -42,7 +42,7 @@ runs: submodules: true - name: Setup Ruby - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 with: ruby-version: ${{ inputs.ruby_version }} rubygems: ${{ inputs.rubygems_version }} @@ -65,7 +65,7 @@ runs: bundle exec rake build GEMSPEC="${{ inputs.gem_name }}.gemspec" GEM_FILE_NAME="${{ steps.gem_name.outputs.name }}" - name: Save the generated gem file for later - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: ${{ inputs.artifact }} path: ${{ steps.gem_name.outputs.name }} diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index 90b882f..cfc1844 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -23,7 +23,7 @@ runs: steps: - name: "Check PR Eligibility" id: check_pr - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea with: script: | let pr; diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index 740dc1d..269cf7a 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -62,7 +62,7 @@ runs: submodules: true - name: Setup Ruby - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 with: ruby-version: ${{ inputs.ruby_version }} rubygems: ${{ inputs.rubygems_version }} @@ -82,7 +82,7 @@ runs: aws_secret_id: ${{ inputs.aws_secret_id }} - name: Fetch the gem artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: merge-multiple: true @@ -172,7 +172,7 @@ runs: fi - name: Publish the gem - uses: rubygems/release-gem@v1 + uses: rubygems/release-gem@ebe1ec66bd8d2c709ac29aa2b43438d450e7a0a6 if: inputs.dry_run == 'false' && steps.gem_exists.outputs.exists == 'false' with: await-release: false From 83826e78c6ee800e797ab456efd3c7c1a027799a Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 24 Jul 2025 12:26:12 -0600 Subject: [PATCH 31/34] avoid potential template injection exploits --- ruby/build/action.yml | 11 ++++++++-- ruby/publish/action.yml | 46 ++++++++++++++++++++++++++++------------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/ruby/build/action.yml b/ruby/build/action.yml index e6132d0..ee9c074 100644 --- a/ruby/build/action.yml +++ b/ruby/build/action.yml @@ -57,12 +57,19 @@ runs: - name: Get the gem file name shell: bash id: gem_name - run: echo "name=$(ruby ${{ github.action_path }}/gem_name.rb ${{ inputs.gem_name }} ${{ steps.release_version.outputs.version }})" >> "$GITHUB_OUTPUT" + env: + GEM_NAME: ${{ inputs.gem_name }} + ACTION_PATH: ${{ github.action_path }} + RELEASE_VERSION: ${{ steps.release_version.outputs.version }} + run: echo "name=$(ruby ${ACTION_PATH}/gem_name.rb ${GEM_NAME} ${RELEASE_VERSION})" >> "$GITHUB_OUTPUT" - name: Build the gem shell: bash + env: + GEM_NAME: ${{ inputs.gem_name }} + GEM_FILE_NAME: ${{ steps.gem_name.outputs.name }} run: | - bundle exec rake build GEMSPEC="${{ inputs.gem_name }}.gemspec" GEM_FILE_NAME="${{ steps.gem_name.outputs.name }}" + bundle exec rake build GEMSPEC="${GEM_NAME}.gemspec" GEM_FILE_NAME="${GEM_FILE_NAME}" - name: Save the generated gem file for later uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index 269cf7a..b05552b 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -102,12 +102,14 @@ runs: - name: Look for existing tag id: tag_exists shell: bash + env: + RELEASE_VERSION: ${{ steps.release_version.outputs.version }} run: | - if git rev-parse "v${{ steps.release_version.outputs.version }}" >/dev/null 2>&1; then - echo "Tag v${{ steps.release_version.outputs.version }} already exists." + if git rev-parse "v${RELEASE_VERSION}" >/dev/null 2>&1; then + echo "Tag v${RELEASE_VERSION} already exists." echo "exists=true" >> "$GITHUB_OUTPUT" else - echo "Tag v${{ steps.release_version.outputs.version }} does not exist." + echo "Tag v${RELEASE_VERSION} does not exist." echo "exists=false" >> "$GITHUB_OUTPUT" fi @@ -122,35 +124,46 @@ runs: - name: Look for existing release id: release_exists shell: bash + env: + RELEASE_VERSION: ${{ steps.release_version.outputs.version }} run: | - if gh release view "v${{ steps.release_version.outputs.version }}" >/dev/null 2>&1; then - echo "Release v${{ steps.release_version.outputs.version }} already exists." + if gh release view "v${RELEASE_VERSION}" >/dev/null 2>&1; then + echo "Release v${RELEASE_VERSION} already exists." echo "exists=true" >> "$GITHUB_OUTPUT" else - echo "Release v${{ steps.release_version.outputs.version }} does not exist." + echo "Release v${RELEASE_VERSION} does not exist." echo "exists=false" >> "$GITHUB_OUTPUT" fi - name: Write release notes to file shell: bash + env: + RELEASE_NOTES: ${{ inputs.release_message }} run: | cat <<'__RELEASE_NOTES_IKDJAIELD__' > release_notes.txt - ${{ inputs.release_message }} + ${RELEASE_NOTES} __RELEASE_NOTES_IKDJAIELD__ - name: Create a new release if: steps.release_exists.outputs.exists == 'false' shell: bash - run: gh release create v${{ steps.release_version.outputs.version }} --title ${{ steps.release_version.outputs.version }} --notes-file release_notes.txt --draft + env: + RELEASE_VERSION: ${{ steps.release_version.outputs.version }} + run: gh release create v${RELEASE_VERSION} --title ${RELEASE_VERSION} --notes-file release_notes.txt --draft - name: Else update the existing release if: steps.release_exists.outputs.exists == 'true' shell: bash - run: gh release edit v${{ steps.release_version.outputs.version }} --notes-file release_notes.txt + env: + RELEASE_VERSION: ${{ steps.release_version.outputs.version }} + run: gh release edit v${RELEASE_VERSION} --notes-file release_notes.txt - name: Upload release artifacts shell: bash - run: gh release upload --clobber v${{ steps.release_version.outputs.version }} *.gem ${{ env.RELEASE_ASSETS }}/*.sig + env: + RELEASE_VERSION: ${{ steps.release_version.outputs.version }} + RELEASE_ASSETS: ${{ env.RELEASE_ASSETS }} + run: gh release upload --clobber v${RELEASE_VERSION} *.gem ${RELEASE_ASSETS}/*.sig - name: Upload S3 assets uses: mongodb-labs/drivers-github-tools/upload-s3-assets@58501b85eae697e451b5d1d7dba53f69f65d1909 @@ -162,12 +175,15 @@ runs: - name: Look for existing gem id: gem_exists shell: bash + env: + GEM_NAME: ${{ inputs.gem_name }} + RELEASE_VERSION: ${{ steps.release_version.outputs.version }} run: | - if gem search --remote ${{ inputs.gem_name }} --version ${{ steps.release_version.outputs.version }} | grep -q "${{ steps.release_version.outputs.version }}"; then - echo "Gem ${{ inputs.gem_name }} version ${{ steps.release_version.outputs.version }} already exists." + if gem search --remote ${GEM_NAME} --version ${RELEASE_VERSION} | grep -q "${RELEASE_VERSION}"; then + echo "Gem ${GEM_NAME} version ${RELEASE_VERSION} already exists." echo "exists=true" >> "$GITHUB_OUTPUT" else - echo "Gem ${{ inputs.gem_name }} version ${{ steps.release_version.outputs.version }} does not exist." + echo "Gem ${GEM_NAME} version ${RELEASE_VERSION} does not exist." echo "exists=false" >> "$GITHUB_OUTPUT" fi @@ -180,5 +196,7 @@ runs: - name: Publish the release if: inputs.dry_run == 'false' shell: bash - run: gh release edit v${{ steps.release_version.outputs.version }} --draft=false + env: + RELEASE_VERSION: ${{ steps.release_version.outputs.version }} + run: gh release edit v${RELEASE_VERSION} --draft=false From d6817056897bbc7c574ea84b0328014579cb2cc2 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Thu, 24 Jul 2025 12:28:46 -0600 Subject: [PATCH 32/34] trailing whitespace --- ruby/publish/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index b05552b..e0fd44c 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -137,7 +137,7 @@ runs: - name: Write release notes to file shell: bash - env: + env: RELEASE_NOTES: ${{ inputs.release_message }} run: | cat <<'__RELEASE_NOTES_IKDJAIELD__' > release_notes.txt From a385189376ea1a65ecb39b2a5770d2d819a453de Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 28 Jul 2025 08:34:11 -0600 Subject: [PATCH 33/34] Add a comment to explain the obscure identifier --- ruby/publish/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index e0fd44c..d0362b4 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -140,6 +140,8 @@ runs: env: RELEASE_NOTES: ${{ inputs.release_message }} run: | + # identifier is intentionally obscure to avoid potential conflicts + # with supplied text from the release notes themselves. cat <<'__RELEASE_NOTES_IKDJAIELD__' > release_notes.txt ${RELEASE_NOTES} __RELEASE_NOTES_IKDJAIELD__ From e3849252bcfaa9c5bdacdf09d2963ac6e820ef21 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Mon, 28 Jul 2025 08:43:23 -0600 Subject: [PATCH 34/34] document each commit SHA --- ruby/build/action.yml | 3 +++ ruby/cleanup/action.yml | 1 + ruby/pr-check/action.yml | 1 + ruby/publish/action.yml | 11 ++++++++++- 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ruby/build/action.yml b/ruby/build/action.yml index ee9c074..5619680 100644 --- a/ruby/build/action.yml +++ b/ruby/build/action.yml @@ -34,6 +34,7 @@ runs: using: composite steps: - name: Check out the repository + # 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28 uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909 with: app_id: ${{ inputs.app_id }} @@ -42,6 +43,7 @@ runs: submodules: true - name: Setup Ruby + # bb6434c747fa7022e12fa1cae2a0951fcffcff26 => the 'v1' branch as of 2025-07-28 uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 with: ruby-version: ${{ inputs.ruby_version }} @@ -72,6 +74,7 @@ runs: bundle exec rake build GEMSPEC="${GEM_NAME}.gemspec" GEM_FILE_NAME="${GEM_FILE_NAME}" - name: Save the generated gem file for later + # ea165f8d65b6e75b540449e92b4886f43607fa02 => the 'v4' tag as of 2025-07-28 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: ${{ inputs.artifact }} diff --git a/ruby/cleanup/action.yml b/ruby/cleanup/action.yml index 7788230..1f98cab 100644 --- a/ruby/cleanup/action.yml +++ b/ruby/cleanup/action.yml @@ -15,6 +15,7 @@ runs: using: composite steps: - name: 'Check out the repository' + # 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28 uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909 with: app_id: ${{ inputs.app_id }} diff --git a/ruby/pr-check/action.yml b/ruby/pr-check/action.yml index cfc1844..e43308d 100644 --- a/ruby/pr-check/action.yml +++ b/ruby/pr-check/action.yml @@ -23,6 +23,7 @@ runs: steps: - name: "Check PR Eligibility" id: check_pr + # 60a0d83039c74a4aee543508d2ffcb1c3799cdea => 'v7' tag as of 2025-07-28 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea with: script: | diff --git a/ruby/publish/action.yml b/ruby/publish/action.yml index d0362b4..d3ad53d 100644 --- a/ruby/publish/action.yml +++ b/ruby/publish/action.yml @@ -54,6 +54,7 @@ runs: using: composite steps: - name: Check out the repository + # 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28 uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909 with: app_id: ${{ inputs.app_id }} @@ -62,7 +63,8 @@ runs: submodules: true - name: Setup Ruby - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 + # bb6434c747fa7022e12fa1cae2a0951fcffcff26 => the 'v1' branch as of 2025-07-28 + uses: ruby/setup-ruby@bb6434c747fa7022e12fa1cae2a0951fcffcff26 with: ruby-version: ${{ inputs.ruby_version }} rubygems: ${{ inputs.rubygems_version }} @@ -75,6 +77,7 @@ runs: run: echo "version=$(bundle exec rake version)" >> "$GITHUB_OUTPUT" - name: Setup GitHub tooling for DBX Drivers + # 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28 uses: mongodb-labs/drivers-github-tools/setup@58501b85eae697e451b5d1d7dba53f69f65d1909 with: aws_role_arn: ${{ inputs.aws_role_arn }} @@ -82,16 +85,19 @@ runs: aws_secret_id: ${{ inputs.aws_secret_id }} - name: Fetch the gem artifacts + # d3f86a106a0bac45b974a628896c90dbdf5c8093 => the 'v4' tag as of 2025-07-28 uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: merge-multiple: true - name: Sign the gems + # 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28 uses: mongodb-labs/drivers-github-tools/gpg-sign@58501b85eae697e451b5d1d7dba53f69f65d1909 with: filenames: '*.gem' - name: Generate SSDLC Reports + # 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28 uses: mongodb-labs/drivers-github-tools/full-report@58501b85eae697e451b5d1d7dba53f69f65d1909 with: product_name: ${{ inputs.product_name }} @@ -114,6 +120,7 @@ runs: fi - name: Create the tag + # 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28 uses: mongodb-labs/drivers-github-tools/tag-version@58501b85eae697e451b5d1d7dba53f69f65d1909 if: steps.tag_exists.outputs.exists == 'false' with: @@ -168,6 +175,7 @@ runs: run: gh release upload --clobber v${RELEASE_VERSION} *.gem ${RELEASE_ASSETS}/*.sig - name: Upload S3 assets + # 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28 uses: mongodb-labs/drivers-github-tools/upload-s3-assets@58501b85eae697e451b5d1d7dba53f69f65d1909 with: version: ${{ steps.release_version.outputs.version }} @@ -190,6 +198,7 @@ runs: fi - name: Publish the gem + # ebe1ec66bd8d2c709ac29aa2b43438d450e7a0a6 => the 'v1' branch as of 2025-07-28 uses: rubygems/release-gem@ebe1ec66bd8d2c709ac29aa2b43438d450e7a0a6 if: inputs.dry_run == 'false' && steps.gem_exists.outputs.exists == 'false' with: