Skip to content

Commit cdeea25

Browse files
committed
feat!: rebuild the client on API specification 2.26.1
The 0.3.x line was generated in 2024 and has drifted well past usefulness: it misses every operation the API has shipped since, including OMR, and it offers nothing above the raw generated surface. This replaces it with a generated client that is reproducible from this repository alone, plus the ergonomic layer the README has always claimed. Regenerated with openapi-generator 7.24.0 (ruby, faraday) against API specification 2.26.1: 123 operations, 196 models, 23 scopes. Four defects that no check in this repository would have caught, all found by installing the gem and making real requests: * The gemspec declared typhoeus while tools/openapi-config.json selects the faraday library. `gem install flat_api` pulled a dependency the code never loads, and did not pull the ones it does. Now declares faraday, faraday-multipart and marcel. * The gem could not be loaded at all. The 200 response of createLtiConfiguration was an inline allOf over LtiConfiguration, which is a oneOf. This generator emits a oneOf as a module and an allOf as a subclass, so the output read `class CreateLtiConfiguration200Response < LtiConfiguration`, and a Ruby class cannot inherit a module. Fixed in the specification (BE-1213), not patched here. * The typed errors were dead code. errors.rb defined the hierarchy, and api_client.rb went on raising the generated ApiError, so nothing could ever rescue FlatNotFoundError. The raise site is rewired now. * None of errors.rb, retry.rb, pagination.rb or oauth.rb was required from lib/flat_api.rb, so `require 'flat_api'` gave you the generated client and nothing built on top of it. The retry policy, the pagination helper and the OAuth refresh were all unreachable. 95_requires.py wires them, errors first, because api_client.rb raises from it. Also: * required_ruby_version moves from 3.0 to 3.3, matching the runtimes upstream still supports and the matrix in .sdkgen.yaml. * The gemspec ships LICENSE, README.md and CHANGELOG.md, and drops a test_files list pointing at a directory that does not exist. * Removes .gitlab-ci.yml. It is a leftover of an old generation: this repository has no GitLab mirror, the file pins Ruby 3.0 and 3.1, which the gemspec now refuses, and it runs rspec against a spec directory that is not there. * tools/smoke.rb drives the shared scenarios against the real API: score lifecycle, a paginated traversal and both typed errors, cleaning up what it creates. Nothing metered. * Stops tracking .DS_Store. * Removes the test harness that was never wired up: an rspec development dependency and a .rspec requiring a spec_helper that does not exist, a Rakefile task over a spec directory that does not exist, pry-byebug, and a rubocop pinned to 0.66.0 from 2019 with a config targeting Ruby 2.4 and excluding Rails paths. Nothing ran any of it, and rubocop at that pin cannot parse the Ruby this gem now requires. CI builds the gem and loads every file, which is the same shape as the Python client's. A second round, after a review pointed at four more of exactly the same kind. Each was written, documented in the README and never reached by a request: * FlatApi::FlatClient did not exist. The first code sample in the README and in QUICKSTART raised NameError, and so did the pagination example below it. 30_client.py writes it: it holds one ApiClient, exposes each generated API by a short name, and paginates without the caller seeing a cursor. It builds its own Configuration rather than mutating Configuration.default, so two clients with different tokens do not overwrite each other. * Pagination sent the cursor as :next. The generator renames the parameter to :_next, because next is a Ruby keyword, and maps it back to the next query parameter itself. Every iteration therefore refetched page one; the loop guard saw a cursor it had already used and stopped. Traversals returned the first page and looked like they had reached the end. * RetryPolicy was never called. call_api is now a wrapper around the renamed call_api_once, and Configuration carries a retry_policy to tune or disable it. Wrapping the one request path rather than the 127 generated methods. * TokenManager#access_token returned the token whether or not it had expired, which made Tokens#expired? dead code. It now refreshes, re-checking inside the lock so that two threads arriving together spend one round trip rather than two, and so a provider that rotates refresh tokens does not have the second call invalidate what the first stored. The smoke suite passed through all four, so it changed too: * It goes through FlatClient, the entry point the documentation points at. * The pagination check creates three collections and traverses with limit=1, so it cannot pass without following the cursor. The previous version asked for ten items on an account holding fewer, never requested a second page, and proved nothing. * Two checks that need no network cover the retry wiring and the token refresh, since a build cannot tell a module that runs from one that does not. * scenarios.yaml listed two scenarios no runner executed. It now describes what actually runs.
1 parent 61d0444 commit cdeea25

612 files changed

