Skip to content

fix(xtest): Fixes unbuildable dist paths on merge_group events - #532

Merged
dmihalcik-virtru merged 3 commits into
mainfrom
fix-mq-paths
Jun 23, 2026
Merged

fix(xtest): Fixes unbuildable dist paths on merge_group events#532
dmihalcik-virtru merged 3 commits into
mainfrom
fix-mq-paths

Conversation

@dmihalcik-virtru

@dmihalcik-virtru dmihalcik-virtru commented Jun 22, 2026

Copy link
Copy Markdown
Member

Problem

xtest fails for merge_group events from opentdf/platform during go CLI setup:

tdfs.py:483: in __init__
    raise FileNotFoundError(f"SDK executable not found at path: {self.path}")
E   FileNotFoundError: SDK executable not found at path:
    sdk/go/dist/refs/heads/gh-readonly-queue/main/pr-3630-8a006469dc6e55455a2ce4715415671d39670ef6/cli.sh

The Prepare go cli step only built main, yet the matrix value was go@refs/heads/gh-readonly-queue/....

Root cause

This is a version-resolution bug in otdf_sdk_mgr/resolve.py, not a workflow-config bug.

The platform caller (opentdf/platformchecks.yaml, platform-xtest) passes the go ref as a commit SHA (otdfctl-ref: <merge-sha> main). On a merge-queue run that SHA is pointed at by exactly one ref — the temporary refs/heads/gh-readonly-queue/main/pr-<n>-<sha> branch.

resolve.py had all the merge-queue / PR / branch normalization (→ mq-main-N, pull-N, flattened slashes, head: true) only in the len(matching_tags) > 1 branch. The single-match path stripped just refs/tags//infix, so it:

  1. returned tag = "refs/heads/gh-readonly-queue/main/pr-…" — slashes become the bad nested dist/refs/heads/… path the test looked for, and
  2. never set head: true, so setup-cli-tool skipped the source checkout/build entirely (only main, which is flagged head, got built).

Fix

  • Extract _classify_sha_match() — normalizes any matched (sha, ref) into a filesystem-safe tag (slashes → --) and flags PR / merge-queue / branch refs as head.
  • Extract _ref_specificity() — when a SHA is pointed at by several refs, prefer PR > merge-queue > branch/tag.
  • Route both single- and multi-match SHA lookups through the helper, so a merge-queue commit resolves identically regardless of how many refs point at it. This also drops the previously-dead "unable to differentiate" error path.

Now the example ref resolves to tag = mq-main-3630, head = true, pr = 3630 — a clean dist dir that gets source-built, with matrix value go@mq-main-3630.

Testing

  • Added test_single_match_merge_queue and test_single_match_branch_flagged_head regression tests.
  • uv run pytest — all 135 pass.
  • uv run ruff check ., uv run ruff format ., uv run pyright — clean.

Summary by CodeRabbit

  • Bug Fixes
    • Improved commit SHA resolution to reliably identify pull requests, merge-queue branches, and git branch references with appropriate prioritization and tag formatting.

When a go ref resolves from a commit SHA (as the platform merge_group
caller passes), the SHA is often pointed at by exactly one ref — the
gh-readonly-queue branch. The single-match path only stripped
refs/tags/, so it returned tag=refs/heads/gh-readonly-queue/... (slashes
become a bad nested dist path) and never set head:true, so setup-cli-tool
skipped the source build entirely (only main got built).

Extract _classify_sha_match()/_ref_specificity() and route both single-
and multi-match SHA lookups through them so a merge-queue commit resolves
to a flat tag (mq-main-N) flagged as a head regardless of how many refs
point at it.
@dmihalcik-virtru
dmihalcik-virtru requested review from a team as code owners June 22, 2026 21:51
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dmihalcik-virtru, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 47 minutes and 1 second. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9d671d1d-494b-44dd-a175-acf49d77be8b

📥 Commits

Reviewing files that changed from the base of the PR and between 0e854af and 8fd0fb6.

📒 Files selected for processing (1)
  • otdf-sdk-mgr/src/otdf_sdk_mgr/resolve.py
📝 Walkthrough

Walkthrough

Two new internal helpers, _ref_specificity and _classify_sha_match, are added to resolve.py to rank git ref types by priority and convert matched (sha, ref) pairs into structured ResolveSuccess results. The SHA disambiguation loop in _resolve_against is replaced with a single deterministic selection using _ref_specificity. Two new tests validate merge-queue and branch ref resolution paths.

Changes

SHA Ref Classification and Disambiguation

