Skip to content

Commit 5eb7a9e

Browse files
tomasr78claude
andcommitted
Trunk-based release pipeline; 3.0.1
- build.yml: specs on Ruby 3.2, 3.3, 3.4, 4.0 + aggregator `build` job (required check) that checks ConvertApi::VERSION, builds and installs the gem. Actions pinned to SHAs; Dependabot keeps them current. - publish.yml: GitHub Release v{semver} by tomasr78 -> checks publisher, tag, main, version, RubyGems absence -> specs -> gem build/install -> push from the `rubygems` environment with Trusted Publishing (temporary RUBYGEMS_API_KEY fallback until the trusted publisher exists). - Live specs tagged `live: true`, skipped without CONVERT_API_SECRET; CONVERT_API_BASE_URI supported. - Fix load warnings on Ruby 3.4+ (URI.regexp) and 4.0 (cgi). - Gem ships lib/ + README/LICENSE/CHANGELOG only; metadata URIs; homepage -> convertapi-library-ruby. - RELEASING.md, CHANGELOG.md; version 3.0.1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 551d77e commit 5eb7a9e

14 files changed

Lines changed: 546 additions & 55 deletions

File tree

‎.github/dependabot.yml‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: 2
2+
updates:
3+
# The workflows pin every action to a commit SHA; Dependabot keeps those pins current.
4+
- package-ecosystem: github-actions
5+
directory: /
6+
schedule:
7+
interval: weekly
8+
groups:
9+
actions:
10+
patterns: ['*']

