Skip to content

Updates to DBX Ruby release process #86

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
85e5dcf
pass release notes to publish action, and make it idempotent
jamis Jun 6, 2025
3e526e9
split build & publish
jamis Jun 9, 2025
84b5369
add PR-check action
jamis Jun 12, 2025
040fd64
add some debugging for troubleshooting
jamis Jun 13, 2025
fde9f93
more debugging
jamis Jun 13, 2025
d0e0dec
typo
jamis Jun 13, 2025
066352c
add `ref` input parameter
jamis Jun 16, 2025
057146a
permit write access to publish as well
jamis Jun 16, 2025
023a472
troubleshooting: show the permissions of the current user
jamis Jun 16, 2025
73e3905
fix indentation
jamis Jun 16, 2025
bdbbe4d
use role_name instead of permissions
jamis Jun 16, 2025
96dfd86
wrong quotes
jamis Jun 16, 2025
fb201ad
checkout submodules -- so the candidate.rake tasks can load
jamis Jun 16, 2025
ff75009
can't use pattern with merge-multiple
jamis Jun 16, 2025
1eb56ea
use `cat`, not `echo`, when writing a heredoc to a file
jamis Jun 16, 2025
3178251
build using a rake task, to accommodate gems that need a compile step
jamis Jun 17, 2025
2752ec6
pr-check action only works with push & workflow_dispatch
jamis Jun 19, 2025
f89b3ee
some debugging output to help troubleshooting
jamis Jun 19, 2025
cccd2b1
a bit more debug output
jamis Jun 19, 2025
d35fd27
okay, possibly checking the right things now
jamis Jun 19, 2025
5e58425
try again
jamis Jun 19, 2025
85472de
fix syntax error
jamis Jun 19, 2025
7c3926f
more debugging
jamis Jun 19, 2025
10239c3
need to get the actual PR record once we know its number
jamis Jun 19, 2025
339da5f
pulls/get doesn't return a list
jamis Jun 19, 2025
7c38a00
it's not a list, but it's still wrapped
jamis Jun 19, 2025
6da6fb7
remove debugging output
jamis Jun 19, 2025
e74b084
Merge branch 'main' into ruby-3643-update-release-process
jamis Jul 24, 2025
3eece64
remove trailing whitespace
jamis Jul 24, 2025
e8adfe6
pin to specific commit
jamis Jul 24, 2025
2947587
pin all action references
jamis Jul 24, 2025
83826e7
avoid potential template injection exploits
jamis Jul 24, 2025
d681705
trailing whitespace
jamis Jul 24, 2025
a385189
Add a comment to explain the obscure identifier
jamis Jul 28, 2025
e384925
document each commit SHA
jamis Jul 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions ruby/build/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
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
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'
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
# 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28
uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and in other places: it might be helpful to add a comment indicating what this is pointing to, either a tag or a specific commit that introduces certain functionality.

As an aside for @blink1073: I'd like to figure out a solution for using actions from this repository in other actions. Currently, if I were to introduce two actions here with one using another, there is no way to reference that action in a commit hash or tag before the PR introducing the actions is merged, necessitating a second PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments. I can understand why we want to document those references, but it really feels like there has got to be a better way. A textual description for a commit SHA is a pretty brittle reference. Would a pre-processor be useful for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been using this approach and then changing back to a version tag before merging. I had tried and failed to use relative paths outside of the GitHub Action directory.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll hold off on merging #84 until this is approved, then we can merge both and cut the v3 tag

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried a few different approaches, but all resulted in either an error or the workflow not running. Looking at https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax#runsstepsuses, you can use another action in your OWN repository, but not it the separate repo's repository. We're stuck with either having a single repo per action (no thanks), or using the current branch as the target for testing and then reverting back to the version tag before merging.

with:
app_id: ${{ inputs.app_id }}
private_key: ${{ inputs.app_private_key }}
ref: ${{ inputs.ref }}
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 }}
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
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="${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 }}
path: ${{ steps.gem_name.outputs.name }}
retention-days: 1
overwrite: true
21 changes: 21 additions & 0 deletions ruby/build/gem_name.rb
Original file line number Diff line number Diff line change
@@ -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 <gem_name> <gem_version>

if ARGV.length != 2
puts "Usage: ruby gem_name.rb <gem_name> <gem_version>"
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"
3 changes: 2 additions & 1 deletion ruby/cleanup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ runs:
using: composite
steps:
- name: 'Check out the repository'
uses: mongodb-labs/drivers-github-tools/secure-checkout@v2
# 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28
uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909
with:
app_id: ${{ inputs.app_id }}
private_key: ${{ inputs.app_private_key }}
Expand Down
113 changes: 113 additions & 0 deletions ruby/pr-check/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# 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

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
# 60a0d83039c74a4aee543508d2ffcb1c3799cdea => 'v7' tag as of 2025-07-28
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL this exists - interesting!

with:
script: |
let pr;

// was this triggered by a push event?
if (context.eventName == '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: listing } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.payload.after,
});

if (listing.length == 0) {
throw new Error(`Workflow aborted: No pull request found for the pushed commit (${context.payload.after}).`);
}

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') {
// 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 (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 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 {
throw new Error(`Workflow aborted: Unsupported event type: ${context.eventName}.`);
}

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.');
}

console.log('body: >>', pr.body, '<<');
console.log('ref: >>', pr.merge_commit_sha, '<<');

core.setOutput('message', pr.body);
core.setOutput('ref', pr.merge_commit_sha);
Loading
Loading