Skip to content

Fix non-paginating entity finders, add CI, and release 0.2.1 - #8

Merged
fedorgorshkov-fact merged 1 commit into
mainfrom
fix/gem-quality-0.2.1
Jul 29, 2026
Merged

Fix non-paginating entity finders, add CI, and release 0.2.1#8
fedorgorshkov-fact merged 1 commit into
mainfrom
fix/gem-quality-0.2.1

Conversation

@fedorgorshkov-fact

Copy link
Copy Markdown
Contributor

🚪 Why?

Follow-up to the v0.2.0 release (#7). Auditing the gem after that merge turned up one
silent-wrong-answer bug in the newly-added entity finders, a latent require gap, and the
absence of any CI — which is the actual reason a sandbox base_url shipped in c09ac21 and
broke configuration_spec.rb:9 unnoticed until release day.

This PR fixes those and cleans up release metadata. It does not attempt the two known
architectural bugs (see Deferred below) — those are documented rather than silently carried.

No consumer needs to re-pin unless it starts using the subscription or custom-list-pagination
paths, neither of which is reachable from catalog provisioning today.

What changed

Fixed: find_by_* searched only the first page (the real bug)

find_by_custom_property and find_by_integration_entity_id issued exactly one request and
searched response['data']. The comment directly above them explains why that's unsafe:

Hyperline silently ignores unknown query params (returning the unfiltered list)

If the server drops the filter, the response is page 1 of the unfiltered list. Any entity
past that page returned nil — indistinguishable from "does not exist". A nil here reads as
"not imported yet", so the failure mode is a duplicate create, not an exception.

Both finders now walk the full result set through a shared private search_find helper. Two
constraints from the existing specs shaped it:

  • The first request omits skip entirely rather than sending skip=0. The finder specs stub
    with exact-match .with(query: …) and no skip key, so emitting it would have broken all five.
    It also keeps the unpaged-search request shape byte-identical to before.
  • Meta is best-effort. Those same stubs return partial envelopes (meta: { total: 1 }, no
    taken/skipped), so next_offset falls back to data.size and terminates cleanly instead of
    looping forever or raising on nil. This also hardens the finder path against endpoints that
    answer with a non-standard envelope.

Three specs cover it: a match on page 2 for each finder, plus one asserting a single request when
meta omits the counters.

Fixed: missing require 'json'

BaseResource#parse_error_body calls JSON.parse, but json was never required anywhere in
lib/. It worked only because Faraday loads it transitively — a dependency change would have
turned the error-handling path into a NameError. One line, on the path you hit precisely when
something is already going wrong.

Fixed: gemspec metadata URLs

source_code_uri and changelog_uri pointed at github.com/hyperline/hyperline-ruby, which
does not exist — both 404 for anyone installing the gem. Now factorialco/hyperline-cli.

⚠️ Reviewers: this fix landed once before and was reverted. #3 was titled "Fix gemspec
metadata URLs" but its body says "Remove mfa" — it bundled the URL correction with deleting
spec.metadata['rubygems_mfa_required']. #4 then reverted the whole commit, restoring the wrong
URLs as collateral. This PR changes the two URL lines only and leaves
rubygems_mfa_required at hyperline.gemspec:23 untouched.
Please don't re-bundle them.

Added: CI

.github/workflows/ci.yml runs rspec + rubocop on Ruby 3.3.5 (matching .tool-versions) for
pushes to main and all PRs. The repo had no CI at all. This is the highest-leverage change here:
it is exactly what would have caught the v0.2.0 base_url regression at PR time.

Release hygiene

  • CHANGELOG gained a 0.2.1 entry and the 0.2.0 entry that was never written — the
    five resources added in Feat/adding bundles #7 were undocumented. Plus a Known issues section recording the
    deferred bugs.
  • Gemspec description listed three resources; there are eight.
  • .gitignore now covers *.gem, /pkg/, bundler and lint caches — it previously had two
    lines, which is how a build artifact got committed.
  • Version0.2.1, Gemfile.lock regenerated.

Deferred, deliberately

Both are real and both are documented under Known issues in the CHANGELOG rather than quietly
carried. Neither is reachable from catalog provisioning, which is the only consumer today:

  1. Subscriptions#list hits v1 while #get/#update and search use v2. BaseResource#list
    builds from resource_path, not search_path, so it ignores the v2 override — despite two
    comments in the code stating that listing subscriptions is a v2 operation. Fixing it means
    deciding whether the comments or the code are wrong, and subscriptions_spec.rb:11 currently
    asserts the v1 path, so a fix has to change a passing test. Bites whenever
    subscription-management code lands.
  2. Collection#next_page always re-issues the resource's default #list. So paginating a
    custom list method — Subscriptions#list_templates is the only one today — returns page 1 of
    templates and every subsequent page of subscriptions. The fix is for Collection to capture
    the path or a callable instead of the resource, which is a wider change than this PR's scope.

Standard .list pagination is unaffected: products.list and custom_properties.list both
re-page their own base_path correctly.

Out of scope but required

  • lib/hyperline/errors.rb — adding rubocop to CI with 5 standing offenses means CI fails on
    its first run. Four were blank lines between error classes. For the fifth (a nested ternary),
    rubocop's autocorrect produced an unreadable multi-line if nested inside a ||, so I
    extracted ErrorMapper.error_class_for by hand. Logic is equivalent — MAPPED[nil] was already
    nil, so the status.nil? guard behaves identically.
  • Deleted hyperline-0.1.0.gem — a committed build artifact. Gitignoring *.gem while
    leaving a tracked 0.1.0 file beside a 0.2.1 release is half a fix. Easy to drop if you'd rather
    keep it.

Testing

  • bundle exec rspec71 examples, 0 failures (68 before; +3 for the pagination fix)
  • bundle exec rubocop26 files, no offenses (5 before)
  • Gem::Specification.loadhyperline 0.2.1, metadata URLs corrected,
    rubygems_mfa_required still "true"
  • ci.yml parses as valid YAML

Requires a v0.2.1 tag on main after merge.

@fedorgorshkov-fact
fedorgorshkov-fact merged commit 090a373 into main Jul 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant