feat(upload): print a short link to the upload when a collection id is passed - #1168
Merged
Conversation
|
😎 This pull request was merged. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1168 +/- ##
==========================================
+ Coverage 83.07% 83.36% +0.28%
==========================================
Files 72 72
Lines 16313 16359 +46
==========================================
+ Hits 13552 13637 +85
+ Misses 2761 2722 -39 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
TylerJang27
marked this pull request as draft
August 26, 2026 02:40
TylerJang27
marked this pull request as ready for review
August 26, 2026 20:29
acatxnamedvirtue
approved these changes
Aug 26, 2026
dfrankland
approved these changes
Aug 26, 2026
|
Stacked PR 1169 failed testing in the merge queue. Please investigate the failure and re-submit the stack. |
…s passed The end-of-run "Bundle Upload ID" line becomes a link when the run is in test-collection link mode: 🏷️ Bundle Upload: https://app.trunk.io/{org}/flaky-tests/collections/{short_id}/u/{bundle_meta_id} The webapp resolves the upload's createdAt from the id and redirects to the canonical uploads page (companion PR: trunk-io/trunk2#5440). Unlike the per-test `/t/` links there is no `?repo=` param — the collection short id fully scopes the lookup. Gated exactly as the `/t/` links are: a collection id must be passed and `--hide-test-collection-links` / `TRUNK_HIDE_TEST_COLLECTION_LINKS` must be unset. Otherwise the bare bundle upload id prints as before. The gate reads `test_collection_short_id` rather than `base_props.test_collection.short_id` because an exported-but-blank `TRUNK_TEST_COLLECTION_ID` is `Some("")`, not `None`, and would otherwise produce a malformed `/collections//u/` link. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TylerJang27
added a commit
that referenced
this pull request
Aug 27, 2026
…solve Alternative to the short-link form in #1168, for comparison — see trunk-io/trunk2#5440. The short link carries only the bundle_meta id, so the webapp has to recover `bundle_meta_created_at` before it can address the upload, then redirect. That lookup cannot use `test_collection_upload`'s primary key: it leads with `(test_collection_id, repo_id, bundle_meta_created_at, …)` and a link carries no repo, so with `repo_id` unconstrained the index resolves only the leading column and every granule in the collection becomes a bloom-filter candidate. The 45-day TTL means the query's own 45-day bound prunes almost nothing on top of that. It measures as one granule on staging today only because staging collections fit in one granule. The CLI already has both halves — `CreateBundleUploadResponse` returns `test_collection_bundle_meta_created_at` alongside the id, and both land in the bundle — so it can emit the webapp's canonical `uploads/{bundleMetaKey}` URL directly and skip the lookup and the redirect entirely. Costs, stated plainly: - The printed URL grows from 105 to 170 characters (+62%), which is the tradeoff the short-link design was chosen to avoid. - It makes the CLI a second producer of the `bundleMetaKey` encoding, a frozen contract with `encodeBundleMetaKey` in trunk2. Pinned here by a golden vector generated from that function. Mitigating: `bundleMetaKey` is already a permanent public URL contract the webapp emits, and unlike a hash its drift is visible — it is base64 of a two-field JSON object. Field order and whitespace match `JSON.stringify({ id, createdAt })` byte for byte via a `Serialize` struct rather than a `format!`, so the golden test is meaningful and an id containing a quote cannot break the payload. The webapp's decoder parses JSON and is order-insensitive, so a drift would still resolve — it would just stop matching the string the webapp emits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TylerJang27
force-pushed
the
tyler/collection-upload-short-link
branch
from
August 27, 2026 18:42
ca5d99b to
0eeb6c4
Compare
|
This pull request was merged into |
trunk-io Bot
pushed a commit
that referenced
this pull request
Aug 27, 2026
…solve (#1169) * feat(upload): print the canonical upload link, not a short link to resolve Alternative to the short-link form in #1168, for comparison — see trunk-io/trunk2#5440. The short link carries only the bundle_meta id, so the webapp has to recover `bundle_meta_created_at` before it can address the upload, then redirect. That lookup cannot use `test_collection_upload`'s primary key: it leads with `(test_collection_id, repo_id, bundle_meta_created_at, …)` and a link carries no repo, so with `repo_id` unconstrained the index resolves only the leading column and every granule in the collection becomes a bloom-filter candidate. The 45-day TTL means the query's own 45-day bound prunes almost nothing on top of that. It measures as one granule on staging today only because staging collections fit in one granule. The CLI already has both halves — `CreateBundleUploadResponse` returns `test_collection_bundle_meta_created_at` alongside the id, and both land in the bundle — so it can emit the webapp's canonical `uploads/{bundleMetaKey}` URL directly and skip the lookup and the redirect entirely. Costs, stated plainly: - The printed URL grows from 105 to 170 characters (+62%), which is the tradeoff the short-link design was chosen to avoid. - It makes the CLI a second producer of the `bundleMetaKey` encoding, a frozen contract with `encodeBundleMetaKey` in trunk2. Pinned here by a golden vector generated from that function. Mitigating: `bundleMetaKey` is already a permanent public URL contract the webapp emits, and unlike a hash its drift is visible — it is base64 of a two-field JSON object. Field order and whitespace match `JSON.stringify({ id, createdAt })` byte for byte via a `Serialize` struct rather than a `format!`, so the golden test is meaningful and an id containing a quote cannot break the payload. The webapp's decoder parses JSON and is order-insensitive, so a drift would still resolve — it would just stop matching the string the webapp emits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(upload): pin the key to a verified golden; tighten comments The golden vector now uses a case verified three ways: against a base64 of the literal JSON, against trunk2's own `encodeBundleMetaKey`, and by decoding the Rust output back (byte-identical, field order and no-whitespace included). Confirmed load-bearing — swapping the struct's field order fails it. The three url_for_upload cases shared five identical arguments; they go through one `upload_url(created_at)` helper so each test shows only what it varies. Comments trimmed to the non-obvious parts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The end-of-run
🏷️ Bundle Upload IDline becomes a link when the run is in test-collection link mode:The webapp resolves the upload's
createdAtfrom the id and redirects to the canonical uploads page. No RPC or response changes —CreateBundleUploadResponse.test_collection_bundle_meta_idalready carries the id, andcontext.rsalready threads it ontobase_props.test_collection.Unlike the per-test
/t/links from #1165, there is no?repo=param: the collection short id fully scopes the webapp's lookup, so there is no repo name to resolve.Companion webapp PR (must deploy first, it hosts the redirect page): trunk-io/trunk2#5440
Behavior
--hide-test-collection-links/TRUNK_HIDE_TEST_COLLECTION_LINKS🏷️ Bundle Upload: …/collections/{short_id}/u/{bundle_meta_id}🏷️ Bundle Upload ID: {id}(unchanged)🏷️ Bundle Upload ID: {id}(unchanged)Same gate as #1165, so the one flag controls both link kinds.
Note on the gate
collection_upload_url()readstest_collection_short_idrather thanbase_props.test_collection.short_id. An exported-but-blankTRUNK_TEST_COLLECTION_IDisSome(""), notNone, so the latter yields a malformed/collections//u/…link — the same edge #1165 added a test for. The existingupload_bundle_without_test_collection_id_prints_repo_linkstest caught this.upload_bundle's assertion changed: that test passes--test-collection-id tc_123, so by design it now gets the link rather than the bare id. The bare-id form stays covered by the new links-hidden test.Test plan
cargo test -p api— URL unit test for the new form (20 passing)cargo test -p trunk-analytics-cli— full suite green (53 + 23 + 13 + 9), including 2 new integration tests covering the gate matrix abovecargo fmtapplied;cargo clippyfindings unchanged frommain(5 pre-existing inupload_command.rsbefore and after)🤖 Generated with Claude Code