Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/release-ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ jobs:
sha: ${{ inputs.sha || github.event.pull_request.head.sha }}
dry_run: ${{ inputs.dry_run || github.event_name == 'pull_request' }}
working_directory: test/release/ruby
package_name: bt-publishing-test # exercises the RubyGems-availability fail-fast check

prepare:
needs: validate
Expand Down
2 changes: 1 addition & 1 deletion actions/release/lang/js/publish/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ runs:
echo "=== pnpm ==="
pnpm --version || echo "(unavailable)"
echo "=== Registry ==="
npm config get registry
pnpm config get registry
echo "=== package.json version ==="
node -p "require('./package.json').version" 2>/dev/null || echo "(unavailable)"

Expand Down
25 changes: 19 additions & 6 deletions actions/release/lang/js/validate/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,24 @@ runs:
echo "No package_name provided; skipping npm availability check."
exit 0
fi
if npm view "$PACKAGE_NAME@$VERSION" version --registry "$REGISTRY" >/dev/null 2>&1; then
echo "Error: $PACKAGE_NAME@$VERSION already exists on npm — has the version been bumped?"
exit 1
fi
echo "$PACKAGE_NAME@$VERSION is available on npm."
REGISTRY="${REGISTRY%/}"
CODE=$(curl -sS -o /dev/null -w '%{http_code}' \
--retry 3 --retry-connrefused --max-time 30 \
"$REGISTRY/$PACKAGE_NAME/$VERSION")
case "$CODE" in
200)
echo "Error: $PACKAGE_NAME@$VERSION already exists on npm — has the version been bumped?"
exit 1
;;
404)
echo "$PACKAGE_NAME@$VERSION is available on npm."
;;
*)
echo "Error: unexpected response from the npm registry (HTTP $CODE) checking $PACKAGE_NAME@$VERSION;"
echo "cannot confirm the version is unpublished — aborting rather than risk a bad release."
exit 1
;;
esac

- name: Validate release channel
shell: bash
Expand Down Expand Up @@ -251,6 +264,6 @@ runs:
echo "=== pnpm ==="
pnpm --version || echo "(unavailable)"
echo "=== Registry ==="
npm config get registry
pnpm config get registry
echo "=== package.json version ==="
node -p "require('./package.json').version" 2>/dev/null || echo "(unavailable)"
39 changes: 37 additions & 2 deletions actions/release/lang/ruby/validate/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
name: Validate Ruby Release
description: >
Checks out the release SHA, sets up Ruby, reads the gem version, validates
the release (tag existence, branch, commit metadata), and runs lint + build
to confirm the gem is publishable before the approval gate.
the release (RubyGems availability, tag existence, branch, commit metadata),
and runs lint + build to confirm the gem is publishable before the approval gate.

inputs:
sha:
Expand Down Expand Up @@ -32,6 +32,13 @@ inputs:
description: "Path to the gem root (where Gemfile and gemspec live)"
required: false
default: '.'
package_name:
description: >
RubyGems gem name. When set, validate fails fast if this version is already
published — the registry, not the git tag, is the source of truth (covers
prereleases and force-deleted tags). Leave empty to skip.
required: false
default: ''
ruby_version:
description: "Ruby version to use, or a version file path (.tool-versions, .ruby-version)"
required: false
Expand Down Expand Up @@ -83,6 +90,34 @@ runs:
echo "version=$VERSION" >> $GITHUB_OUTPUT
fi

- name: Check RubyGems version availability
shell: bash
env:
PACKAGE_NAME: ${{ inputs.package_name }}
VERSION: ${{ steps.read-version.outputs.version }}
run: |
if [ -z "$PACKAGE_NAME" ]; then
echo "No package_name provided; skipping RubyGems availability check."
exit 0
fi
CODE=$(curl -sS -o /dev/null -w '%{http_code}' \
--retry 3 --retry-connrefused --max-time 30 \
"https://rubygems.org/api/v2/rubygems/$PACKAGE_NAME/versions/$VERSION.json")
case "$CODE" in
200)
echo "Error: $PACKAGE_NAME $VERSION already exists on RubyGems — has the version been bumped?"
exit 1
;;
404)
echo "$PACKAGE_NAME $VERSION is available on RubyGems."
;;
*)
echo "Error: unexpected response from RubyGems (HTTP $CODE) checking $PACKAGE_NAME $VERSION;"
echo "cannot confirm the version is unpublished — aborting rather than risk a bad release."
exit 1
;;
esac

- name: Validate SHA format
shell: bash
env:
Expand Down
13 changes: 11 additions & 2 deletions templates/actions/release/lang/ruby/validate.yml.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Validate Ruby Release
description: >
Checks out the release SHA, sets up Ruby, reads the gem version, validates
the release (tag existence, branch, commit metadata), and runs lint + build
to confirm the gem is publishable before the approval gate.
the release (RubyGems availability, tag existence, branch, commit metadata),
and runs lint + build to confirm the gem is publishable before the approval gate.

