Skip to content

fix(config): preserve multiple outputs from the same remote flake#2912

Open
mikeland73 wants to merge 2 commits into
mainfrom
claude/focused-goldberg-s4suir
Open

fix(config): preserve multiple outputs from the same remote flake#2912
mikeland73 wants to merge 2 commits into
mainfrom
claude/focused-goldberg-s4suir

Conversation

@mikeland73

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2662.

Adding two outputs from the same remote flake dropped the first one:

"packages": [
  "git+http://git@company.gitlab.com/group/utils.git#kubeupdate",
  "git+http://git@company.gitlab.com/group/utils.git#getcrds"
]

After adding #getcrds, kubeupdate disappeared from the environment (only the
last-added output survived).

Root cause

Config.Packages (internal/devconfig/config.go) dedupes the package list with
lo.UniqBy keyed on Package.Name, keeping only the last occurrence per name so
that a later pkg@v2 replaces an earlier pkg@v1.

For flake references that key is not unique per output. Package strings are
split on their last @ (searcher.ParseVersionedPackage), so:

  • the #fragment that distinguishes the outputs is parsed into the version, and
  • for a URL containing user@host (here git@company.gitlab.com), the Name is
    truncated to the part before the @git+http://git.

So both outputs parse to the same Name (git+http://git) and collapse into a
single package, dropping the first.

Fix

Key the dedup on the full reference (which includes the #fragment) when the
package looks like a flake installable — detected by a :// scheme separator or a
# output fragment — and keep deduping plain packages by name so the existing
"last version wins" behavior for pkg@v1 / pkg@v2 is unchanged.

How was it tested?

  • go build ./... — clean.
  • go vet ./internal/devconfig/ — clean; gofmt reports no changes.
  • New unit tests in internal/devconfig/config_test.go:
    • TestPackagesPreservesMultipleFlakeOutputs — two #-fragment outputs from the
      same git+http://git@host/... flake are both retained (fails before this change,
      passes after).
    • TestPackagesDedupesByNameForPlainPackagespython@3.10 + python@3.11 still
      dedupe to the last occurrence (python@3.11), confirming the plain-package
      behavior is preserved.
  • go test ./internal/devconfig/... passes for the changed code. Two pre-existing
    TestFindError/*Permissions cases fail in this environment because it runs as
    root (a chmod 0o000 file is still readable), independent of this change — they
    fail identically on main.

Note: the end-to-end devbox add/devbox shell flow needs nix, which wasn't
available in the authoring environment; the unit tests exercise the exact dedup
logic that was dropping the flake output.

cc @jDmacD (issue reporter) — thanks for the clear, step-by-step reproduction.

Community Contribution License

All community contributions in this pull request are licensed to the project
maintainers under the terms of the
Apache 2 License.

By creating this pull request, I represent that I have the right to license the
contributions to the project maintainers under the Apache 2 License as stated in
the
Community Contribution License.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Qk7hyZKVoiy6CrUdA6XknT


Generated by Claude Code

Adding two outputs from the same remote flake (for example
`git+http://git@host/repo.git#toolA` and `...#toolB`) dropped the first
one. `Config.Packages` deduped the package list with `lo.UniqBy` keyed on
`Package.Name`, keeping only the last occurrence per name.

For flake references that Name is not unique per output: package strings
are split on their last `@`, so a "#fragment" ends up in the version and,
for URLs containing a `user@host`, the Name is truncated to the part
before the `@`. Every output of such a flake therefore shares the same
Name and collapsed into a single package.

Key the dedup on the full reference (which includes the fragment) when the
package looks like a flake installable — detected by a `://` scheme
separator or a `#` output fragment — and keep deduping plain packages by
name so a later `pkg@v2` still replaces an earlier `pkg@v1`.

Fixes #2662

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qk7hyZKVoiy6CrUdA6XknT
Copilot AI review requested due to automatic review settings July 9, 2026 14:23

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 a regression in Config.Packages() where adding multiple outputs from the same remote flake (distinguished by #fragment) could incorrectly drop earlier entries due to name-based deduplication interacting with user@host URLs.

Changes:

  • Adjust package deduplication to key flake-like references by their full reference (VersionedName()), preserving multiple #fragment outputs from the same flake.
  • Add unit tests covering (1) preserving multiple flake outputs and (2) retaining the existing “last version wins” behavior for plain name@version packages.

Reviewed changes

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

File Description
internal/devconfig/config.go Updates deduplication logic to preserve multiple outputs from the same remote flake reference.
internal/devconfig/config_test.go Adds regression and behavior-preservation tests for the updated deduplication behavior.

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

Comment thread internal/devconfig/config_test.go Outdated
Address review feedback: the length check keyed off a map built from
VersionedName(), which would collapse duplicates and could pass even if
the dedupe logic regressed to returning duplicate packages. Assert on the
returned slice length directly and require each expected package to appear
exactly once.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qk7hyZKVoiy6CrUdA6XknT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

adding a second output from a remote flake overwrites the first

3 participants