Lines changed: 38238 additions & 21170 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: CI
2+
3+
# Build and load checks. Everything that needs a credential runs elsewhere and reports
4+
# back as a commit status, so no secret is reachable from this workflow.
5+
6+
on:
7+
pull_request:
8+
push:
9+
branches: [master, main]
10+
11+
permissions:
12+
contents: read
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
build:
20+
name: build (ruby ${{ matrix.ruby }})
21+
runs-on: ubuntu-latest
22+
strategy:
23+
fail-fast: false
24+
matrix:
25+
ruby: ['3.3', '3.4']
26+
steps:
27+
- uses: actions/checkout@v4
28+
- uses: ruby/setup-ruby@v1
29+
with:
30+
ruby-version: ${{ matrix.ruby }}
31+
bundler-cache: true
32+
- name: Load every file
33+
run: bundle exec ruby -Ilib -e "require 'flat_api'; puts FlatApi::VERSION"

.github/workflows/gem-push.yml

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

.github/workflows/release.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Release
2+
3+
# Publishing is triggered by a version tag and nothing else (FR-019a).
4+
5+
on:
6+
push:
7+
tags: ['[0-9]+.[0-9]+.[0-9]+']
8+
9+
permissions:
10+
contents: read
11+
id-token: write # OIDC for RubyGems trusted publishing (FR-021a)
12+
13+
jobs:
14+
publish:
15+
runs-on: ubuntu-latest
16+
environment: rubygems
17+
steps:
18+
- uses: actions/checkout@v4
19+
- uses: ruby/setup-ruby@v1
20+
with:
21+
ruby-version: '3.4'
22+
bundler-cache: true
23+
24+
- name: The tag must match the packaged version
25+
run: |
26+
TAG="${GITHUB_REF_NAME}"
27+
PKG="$(ruby -Ilib -e "require 'flat_api/version'; print FlatApi::VERSION")"
28+
[ "$TAG" = "$PKG" ] || { echo "tag $TAG != VERSION $PKG"; exit 1; }
29+
30+
- run: gem build flat_api.gemspec
31+
32+
# No API key: RubyGems trusts this repository and workflow by OIDC.
33+
- uses: rubygems/release-gem@v1

.github/workflows/ruby.yml

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

.github/workflows/tag-on-merge.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Tag on merge
2+
3+
# Merging is what creates the version tag, and the tag is what publishes (FR-007f, FR-019a).
4+
# A breaking release waits for a human to merge, which is how the FR-019 approval is expressed.
5+
6+
on:
7+
push:
8+
branches: [master, main]
9+
10+
permissions:
11+
contents: write
12+
13+
jobs:
14+
tag:
15+
runs-on: ubuntu-latest
16+
steps:
17+
# SDK_RELEASE_TOKEN, not the automatic GITHUB_TOKEN. GitHub does not start a workflow run for
18+
# an event created with GITHUB_TOKEN, so a tag pushed with it would never trigger release.yml
19+
# and nothing would ever publish. That failure is silent: the tag appears, the release
20+
# workflow simply never runs. Needs contents:write on this repository.
21+
# Checked before checkout. An empty token there surfaces as a bare "Input required and not
22+
# supplied: token", which says nothing about which secret is missing or why it matters.
23+
- name: SDK_RELEASE_TOKEN must be set
24+
run: |
25+
test -n "${{ secrets.SDK_RELEASE_TOKEN }}" || {
26+
echo "SDK_RELEASE_TOKEN is not set on this repository."
27+
echo
28+
echo "The tag has to be pushed with it rather than the automatic GITHUB_TOKEN, because"
29+
echo "GitHub does not start a workflow run for an event created with that token. The"
30+
echo "tag would appear and release.yml would never fire, publishing nothing."
31+
exit 1
32+
}
33+
- uses: actions/checkout@v4
34+
with:
35+
fetch-depth: 0
36+
token: ${{ secrets.SDK_RELEASE_TOKEN }}
37+
- name: Tag the version if it is new
38+
run: |
39+
VERSION="$(cat VERSION)"
40+
if git rev-parse "$VERSION" >/dev/null 2>&1; then
41+
echo "Tag $VERSION already exists, nothing to do."
42+
exit 0
43+
fi
44+
git config user.name "Flat SDK bot"
45+
git config user.email "developers@flat.io"
46+
git tag -a "$VERSION" -m "Release $VERSION"
47+
git push origin "$VERSION"

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,9 @@ build/
3737

3838
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
3939
.rvmrc
40+
41+
# build artifacts
42+
*.gem
43+
.sdkgen-scratch/
44+
.openapi-spec.yaml
45+
.DS_Store

.gitlab-ci.yml

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

0 commit comments

Comments
 (0)