Skip to content

Commit 0eb77c2

Browse files
authored
Updates to DBX Ruby release process (#86)
1 parent e5bd985 commit 0eb77c2

File tree

5 files changed

+336
-43
lines changed

5 files changed

+336
-43
lines changed

ruby/build/action.yml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: Build Gem
2+
description: Build a gem for a DBX Ruby project
3+
inputs:
4+
app_id:
5+
description: The APP_ID defined for this project
6+
required: true
7+
app_private_key:
8+
description: The APP_PRIVATE_KEY defined for this project
9+
required: true
10+
artifact:
11+
description: The name to give the generated artifact (e.g. "ruby" or "jruby")
12+
required: false
13+
default: ruby
14+
bundler_cache_version:
15+
description: The cache-version to use for the bundler cache
16+
required: false
17+
default: '0'
18+
gem_name:
19+
description: The name (sans extension) of the gemspec file (e.g. "mongo")
20+
required: true
21+
ref:
22+
description: The reference to checkout (branch, tag, sha, etc)
23+
required: true
24+
ruby_version:
25+
description: The version of Ruby to use (see setup-ruby/action.yml)
26+
default: '3.2'
27+
required: false
28+
rubygems_version:
29+
description: The version of Rubygems to use (see setup-ruby/action.yml)
30+
required: false
31+
default: latest
32+
33+
runs:
34+
using: composite
35+
steps:
36+
- name: Check out the repository
37+
# 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28
38+
uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909
39+
with:
40+
app_id: ${{ inputs.app_id }}
41+
private_key: ${{ inputs.app_private_key }}
42+
ref: ${{ inputs.ref }}
43+
submodules: true
44+
45+
- name: Setup Ruby
46+
# bb6434c747fa7022e12fa1cae2a0951fcffcff26 => the 'v1' branch as of 2025-07-28
47+
uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990
48+
with:
49+
ruby-version: ${{ inputs.ruby_version }}
50+
rubygems: ${{ inputs.rubygems_version }}
51+
bundler-cache: true
52+
cache-version: ${{ inputs.bundler_cache_version }}
53+
54+
- name: Get the release version
55+
id: release_version
56+
shell: bash
57+
run: echo "version=$(bundle exec rake version)" >> "$GITHUB_OUTPUT"
58+
59+
- name: Get the gem file name
60+
shell: bash
61+
id: gem_name
62+
env:
63+
GEM_NAME: ${{ inputs.gem_name }}
64+
ACTION_PATH: ${{ github.action_path }}
65+
RELEASE_VERSION: ${{ steps.release_version.outputs.version }}
66+
run: echo "name=$(ruby ${ACTION_PATH}/gem_name.rb ${GEM_NAME} ${RELEASE_VERSION})" >> "$GITHUB_OUTPUT"
67+
68+
- name: Build the gem
69+
shell: bash
70+
env:
71+
GEM_NAME: ${{ inputs.gem_name }}
72+
GEM_FILE_NAME: ${{ steps.gem_name.outputs.name }}
73+
run: |
74+
bundle exec rake build GEMSPEC="${GEM_NAME}.gemspec" GEM_FILE_NAME="${GEM_FILE_NAME}"
75+
76+
- name: Save the generated gem file for later
77+
# ea165f8d65b6e75b540449e92b4886f43607fa02 => the 'v4' tag as of 2025-07-28
78+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
79+
with:
80+
name: ${{ inputs.artifact }}
81+
path: ${{ steps.gem_name.outputs.name }}
82+
retention-days: 1
83+
overwrite: true

ruby/build/gem_name.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# frozen_string_literal: true
2+
3+
# This script generates the name of a gem file based on the provided
4+
# gem name and version. It takes into account whether it is running
5+
# under JRuby to append "-java" to the gem name if necessary.
6+
#
7+
# Usage:
8+
# ruby gem_name.rb <gem_name> <gem_version>
9+
10+
if ARGV.length != 2
11+
puts "Usage: ruby gem_name.rb <gem_name> <gem_version>"
12+
exit 1
13+
end
14+
15+
gem_name = ARGV.first
16+
gem_version = ARGV.last
17+
18+
base_name = "#{gem_name}-#{gem_version}"
19+
base_name = "#{base_name}-java" if defined?(JRUBY_VERSION)
20+
21+
puts "#{base_name}.gem"

ruby/cleanup/action.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ runs:
1515
using: composite
1616
steps:
1717
- name: 'Check out the repository'
18-
uses: mongodb-labs/drivers-github-tools/secure-checkout@v2
18+
# 58501b85eae697e451b5d1d7dba53f69f65d1909 => the 'v2' tag as of 2025-07-28
19+
uses: mongodb-labs/drivers-github-tools/secure-checkout@58501b85eae697e451b5d1d7dba53f69f65d1909
1920
with:
2021
app_id: ${{ inputs.app_id }}
2122
private_key: ${{ inputs.app_private_key }}

ruby/pr-check/action.yml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# PRs are only eligible for release if they are merged and have
2+
# the `release-candidate` label.
3+
#
4+
# The only events allowed to trigger this action are:
5+
# - push (in which case the commit sha is used to find the corresponding
6+
# PR)
7+
# - workflow_dispatch (in which case the PR is found from the inputs
8+
# on the event)
9+
10+
name: PR Check
11+
description: Check that a PR is eligible for release
12+
13+
outputs:
14+
message:
15+
description: The body of the pull request that is being released.
16+
value: ${{ steps.check_pr.outputs.message }}
17+
ref:
18+
description: The ref of the pull request that is being released.
19+
value: ${{ steps.check_pr.outputs.ref }}
20+
21+
runs:
22+
using: composite
23+
steps:
24+
- name: "Check PR Eligibility"
25+
id: check_pr
26+
# 60a0d83039c74a4aee543508d2ffcb1c3799cdea => 'v7' tag as of 2025-07-28
27+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
28+
with:
29+
script: |
30+
let pr;
31+
32+
// was this triggered by a push event?
33+
if (context.eventName == 'push') {
34+
// if so, we need to find the PR that corresponds to the commit
35+
// that was pushed.
36+
//
37+
// because only maintainers can push to protected branches,
38+
// we can assume the user has the correct permissions to do
39+
// this.
40+
const { data: listing } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
41+
owner: context.repo.owner,
42+
repo: context.repo.repo,
43+
commit_sha: context.payload.after,
44+
});
45+
46+
if (listing.length == 0) {
47+
throw new Error(`Workflow aborted: No pull request found for the pushed commit (${context.payload.after}).`);
48+
}
49+
50+
const response = await github.rest.pulls.get({
51+
owner: context.repo.owner,
52+
repo: context.repo.repo,
53+
pull_number: listing[0].number,
54+
});
55+
56+
pr = response.data;
57+
58+
// if it wasn't triggered by a push event, was it triggered by
59+
// a workflow_dispatch event?
60+
} else if (context.eventName == 'workflow_dispatch') {
61+
// it is technically possible for users with only write access
62+
// to trigger workflows; we need to make sure that the user
63+
// who triggered this has either admin or maintain access to the
64+
// repository.
65+
const username = context.triggering_actor || context.actor;
66+
67+
const { data: perms } = await github.rest.repos.getCollaboratorPermissionLevel({
68+
owner: context.repo.owner,
69+
repo: context.repo.repo,
70+
username,
71+
});
72+
73+
if (perms.role_name !== 'admin' && perms.role_name !== 'maintain') {
74+
throw new Error(`User ${username} must have 'admin' or 'maintain' role to initiate the release process. (${perms.role_name})`);
75+
}
76+
77+
// if so, we grab the PR with the number that was passed in with
78+
// the inputs.
79+
const number = context.payload.inputs.pr;
80+
if (!number) {
81+
throw new Error('Workflow aborted: No pull request number provided. (need `pr` input)');
82+
}
83+
84+
const response = await github.rest.pulls.get({
85+
owner: context.repo.owner,
86+
repo: context.repo.repo,
87+
pull_number: number,
88+
});
89+
90+
pr = response.data;
91+
92+
// workflow was triggered by an unrecognized/unsupported event
93+
} else {
94+
throw new Error(`Workflow aborted: Unsupported event type: ${context.eventName}.`);
95+
}
96+
97+
if (!pr) {
98+
throw new Error('No pull request found for the triggered event.');
99+
}
100+
101+
if (!pr.merged) {
102+
throw new Error('Pull request is not merged.');
103+
}
104+
105+
if (!pr.labels.some(label => label.name == 'release-candidate')) {
106+
throw new Error('Pull request is not a release candidate.');
107+
}
108+
109+
console.log('body: >>', pr.body, '<<');
110+
console.log('ref: >>', pr.merge_commit_sha, '<<');
111+
112+
core.setOutput('message', pr.body);
113+
core.setOutput('ref', pr.merge_commit_sha);

0 commit comments

Comments
 (0)