Skip to content

Commit f89608b

Browse files
committed
Use Trusted Publishing for release to RubyGems
1 parent d47b8e6 commit f89608b

5 files changed

Lines changed: 165 additions & 96 deletions

File tree

.github/scripts/pack.sh

Lines changed: 0 additions & 17 deletions
This file was deleted.

.github/scripts/publish.sh

Lines changed: 0 additions & 11 deletions
This file was deleted.

.github/scripts/publish_env.sh

Lines changed: 0 additions & 35 deletions
This file was deleted.

.github/workflows/ci-release.yaml

Lines changed: 148 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,174 @@
11
name: Release CI
2+
23
on:
34
push:
45
tags:
5-
# This looks like a regex, but it's actually a filter pattern
6-
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
7-
- 'release/v?[0-9]*'
8-
9-
env:
10-
GITHUB_REF_NAME: ${{ github.ref_name }}
6+
- "release/v*"
117

128
jobs:
13-
publish:
14-
name: Publish to RubyGems
9+
prepare_release:
10+
name: Prepare release metadata
1511
runs-on: ubuntu-latest
12+
13+
outputs:
14+
version: ${{ steps.meta.outputs.version }}
15+
dry_run: ${{ steps.meta.outputs.dry_run }}
16+
prerelease: ${{ steps.meta.outputs.prerelease }}
17+
publish_tag: ${{ steps.meta.outputs.publish_tag }}
18+
1619
steps:
1720
- name: Checkout code
18-
uses: actions/checkout@v3
21+
uses: actions/checkout@v5
1922
with:
2023
path: main
21-
- name: Set up environment variables
22-
run: ./.github/scripts/publish_env.sh >> $GITHUB_ENV
23-
working-directory: ./main
24-
shell: bash
24+
2525
- name: Setup Ruby
2626
uses: ruby/setup-ruby@v1
2727
with:
28-
ruby-version: '3.1'
28+
ruby-version: "3.1"
2929
bundler-cache: true
30-
- name: Pack API client
31-
run: ./.github/scripts/pack.sh
30+
31+
- name: Compute and validate release metadata
32+
id: meta
3233
working-directory: ./main
3334
shell: bash
34-
- name: Auth with RubyGems
3535
run: |
36-
mkdir -p ~/.gem
37-
echo ":rubygems_api_key: ${{ secrets.RUBYGEMS_PUBLISH_TOKEN }}" > ~/.gem/credentials
38-
chmod 600 ~/.gem/credentials
39-
shell: bash
40-
- name: Publish API client
41-
run: ./.github/scripts/publish.sh
36+
set -euo pipefail
37+
38+
TAG="${GITHUB_REF_NAME#release/}"
39+
TAG_VALUE="${TAG#v}"
40+
VERSION="${TAG_VALUE%-dry}"
41+
42+
DRY_RUN=0
43+
if [ "${TAG_VALUE}" != "${VERSION}" ]; then
44+
DRY_RUN=1
45+
fi
46+
47+
RUBY_VERSION="$(ruby -Ilib -e 'require "fastly/version"; print Fastly::VERSION')"
48+
49+
echo "Tag version: ${VERSION}"
50+
echo "Ruby version: ${RUBY_VERSION}"
51+
52+
if [ "${VERSION}" != "${RUBY_VERSION}" ]; then
53+
echo "Tag version (${VERSION}) does not match Fastly::VERSION (${RUBY_VERSION})" >&2
54+
exit 1
55+
fi
56+
57+
if [[ "${VERSION}" == *-* ]]; then
58+
PRERELEASE=true
59+
else
60+
PRERELEASE=false
61+
fi
62+
63+
PUBLISH_TAG="$(npx -y semver-parser-cli@0.2.0 "${VERSION}" --field preid)"
64+
if [ "${PUBLISH_TAG}" == "undefined" ] || [ -z "${PUBLISH_TAG}" ]; then
65+
if [ "${PRERELEASE}" == "true" ]; then
66+
PUBLISH_TAG=unnamed
67+
else
68+
PUBLISH_TAG=latest
69+
fi
70+
fi
71+
72+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
73+
echo "dry_run=${DRY_RUN}" >> "$GITHUB_OUTPUT"
74+
echo "prerelease=${PRERELEASE}" >> "$GITHUB_OUTPUT"
75+
echo "publish_tag=${PUBLISH_TAG}" >> "$GITHUB_OUTPUT"
76+
77+
publish_rubygems:
78+
name: Publish to RubyGems
79+
runs-on: ubuntu-latest
80+
needs: prepare_release
81+
if: ${{ needs.prepare_release.outputs.dry_run != '1' }}
82+
83+
permissions:
84+
contents: write
85+
id-token: write
86+
87+
steps:
88+
- name: Checkout code
89+
uses: actions/checkout@v5
90+
with:
91+
persist-credentials: false
92+
93+
- name: Setup Ruby
94+
uses: ruby/setup-ruby@v1
95+
with:
96+
ruby-version: "3.1"
97+
bundler-cache: true
98+
99+
- name: Publish gem with trusted publishing
100+
uses: rubygems/release-gem@v1
101+
102+
create_github_release:
103+
name: Create GitHub release
104+
runs-on: ubuntu-latest
105+
needs:
106+
- prepare_release
107+
- publish_rubygems
108+
if: ${{ needs.prepare_release.outputs.dry_run != '1' }}
109+
110+
permissions:
111+
contents: write
112+
113+
steps:
114+
- name: Checkout code
115+
uses: actions/checkout@v5
116+
with:
117+
path: main
118+
119+
- name: Setup Ruby
120+
uses: ruby/setup-ruby@v1
121+
with:
122+
ruby-version: "3.1"
123+
bundler-cache: true
124+
125+
- name: Fetch published gem from RubyGems
126+
id: fetch
42127
working-directory: ./main
43128
shell: bash
129+
env:
130+
VERSION: ${{ needs.prepare_release.outputs.version }}
131+
run: |
132+
set -euo pipefail
133+
134+
for i in 1 2 3 4 5; do
135+
if gem fetch fastly --version "${VERSION}"; then
136+
break
137+
fi
138+
echo "Fetch attempt ${i} failed; retrying..."
139+
sleep 10
140+
done
141+
142+
PACKAGE_FILENAME="$(ls -1 fastly-"${VERSION}"*.gem | head -n 1)"
143+
if [ -z "${PACKAGE_FILENAME}" ]; then
144+
echo "Failed to fetch published gem for version ${VERSION}" >&2
145+
exit 1
146+
fi
147+
148+
mkdir -p "${GITHUB_WORKSPACE}/dist"
149+
mv "${PACKAGE_FILENAME}" "${GITHUB_WORKSPACE}/dist/${PACKAGE_FILENAME}"
150+
151+
echo "package_filename=${PACKAGE_FILENAME}" >> "$GITHUB_OUTPUT"
152+
44153
- name: Write release body file
45-
run: CODE_PATH=./main ./main/.github/scripts/release_body.sh > ./dist/release_body.txt
46154
shell: bash
47-
- name: Create release (dry run)
48-
if: ${{ env.DRY_RUN == '1' }}
49-
run: cat ./dist/release_body.txt
155+
env:
156+
API_CLIENT_NAME: Ruby
157+
PACKAGE_REPO_NAME: RubyGems
158+
VERSION: ${{ needs.prepare_release.outputs.version }}
159+
DRY_RUN: "0"
160+
PUBLISH_TAG: ${{ needs.prepare_release.outputs.publish_tag }}
161+
PACKAGE_FILENAME: ${{ steps.fetch.outputs.package_filename }}
162+
run: |
163+
set -euo pipefail
164+
CODE_PATH=./main ./main/.github/scripts/release_body.sh > ./dist/release_body.txt
165+
50166
- name: Create GitHub release
51-
if: ${{ env.DRY_RUN != '1' }}
52-
uses: softprops/action-gh-release@v1
167+
uses: softprops/action-gh-release@v2
53168
with:
54-
name: v${{ env.VERSION }}
169+
tag_name: ${{ github.ref_name }}
170+
name: v${{ needs.prepare_release.outputs.version }}
55171
body_path: ./dist/release_body.txt
56-
files: |
57-
./dist/${{ env.PACKAGE_FILENAME }}
172+
files: ./dist/${{ steps.fetch.outputs.package_filename }}
58173
draft: false
59-
prerelease: ${{ env.PUBLISH_TAG != 'latest' }}
174+
prerelease: ${{ needs.prepare_release.outputs.prerelease == 'true' }}

Rakefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,18 @@
11
require "bundler/gem_tasks"
2+
3+
# Override Bundler's default `release` task to avoid pushing git tags.
4+
#
5+
# Our release workflow is triggered by a tag push in GitHub Actions and
6+
# publishes the gem using `rubygems/release-gem` (trusted publishing).
7+
# The default Bundler task would also try to create and push a git tag,
8+
# which conflicts with our workflow.
9+
#
10+
# Pattern adapted from:
11+
# https://github.com/line/line-bot-sdk-ruby/pull/339
12+
13+
Rake::Task["release"].clear
14+
15+
desc "Build and push gem to RubyGems without pushing to source control"
16+
task "release" => %w[build release:guard_clean release:rubygem_push] do
17+
puts "Built and pushed gem to RubyGems without pushing to source control."
18+
end

0 commit comments

Comments
 (0)