Skip to content

fix: improve release fetching#964

Merged
gregmagolan merged 1 commit intomainfrom
release_fetch_fixes
Apr 14, 2026
Merged

fix: improve release fetching#964
gregmagolan merged 1 commit intomainfrom
release_fetch_fixes

Conversation

@gregmagolan
Copy link
Copy Markdown
Member

@gregmagolan gregmagolan commented Mar 13, 2026

Currently the release fetcher fails if it finds a release without any assets. This is possible is you happen to check the latest release mid-release when it doesn't have any assets yet. This improves the code so that it falls back to the latest release that has an asset to download when searching.

Before

The GitHub source handler had a single code path for both pinned and unpinned versions:

  1. Compute tag as v{version} — for unpinned, version was always the launcher's own compiled-in version
  2. Query the GitHub API for that specific release: GET /repos/{org}/{repo}/releases/tags/{tag}
  3. Find the matching artifact in the response's assets array
  4. Download via the API asset URL (api.github.com/.../assets/{id})

Problems:

  • The Release struct required the assets field, but GitHub sometimes omits it → missing field 'assets' deserialization error
  • Unpinned versions were tied to the launcher's compiled-in version rather than discovering the latest available release
  • No handling for the release-in-progress window where a tag exists but assets haven't been uploaded yet
  • A version_pinned boolean was threaded through ToolSpec / AspectCliConfig but both paths used the same download logic

After

The GitHub source handler is now split into two clean steps — resolve, then download:

Step 1 — Resolve the tag:

  • Pinned (version = Some("2026.11.6") from version.axl): compute the tag directly (e.g. v2026.11.6). No API call.
  • Unpinned (version = None — no version.axl, or version() with no positional arg): query GET /repos/{org}/{repo}/releases?per_page=10, scan the most recent releases, and pick the first one whose assets contain the matching artifact.

Step 2 — Download using the resolved tag:

Both paths now have a concrete tag and use the same direct download URL:
https://github.com/{org}/{repo}/releases/download/{resolved_tag}/{artifact}

What this fixes:

  • assets now has #[serde(default)], so releases with missing or empty assets are skipped instead of causing a deserialization error
  • Unpinned versions discover the latest available release instead of guessing based on the launcher's compiled-in version
  • The release-in-progress window is handled gracefully — releases without the matching artifact are skipped in favor of the next one
  • The version_pinned boolean is removed; version: Option<String> on ToolSpec naturally encodes the distinction (Some = pinned, None = resolve from API)
  • The cache key is now based on the direct download URL (which includes the resolved tag), so different versions cache independently

@gregmagolan gregmagolan force-pushed the release_fetch_fixes branch 2 times, most recently from affe055 to 1fdcdbe Compare March 15, 2026 22:54
@gregmagolan gregmagolan force-pushed the release_fetch_fixes branch from 1fdcdbe to 8d5a86f Compare March 31, 2026 01:27
@gregmagolan gregmagolan force-pushed the release_fetch_fixes branch 2 times, most recently from 26a39ae to 5b0a53c Compare April 13, 2026 23:05
@gregmagolan gregmagolan marked this pull request as ready for review April 13, 2026 23:06
@gregmagolan gregmagolan force-pushed the release_fetch_fixes branch 2 times, most recently from ab390f5 to 7795f34 Compare April 13, 2026 23:09
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5b0a53c887

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread crates/aspect-launcher/src/main.rs
@gregmagolan gregmagolan force-pushed the release_fetch_fixes branch from 7795f34 to 39461a6 Compare April 13, 2026 23:22
@gregmagolan gregmagolan requested a review from thesayyn April 13, 2026 23:23
@gregmagolan
Copy link
Copy Markdown
Member Author

aspect-launcher manual test results

Tested on: macOS (aarch64-apple-darwin), cargo run -p aspect-launcher from HEAD.

Setup

export ASPECT_CLI_DOWNLOADER_CACHE=/tmp/aspect-test-cache
export ASPECT_DEBUG=1

All tests run from a directory with no version.axl (unpinned tests) or a
purpose-built temp workspace (pinned tests), using
cargo run --manifest-path /path/to/Cargo.toml -p aspect-launcher to exercise
the binary built from HEAD.


Test 1 — Unpinned first run: queries releases API, downloads stable release

rm -rf /tmp/aspect-test-cache
mkdir /tmp/axl-test && cd /tmp/axl-test
ASPECT_DEBUG=1 ASPECT_CLI_DOWNLOADER_CACHE=/tmp/aspect-test-cache \
  cargo run --manifest-path ... -p aspect-launcher -- version

