Fix devbox update not refreshing locked revs for flake refs#2825
Open
Lagoja wants to merge 3 commits intojetify-com:mainfrom
Open
Fix devbox update not refreshing locked revs for flake refs#2825Lagoja wants to merge 3 commits intojetify-com:mainfrom
Lagoja wants to merge 3 commits intojetify-com:mainfrom
Conversation
`devbox update` on a flake ref (e.g. `github:owner/repo#attr`) never moved the locked rev forward. The dispatch in `Update` routed unversioned packages to `attemptToUpgradeFlake`, which ran `nix profile upgrade` — a no-op once devbox's lockfile had already pinned the rev. Re-adding the package worked only because the Add path re-resolves via `FetchResolvedPackage`. Route flake refs through the same lockfile-resolution pipeline as versioned nixpkgs packages, and add a flake-aware branch to `mergeResolvedPackageToLockfile` since flake refs have no Version. Errors in the flake branch are non-fatal (warn + continue) to preserve the forgiving contract from jetify-com#1180 / jetify-com#1840 — one broken ref should not abort update for the rest. Also thread a `refresh bool` through `ResolveFlake`, `lockFlake`, and `FetchResolvedPackage` so the update path passes `--refresh` to `nix flake metadata`. Without it, nix's own eval/tarball cache can serve a stale result (observed: a 10-hour-old commit even after the dispatch fix). Other callers (Add, install, outdated checks) pass `false` and keep using the cache. User-facing message: Info: Updating github:numtide/llm-agents.nix#claude-code 92de4ac -> 8ff0f2a (2026-04-24 → 2026-04-24) Affects both `devbox update` and `devbox global update` — same code path. Removes `attemptToUpgradeFlake` and its `nix.ProfileUpgrade` / `nixprofile.ProfileUpgrade` helpers (no remaining callers).
Splits the per-package dispatch loop out of Update() so golangci-lint's revive/cognitive-complexity check passes (was 34, threshold 32). No behavior change.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes devbox update for flake refs so that updating a flake reference (e.g. github:owner/repo#attr) actually advances the locked revision in devbox.lock, using a flake-aware lockfile merge path and a --refresh metadata resolution option to avoid stale Nix cache results.
Changes:
- Route flake refs through the normal lockfile resolution/merge pipeline and compare updates via
Resolved(andLastModified) instead ofVersion. - Thread a
refreshboolean through flake resolution sodevbox updatecan pass--refreshtonix flake metadata. - Remove the old
nix profile upgrade-based flake update code path and add regression coverage for flake-update formatting/behavior.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| testscripts/update/update_flake_local.test.txt | Adds regression test ensuring local path: flake update doesn’t warn/fail. |
| internal/nix/nixprofile/upgrade.go | Removes profile-upgrade helper (no longer used). |
| internal/nix/flake_update.go | Removes ProfileUpgrade wrapper around nix profile upgrade. |
| internal/nix/flake.go | Adds refresh parameter to ResolveFlake and passes --refresh when requested. |
| internal/lock/resolve.go | Adds refresh plumbing to flake resolution (FetchResolvedPackage / lockFlake). |
| internal/lock/lockfile.go | Updates call sites for new FetchResolvedPackage(pkg, refresh) signature. |
| internal/devbox/update_test.go | Adds tests for flake lockfile merging and update message formatting helpers. |
| internal/devbox/update.go | Updates flake update flow to rewrite lock entries; adds flake-specific merge and messaging. |
| internal/devbox/packages.go | Updates outdated-check path for new FetchResolvedPackage signature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The lexicographic staleness check would trigger whenever resolved.LastModified was empty (some nix error paths omit it), since any non-empty string sorts after "". That wrongly blocked legit updates when the existing lock had a populated timestamp. Skip the guard unless both sides have a value — missing == unknown, not older. Addresses Copilot review feedback on jetify-com#2825.
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.
Problem Summary
When running
devbox updateon a package added via flake reference, the package stays pinned to the original commit hash when it was added (in other words,updatedoesn't work). The hash is only advanced when you remove and re-add the package.devbox updatenow refreshes the locked commit of flake references, matching how it already works for versioned packages. Under the hood, it re-resolves the flake against the upstream source (with --refresh so nix doesn't hand back a stale cache) and rewrites the lockfile entry to the new commit. A broken ref still prints a warning instead of aborting the whole update, so one bad flake won't block the rest of the packages from updating.Summary
devbox updateon a flake ref (e.g.github:owner/repo#attr) now actually advances the locked rev. Previously the dispatch routed unversioned packages toattemptToUpgradeFlake(→nix profile upgrade), which is a no-op once devbox's lockfile has pinned the rev — the only way to get a newer commit was to remove and re-add the package.FetchResolvedPackagepipeline as versioned nixpkgs packages, with a flake-aware branch inmergeResolvedPackageToLockfilethat compares onResolved(since flakes carry noVersion).refresh boolis threaded throughResolveFlake/lockFlake/FetchResolvedPackageso the update path passes--refreshtonix flake metadata. Without this, nix's own eval/tarball cache can still serve stale results on the update path (observed: a 10-hour-old commit). Add, install, and outdated-check callers keep using the cache.attemptToUpgradeFlake,nix.ProfileUpgrade, andnixprofile.ProfileUpgradeare removed (no remaining callers).User-visible message
Falls back gracefully for refs without a git rev (e.g.
path:): shows the date range only. Falls back to rev-only ifLastModifiedis missing.Scope
Affects
devbox updateanddevbox global update— they share this code path, and both were affected by the bug.Test plan
go build ./...andgo vet ./...cleango test ./internal/...— all pass, including 6 new tests coveringmergeResolvedFlakeToLockfile,shortRev,shortDate, anddescribeFlakeUpdatego test ./testscripts -run TestScripts/update— both the pre-existingupdate.test(nixpkgs) and the newupdate_flake_local.test(localpath:flake) passnix build .#defaultproduces a working binarygithub:numtide/llm-agents.nix#claude-codeindevbox.lock, randevbox update, and saw the rev advance with the expected message format