‎.github/workflows/build.yml‎

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
name: Build
2+
run-name: >-
3+
${{ github.event_name == 'pull_request' && format('Checking that #{0} builds', github.event.pull_request.number)
4+
|| format('Building {0}', github.ref_name) }}
5+
6+
# Trunk-based: main is the only long-lived branch. Every pull request and every push to main runs the specs
7+
# on each supported Ruby and builds the gem, but nothing is published here: RubyGems versions are permanent,
8+
# so a release is a deliberate act - publishing a GitHub Release v{semver}, which runs publish.yml. The
9+
# required status check is the `build` job, which passes only when every Ruby passed and the gem built.
10+
on:
11+
pull_request:
12+
branches: [main]
13+
push:
14+
branches: [main]
15+
workflow_dispatch:
16+
17+
permissions:
18+
contents: read
19+
20+
concurrency:
21+
# A newer push to the same pull request cancels the older build; builds of main never cancel each other.
22+
group: build-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || github.run_id }}
23+
cancel-in-progress: true
24+
25+
jobs:
26+
test:
27+
name: test (Ruby ${{ matrix.ruby }})
28+
runs-on: ubuntu-latest
29+
timeout-minutes: 15
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
ruby: ['3.2', '3.3', '3.4', '4.0']
34+
steps:
35+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
36+
with:
37+
persist-credentials: false
38+
39+
- uses: ruby/setup-ruby@824c0e29fdfc7d689c191c27acc969d2d04b7dd8 # v1.331.0
40+
with:
41+
ruby-version: ${{ matrix.ruby }}
42+
bundler-cache: true
43+
44+
# The examples tagged `live: true` convert real files on ConvertAPI and run only when the
45+
# CONVERTAPI_SECRET secret (an API token) exists; pull requests from forks and Dependabot never get it,
46+
# so for them only the offline examples run. CONVERTAPI_BASE_URI (a variable) can point them at
47+
# another deployment, e.g. https://stag-v2.convertapi.com/.
48+
- name: Specs
49+
env:
50+
CONVERT_API_SECRET: ${{ secrets.CONVERTAPI_SECRET }}
51+
CONVERT_API_BASE_URI: ${{ vars.CONVERTAPI_BASE_URI }}
52+
RUBYOPT: -W
53+
run: bundle exec rake spec
54+
55+
build:
56+
name: build
57+
needs: test
58+
# Runs even when a test job failed, so that the required check reports a failure instead of being
59+
# skipped - a skipped required check counts as passed.
60+
if: always()
61+
runs-on: ubuntu-latest
62+
timeout-minutes: 10
63+
steps:
64+
- name: Check the specs
65+
env:
66+
RESULT: ${{ needs.test.result }}
67+
run: |
68+
if [ "$RESULT" != success ]; then
69+
echo "::error::The specs did not pass on every Ruby ($RESULT)"
70+
exit 1
71+
fi
72+
73+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
74+
with:
75+
fetch-depth: 0
76+
persist-credentials: false
77+
78+
- uses: ruby/setup-ruby@824c0e29fdfc7d689c191c27acc969d2d04b7dd8 # v1.331.0
79+
with:
80+
ruby-version: '3.4'
81+
82+
# ConvertApi::VERSION is the gem's version and goes into the User-Agent of every request; publish.yml
83+
# refuses a tag that does not match it. It may run ahead of the latest release, never behind it.
84+
- name: Check the version
85+
id: version
86+
run: |
87+
set -euo pipefail
88+
VERSION=$(ruby -Ilib -rconvert_api/version -e 'print ConvertApi::VERSION')
89+
if ! [[ "$VERSION" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(\.(alpha|beta|rc)\.(0|[1-9][0-9]*))?$ ]]; then
90+
echo "::error file=lib/convert_api/version.rb::ConvertApi::VERSION '$VERSION' is not {major}.{minor}.{patch} or {major}.{minor}.{patch}.{alpha|beta|rc}.{n}"
91+
exit 1
92+
fi
93+
BASE="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
94+
LATEST=$(git tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sed 's/^v//' | sort -V | tail -n1)
95+
if [ -n "$LATEST" ] && [ "$(printf '%s\n%s\n' "$LATEST" "$BASE" | sort -V | tail -n1)" != "$BASE" ]; then
96+
echo "::error file=lib/convert_api/version.rb::ConvertApi::VERSION $VERSION is lower than the latest release $LATEST"
97+
exit 1
98+
fi
99+
# A pre-release sorts below its release, so a pre-release of the latest release is a step back.
100+
if [ "$VERSION" != "$BASE" ] && [ "$BASE" = "$LATEST" ]; then
101+
echo "::error file=lib/convert_api/version.rb::ConvertApi::VERSION $VERSION is a pre-release of $LATEST, which is already released"
102+
exit 1
103+
fi
104+
{
105+
echo "version=$VERSION"
106+
echo "latest=$LATEST"
107+
} >> "$GITHUB_OUTPUT"
108+
109+
# The gem a release would publish, built and installed outside the checkout, so a change can be tried
110+
# out from the run's artifact before it is released.
111+
- name: Build the gem
112+
env:
113+
VERSION: ${{ steps.version.outputs.version }}
114+
run: |
115+
set -euo pipefail
116+
mkdir -p dist
117+
gem build convert_api.gemspec --output "dist/convert_api-$VERSION.gem"
118+
GEM_HOME="$RUNNER_TEMP/gems" gem install --local --no-document "dist/convert_api-$VERSION.gem"
119+
cd "$RUNNER_TEMP"
120+
GEM_HOME="$RUNNER_TEMP/gems" GEM_PATH="$RUNNER_TEMP/gems" ruby -W -e '
121+
require "convert_api"
122+
abort "loaded #{ConvertApi::VERSION}, expected #{ARGV[0]}" unless ConvertApi::VERSION == ARGV[0]
123+
abort "loaded from #{$LOADED_FEATURES.grep(/convert_api\.rb\z/)}" unless $LOADED_FEATURES.grep(/convert_api\.rb\z/).all? { |f| f.start_with?(ENV["GEM_HOME"]) }
124+
puts ConvertApi::Client::USER_AGENT' "$VERSION"
125+
126+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
127+
with:
128+
name: convert_api-${{ steps.version.outputs.version }}-run${{ github.run_number }}
129+
path: dist/
130+
retention-days: 14
131+
if-no-files-found: error
132+
133+
- name: Summary
134+
env:
135+
VERSION: ${{ steps.version.outputs.version }}
136+
LATEST: ${{ steps.version.outputs.latest }}
137+
run: |
138+
{
139+
echo "| | |"
140+
echo "|---|---|"
141+
echo "| \`ConvertApi::VERSION\` | \`$VERSION\` (latest release: \`v$LATEST\`) |"
142+
echo "| Gem | \`convert_api-$VERSION.gem\` (artifact only, not published) |"
143+
echo "| Ruby | 3.2, 3.3, 3.4, 4.0 |"
144+
} >> "$GITHUB_STEP_SUMMARY"

‎.github/workflows/main.yml‎

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

0 commit comments

Comments
 (0)