Expected: queries API, skips prereleases, downloads latest stable release.

Result:

aspect-cli unpinned, querying releases API (no hint cached)
aspect-cli source GitHub {...} querying releases from "https://api.github.com/repos/aspect-build/aspect-cli/releases?per_page=10"
aspect-cli source GitHub {...} downloading "https://github.com/aspect-build/aspect-cli/releases/download/v2026.15.2/aspect-cli-aarch64-apple-darwin" ...
downloading aspect cli version v2026.15.2 file aspect-cli-aarch64-apple-darwin
33281 / 33281 KB (100%)
2026.15.2

Resolved v2026.15.2 (stable), skipped prerelease/main.


Test 2 — Unpinned warm cache: no API call

Same command, second run.

Expected: fresh hint + cached binary → no network call.

Result:

aspect-cli source GitHub {...} found in cache "https://github.com/aspect-build/aspect-cli/releases/download/v2026.15.2/aspect-cli-aarch64-apple-darwin" (resolved tag: v2026.15.2)
2026.15.2

No querying releases line. Binary served entirely from cache.


Test 3 — Stale hint: re-queries API, reuses cached binary

touch -t "$(date -v-25H +%Y%m%d%H%M)" /tmp/aspect-test-cache/launcher/latest/*

Expected: hint older than 24h → re-queries API, finds same version, hits binary cache (no re-download).

Result:

aspect-cli unpinned, querying releases API (hint is stale)
aspect-cli source GitHub {...} querying releases from "https://api.github.com/repos/aspect-build/aspect-cli/releases?per_page=10"
aspect-cli source GitHub {...} found in cache "https://github.com/aspect-build/aspect-cli/releases/download/v2026.15.2/aspect-cli-aarch64-apple-darwin"
2026.15.2

Stale hint triggered API re-query; binary was already cached so no download.
Hint mtime was reset for the next 24h window.


Test 4 — API failure with stale hint: falls back to cached binary

touch -t "$(date -v-25H +%Y%m%d%H%M)" /tmp/aspect-test-cache/launcher/latest/*
GITHUB_TOKEN=invalid ...

Expected: stale hint + API 401 → fall back to cached binary, reset hint expiry.

Result:

aspect-cli unpinned, querying releases API (hint is stale)
aspect-cli API error, falling back to stale cached tag prerelease/main ({
  "message": "Bad credentials",
  "documentation_url": "https://docs.github.com/rest",
  "status": "401"
})
2026.15.2

Launched successfully from cached binary. API error body surfaced in debug output.
Hint mtime reset so the next retry is deferred by another 24h.


Test 5 — Pinned version: direct download, no API call

mkdir -p /tmp/axl-test-pinned/.aspect
printf 'version("2026.15.2")\n' > /tmp/axl-test-pinned/.aspect/version.axl
touch /tmp/axl-test-pinned/MODULE.bazel
cd /tmp/axl-test-pinned

Expected: pinned tag computed directly, no API call, downloads v2026.15.2.

Result:

aspect-cli pinned to tag "v2026.15.2", skipping API
aspect-cli source GitHub {...} downloading "https://github.com/aspect-build/aspect-cli/releases/download/v2026.15.2/aspect-cli-aarch64-apple-darwin" ...
downloading aspect cli version v2026.15.2 file aspect-cli-aarch64-apple-darwin
33281 / 33281 KB (100%)
2026.15.2

Test 5 (re-run) — Pinned version: cache hit

Same command, second run.

Expected: same pinned tag → cache hit, no download, no API call.

Result:

aspect-cli pinned to tag "v2026.15.2", skipping API
aspect-cli source GitHub {...} found in cache "https://github.com/aspect-build/aspect-cli/releases/download/v2026.15.2/aspect-cli-aarch64-apple-darwin"
2026.15.2

Note: the pinned and unpinned runs share the same cached binary when they resolve
to the same tag — confirmed by identical cache paths in both cases.

@gregmagolan gregmagolan force-pushed the release_fetch_fixes branch 3 times, most recently from a98b1ce to fdbb3df Compare April 13, 2026 23:57
@gregmagolan gregmagolan force-pushed the release_fetch_fixes branch from fdbb3df to 1148d4d Compare April 14, 2026 00:47
@gregmagolan gregmagolan merged commit 8fec9cd into main Apr 14, 2026
14 checks passed
@gregmagolan gregmagolan deleted the release_fetch_fixes branch April 14, 2026 00:54
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.

2 participants