Layer / File(s) Summary
Ref specificity ranking and SHA match classification
otdf-sdk-mgr/src/otdf_sdk_mgr/resolve.py
_ref_specificity ranks PR refs > merge-queue refs > other refs. _classify_sha_match maps a (sha, ref) pair to a ResolveSuccess with a normalized filesystem-safe tag, head=True, and an optional pr number. _resolve_against drops the old multi-tag disambiguation loop (and its ambiguity error path) in favor of selecting the single most-specific ref via _ref_specificity then calling _classify_sha_match.
TestResolveSHA: merge-queue and branch ref cases
otdf-sdk-mgr/tests/test_resolve.py
Adds two test methods: one checks that a merge-queue ref produces tag="mq-main-3630", pr="3630", and head=True; another checks that refs/heads/feature/my-branch produces tag="feature--my-branch" and head=True.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 A SHA came in, refs all in a heap,
Which one to pick? The queue? The branch? So deep!
I sorted by specificity — PR wins the race,
Then flattened the slashes with a -- in their place.
Now every merge-queue gets its mq- tag neat,
No ambiguity errors — resolution complete! 🎉

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title references 'xtest' and 'merge_group events' but the PR primarily focuses on fixing SHA resolution logic for merge-queue refs in the resolve module, affecting the broader SDK version resolution system. Consider a title that more directly reflects the core fix: normalizing merge-queue/PR ref resolution and setting the head flag correctly. E.g., 'fix: Normalize merge-queue and PR refs in SHA resolution' or similar.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-mq-paths

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dmihalcik-virtru dmihalcik-virtru changed the title Fix merge-queue SHA resolution producing unbuildable dist paths fix(xtest): Fixes unbuildable dist paths on merge-queue events Jun 22, 2026
@dmihalcik-virtru dmihalcik-virtru changed the title fix(xtest): Fixes unbuildable dist paths on merge-queue events fix(xtest): Fixes unbuildable dist paths on merge_group events Jun 22, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the SHA matching logic in resolve.py by extracting helper functions _ref_specificity and _classify_sha_match to handle both single- and multi-match SHA lookups consistently. It also adds unit tests to verify merge-queue and branch resolution. The review feedback highlights an unreachable fallback block in the merge-queue regex handling and suggests using removeprefix instead of split for safer and more idiomatic string manipulation when stripping prefixes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread otdf-sdk-mgr/src/otdf_sdk_mgr/resolve.py Outdated
Comment thread otdf-sdk-mgr/src/otdf_sdk_mgr/resolve.py Outdated
Comment thread otdf-sdk-mgr/src/otdf_sdk_mgr/resolve.py Outdated
Per Gemini review on #532: MERGE_QUEUE_REGEX requires both named groups,
so the to_branch/pr_number truthiness check and its fallback were dead
code. Also switch ref-prefix stripping from split(...)[-1] to
removeprefix() for clarity and safety.
@github-actions

Copy link
Copy Markdown

X-Test Failure Report

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes SDK version resolution for merge_group (merge-queue) events so SHA-based refs resolve to filesystem-safe dist tags and are correctly flagged as head, ensuring the Go CLI is built from source instead of looking for an unbuilt nested dist/refs/heads/... path.

Changes:

  • Refactors SHA match handling in resolve.py into _classify_sha_match() and _ref_specificity() and routes SHA lookups through the shared logic for both single- and multi-match cases.
  • Prioritizes refs when multiple point at the same SHA (PR > merge-queue > other) and consistently marks branch-like refs as head.
  • Adds regression tests for single-match merge-queue and single-match branch SHAs.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
otdf-sdk-mgr/src/otdf_sdk_mgr/resolve.py Normalizes SHA→ref resolution and prioritizes PR/merge-queue refs; ensures merge-queue SHA refs produce safe dist tags and head=true.
otdf-sdk-mgr/tests/test_resolve.py Adds tests covering single-ref merge-queue and single-branch SHA resolution behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread otdf-sdk-mgr/src/otdf_sdk_mgr/resolve.py
The refs/tags branch of _classify_sha_match could return a namespaced
tag with a remaining slash, contradicting the docstring's filesystem-safe
promise and risking a nested dist/<tag>/ path. Flatten it (no-op for
plain semver tags).
@github-actions

Copy link
Copy Markdown

X-Test Failure Report

@dmihalcik-virtru
dmihalcik-virtru merged commit 5bf87b0 into main Jun 23, 2026
21 checks passed
@dmihalcik-virtru
dmihalcik-virtru deleted the fix-mq-paths branch June 23, 2026 13:38
@sonarqubecloud

Copy link
Copy Markdown

dmihalcik-virtru added a commit that referenced this pull request Jun 23, 2026
## Problem

Follow-up to #532. xtest still fails during go CLI setup, now on
**push-to-main** events from `opentdf/platform`, as in [this example
failure](https://github.com/opentdf/platform/actions/runs/28032142207/job/82975485936):

```
FileNotFoundError: SDK executable not found at path: sdk/go/dist/HEAD/cli.sh
```

The matrix value was `go@HEAD` and only `main` got built.

## Root cause

The platform caller passes the go ref as the main-tip commit **SHA**
(`otdfctl-ref: <sha> main`). On a push to main, `git ls-remote` lists
that SHA under **two** refs:

```
<sha>	HEAD
<sha>	refs/heads/main
```

`_ref_specificity` scored every non-PR/non-merge-queue ref equally
(`2`), so `min()` kept the **first** entry — the symbolic `HEAD`. That
fell through `_classify_sha_match` to the generic tag path, producing
`tag = "HEAD"` with no `head` flag. So `setup-cli-tool` skipped the
source build (only `main`, separately resolved as a head, was built) and
the test looked for the non-existent `dist/HEAD/cli.sh`.

## Fix

Rank real refs above the bare `HEAD`: **PR > merge-queue > branch > tag
> other**. Now `refs/heads/main` wins over `HEAD`, giving `tag =
"main"`, `head = true` (built from source).

Branch is deliberately ranked **above** tag: the SHA path always
resolves a commit-under-test, and only the branch case sets `head=true`.
So a commit that is simultaneously a branch tip and a release tag (e.g.
right after release-please) still gets a source build rather than
resolving to a tag that wouldn't be built.

## Testing

- Added `test_head_and_branch_prefers_branch` and
`test_branch_preferred_over_tag`.
- `uv run pytest` — 137 pass.
- `uv run ruff check .`, `uv run ruff format .`, `uv run pyright` —
clean.
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.

3 participants