inputs:
sha:
Expand Down Expand Up @@ -31,6 +31,13 @@ inputs:
description: "Path to the gem root (where Gemfile and gemspec live)"
required: false
default: '.'
package_name:
description: >
RubyGems gem name. When set, validate fails fast if this version is already
published — the registry, not the git tag, is the source of truth (covers
prereleases and force-deleted tags). Leave empty to skip.
required: false
default: ''
ruby_version:
description: "Ruby version to use, or a version file path (.tool-versions, .ruby-version)"
required: false
Expand Down Expand Up @@ -64,6 +71,8 @@ runs:

<%= render_step('lang/ruby/read-version') %>

<%= render_step('release/lang/ruby/rubygems-availability') %>

<%= render_step('release/validate', version: "${{ steps.read-version.outputs.version }}") %>

- name: Lint and build
Expand Down
2 changes: 1 addition & 1 deletion templates/steps/lang/js/env-dump.yml.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
echo "=== pnpm ==="
pnpm --version || echo "(unavailable)"
echo "=== Registry ==="
npm config get registry
pnpm config get registry
echo "=== package.json version ==="
node -p "require('./package.json').version" 2>/dev/null || echo "(unavailable)"
32 changes: 24 additions & 8 deletions templates/steps/release/lang/js/npm-availability.yml.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<%#
Fails fast if the package version is already published to the npm registry.
Read-only registry query (no auth). Self-guards: skips when package_name is
empty. Complements release/validate's git-tag check by covering prereleases,
which aren't tagged. Assumes the read-version step (id: read-version) has run.
Read-only registry HTTP query — no auth, and no package-manager CLI, so it works
in pnpm-strict repos (a `npm view` here trips devEngines/engines with
EBADDEVENGINES, and swallowing that error silently passes the check). Self-guards:
skips when package_name is empty. Complements release/validate's git-tag check by
covering prereleases, which aren't tagged. Assumes the read-version step
(id: read-version) has run.

@param package_name [String] expr for the npm package name. Default: ${{ inputs.package_name }}
@param registry [String] expr for the npm registry URL. Default: ${{ inputs.registry }}
Expand All @@ -18,8 +21,21 @@
echo "No package_name provided; skipping npm availability check."
exit 0
fi
if npm view "$PACKAGE_NAME@$VERSION" version --registry "$REGISTRY" >/dev/null 2>&1; then
echo "Error: $PACKAGE_NAME@$VERSION already exists on npm — has the version been bumped?"
exit 1
fi
echo "$PACKAGE_NAME@$VERSION is available on npm."
REGISTRY="${REGISTRY%/}"
CODE=$(curl -sS -o /dev/null -w '%{http_code}' \
--retry 3 --retry-connrefused --max-time 30 \
"$REGISTRY/$PACKAGE_NAME/$VERSION")
case "$CODE" in
200)
echo "Error: $PACKAGE_NAME@$VERSION already exists on npm — has the version been bumped?"
exit 1
;;
404)
echo "$PACKAGE_NAME@$VERSION is available on npm."
;;
*)
echo "Error: unexpected response from the npm registry (HTTP $CODE) checking $PACKAGE_NAME@$VERSION;"
echo "cannot confirm the version is unpublished — aborting rather than risk a bad release."
exit 1
;;
esac
36 changes: 36 additions & 0 deletions templates/steps/release/lang/ruby/rubygems-availability.yml.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<%#
Fails fast if the gem version is already published to RubyGems. Read-only
registry HTTP query (no auth). The registry — not the git tag — is the source of
truth, so this catches a duplicate even if the tag was force-deleted or never
pushed, and it covers prereleases (which aren't tagged). Self-guards: skips when
package_name is empty. Assumes the read-version step (id: read-version) has run.

@param package_name [String] expr for the RubyGems gem name. Default: ${{ inputs.package_name }}
-%>
- name: Check RubyGems version availability
shell: bash
env:
PACKAGE_NAME: <%= locals.fetch(:package_name) { "${{ inputs.package_name }}" } %>
VERSION: ${{ steps.read-version.outputs.version }}
run: |
if [ -z "$PACKAGE_NAME" ]; then
echo "No package_name provided; skipping RubyGems availability check."
exit 0
fi
CODE=$(curl -sS -o /dev/null -w '%{http_code}' \
--retry 3 --retry-connrefused --max-time 30 \
"https://rubygems.org/api/v2/rubygems/$PACKAGE_NAME/versions/$VERSION.json")
case "$CODE" in
200)
echo "Error: $PACKAGE_NAME $VERSION already exists on RubyGems — has the version been bumped?"
exit 1
;;
404)
echo "$PACKAGE_NAME $VERSION is available on RubyGems."
;;
*)
echo "Error: unexpected response from RubyGems (HTTP $CODE) checking $PACKAGE_NAME $VERSION;"
echo "cannot confirm the version is unpublished — aborting rather than risk a bad release."
exit 1
;;
esac