feat: add 'uvbox git' subcommand for git repository sources (#19)#22
feat: add 'uvbox git' subcommand for git repository sources (#19)#22hasansezertasan wants to merge 18 commits into
Conversation
|
Gonna have a look tomorrow! |
Don't hurry, it's still in draft 🤓. |
…behavior - Surface all three source subcommands (pypi/wheel/git) in Basic Usage so readers don't need to scroll to discover git support. - Use the real VaasuDevanS/cowsay-python repo in git command examples so they are copy-paste runnable against examples/git/simple-app.toml. - Generalise [package].name / script reference docs: they apply to all source types, and for git the name must match the distribution name the repo's pyproject.toml registers (not the repo slug). - Clarify auto-update semantics for git builds: always-update behavior only holds when [package.version] is unset; pinning static/dynamic to the installed version disables it via the version-compare short-circuit in box/main.go. - Disambiguate Examples list entries by including the directory prefix (both simple-app.toml files were rendering with identical link text). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Propagate constraints-file download error instead of swallowing at Debug - Extract selectInstallMethod pure helper; reject git+wheels conflict at both build time (boxer preRun) and runtime (box dispatch) - uvToolInstallGit now takes packageVersion and warns when non-empty, so users who set [package.version].static on a git build get a visible breadcrumb instead of silent ignore - Capture uv stdout into a buffer in uvToolInstallGit and include it in the returned error, preserving resolver/auth context on failure - Deepen validateGitSource with net/url parsing: reject prefix-only, scheme typos, unsupported schemes, and missing host - Add TestSelectInstallMethod dispatch matrix, malformed-spec validator cases, and a no-op guard test for validateGitSourceFlag - Reconcile README [package.version] section with actual dispatch flow, add golden-hash regeneration recipe, and trim duplicated comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
I pushed quickly today to get this PR ready. I'm not actively working with Go day-to-day — I put this together by reading through the surrounding code and iterating with an AI agent. There may be edge cases I missed, so I'd really appreciate a careful review. Thanks again! |
…behavior - Surface all three source subcommands (pypi/wheel/git) in Basic Usage so readers don't need to scroll to discover git support. - Use the real VaasuDevanS/cowsay-python repo in git command examples so they are copy-paste runnable against examples/git/simple-app.toml. - Generalise [package].name / script reference docs: they apply to all source types, and for git the name must match the distribution name the repo's pyproject.toml registers (not the repo slug). - Clarify auto-update semantics for git builds: always-update behavior only holds when [package.version] is unset; pinning static/dynamic to the installed version disables it via the version-compare short-circuit in box/main.go. - Disambiguate Examples list entries by including the directory prefix (both simple-app.toml files were rendering with identical link text). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Propagate constraints-file download error instead of swallowing at Debug - Extract selectInstallMethod pure helper; reject git+wheels conflict at both build time (boxer preRun) and runtime (box dispatch) - uvToolInstallGit now takes packageVersion and warns when non-empty, so users who set [package.version].static on a git build get a visible breadcrumb instead of silent ignore - Capture uv stdout into a buffer in uvToolInstallGit and include it in the returned error, preserving resolver/auth context on failure - Deepen validateGitSource with net/url parsing: reject prefix-only, scheme typos, unsupported schemes, and missing host - Add TestSelectInstallMethod dispatch matrix, malformed-spec validator cases, and a no-op guard test for validateGitSourceFlag - Reconcile README [package.version] section with actual dispatch flow, add golden-hash regeneration recipe, and trim duplicated comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
a38fe58 to
edc2339
Compare
There was a problem hiding this comment.
I am starting to review. First thank for this PR, looking at it, I am just currently working on improving CI and tests, and fix the wheels issue your PR mentionned (really appreciate the catch).
Goal is to fix the issues that are bothering your PR so that we can have a good base.
…behavior - Surface all three source subcommands (pypi/wheel/git) in Basic Usage so readers don't need to scroll to discover git support. - Use the real VaasuDevanS/cowsay-python repo in git command examples so they are copy-paste runnable against examples/git/simple-app.toml. - Generalise [package].name / script reference docs: they apply to all source types, and for git the name must match the distribution name the repo's pyproject.toml registers (not the repo slug). - Clarify auto-update semantics for git builds: always-update behavior only holds when [package.version] is unset; pinning static/dynamic to the installed version disables it via the version-compare short-circuit in box/main.go. - Disambiguate Examples list entries by including the directory prefix (both simple-app.toml files were rendering with identical link text). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Propagate constraints-file download error instead of swallowing at Debug - Extract selectInstallMethod pure helper; reject git+wheels conflict at both build time (boxer preRun) and runtime (box dispatch) - uvToolInstallGit now takes packageVersion and warns when non-empty, so users who set [package.version].static on a git build get a visible breadcrumb instead of silent ignore - Capture uv stdout into a buffer in uvToolInstallGit and include it in the returned error, preserving resolver/auth context on failure - Deepen validateGitSource with net/url parsing: reject prefix-only, scheme typos, unsupported schemes, and missing host - Add TestSelectInstallMethod dispatch matrix, malformed-spec validator cases, and a no-op guard test for validateGitSourceFlag - Reconcile README [package.version] section with actual dispatch flow, add golden-hash regeneration recipe, and trim duplicated comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
edc2339 to
f4e01f5
Compare
f4e01f5 to
81db866
Compare
- Revert constraints download to non-fatal logger.Debug (optional file) - Unify log messages: "Installing package" with "method" key (pypi/git) - Match uvToolInstallGit stdout/error handling to uvToolInstallLine pattern Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extracts ldflag construction into a pure, testable function and adds validateGitSource to enforce the git+ prefix constraint. Regression tests lock in pypi and wheel ldflag output; new tests cover git source injection behavior. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oBuild - Replace inline ldflags construction in goBuild with buildGoBuildLdflags(GitSource, WheelsToEmbed) - Add GitSource package-level var alongside Config/Output/Nfpm/ReleaseVersion - Register gitCmd cobra subcommand (ExactArgs(1), same flags as pypiCmd/wheelCmd) - Add validateGitSourceFlag helper, called from preRun Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The smoke test surfaced a pre-existing bug in boxer's ldflag handling: Go's GOFLAGS parser uses strings.Fields (whitespace split, no quote handling), so any ldflag string containing -X flags fails to parse with "unknown flag -X". This silently broke the wheel path in commit f19680f when ldflags moved to GOFLAGS for Windows compatibility, and would have broken git the same way. To unblock the git feature without touching the wheel path (which remains broken in main and needs a separate fix), embed the git source via a committed placeholder file box/git_source.txt + //go:embed in box/box_package_git.go. boxer writes the git spec into this file before go build via writeGitSourceFile, replacing the empty placeholder for git builds and leaving it empty for pypi/wheel builds. This sidesteps GOFLAGS entirely for git. The wheel path's GOFLAGS bug is left untouched and should be addressed in a separate PR by the original author of f19680f, who can verify the Windows fix properly. Verified end-to-end: uvbox git git+https://github.com/VaasuDevanS/cowsay-python --darwin --arm ./dist/cowsay -t "uvbox git works!" # prints cow ✓ ./cowsay self update # "Already up-to-date" ✓ ./cowsay self path # cowsay-637049bd... ✓ uvbox pypi (regression) # cowsay-2fea8a21... ✓ different dir Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Match the existing wheels/placeholder pattern: gitignore the dynamically generated file and create it on demand via go generate. Keeps the box package free of empty committed files and lets `mise run generate:box` handle bootstrapping for tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use the VaasuDevanS/cowsay-python repo in examples/git/simple-app.toml so the example is runnable as-is, and add a git entry to the README examples list next to the existing pypi entry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…behavior - Surface all three source subcommands (pypi/wheel/git) in Basic Usage so readers don't need to scroll to discover git support. - Use the real VaasuDevanS/cowsay-python repo in git command examples so they are copy-paste runnable against examples/git/simple-app.toml. - Generalise [package].name / script reference docs: they apply to all source types, and for git the name must match the distribution name the repo's pyproject.toml registers (not the repo slug). - Clarify auto-update semantics for git builds: always-update behavior only holds when [package.version] is unset; pinning static/dynamic to the installed version disables it via the version-compare short-circuit in box/main.go. - Disambiguate Examples list entries by including the directory prefix (both simple-app.toml files were rendering with identical link text). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
uv shells out to the system git binary when resolving git+ sources, so binaries produced by 'uvbox git' need git installed on the end-user machine at first run (or whenever auto-update re-installs). Also call out that ssh:// specs use the user's local SSH setup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Propagate constraints-file download error instead of swallowing at Debug - Extract selectInstallMethod pure helper; reject git+wheels conflict at both build time (boxer preRun) and runtime (box dispatch) - uvToolInstallGit now takes packageVersion and warns when non-empty, so users who set [package.version].static on a git build get a visible breadcrumb instead of silent ignore - Capture uv stdout into a buffer in uvToolInstallGit and include it in the returned error, preserving resolver/auth context on failure - Deepen validateGitSource with net/url parsing: reject prefix-only, scheme typos, unsupported schemes, and missing host - Add TestSelectInstallMethod dispatch matrix, malformed-spec validator cases, and a no-op guard test for validateGitSourceFlag - Reconcile README [package.version] section with actual dispatch flow, add golden-hash regeneration recipe, and trim duplicated comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Revert constraints download to non-fatal logger.Debug (optional file) - Unify log messages: "Installing package" with "method" key (pypi/git) - Match uvToolInstallGit stdout/error handling to uvToolInstallLine pattern Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
81db866 to
d646f8c
Compare
Thanks for the review. I addressed your comments. Can you take a look at it again 🤓? |
|
Remains only to fix the wheel issue you reported on my side! |
Closes #19.
Summary
Adds a new
uvbox git <git-spec>subcommand alongside the existingpypiandwheelsource types. The git spec is passed through touv tool install --fromverbatim, so any formuvaccepts works (@main,@v1.0.0,@<commit>,ssh://, etc.).Implements the approach @Coruscant11 chose in this comment: subcommand with the git spec as a positional CLI argument, no changes to the
uvbox.tomlschema.When the outer version check decides to install/update,
uvToolInstallGitrunsuv tool install --from <spec> <name> --upgrade.auto-update = truewith no[package.version]set re-enters that path on every run (the version compare treats the unset case as always-stale), delivering thepycrucible delete_after_run-equivalent behavior the issue requested. If a user sets[package.version].staticon a git build, a user-visible warning is logged because the git ref is the source of truth.Design notes
box/config_identifier_test.golocks in a byte-stable golden hash forComputeIdentifierto guarantee existing binaries find the same XDG dir.ComputeIdentifier(only when set), so binaries built fromgit+url@mainandgit+url@v1.0.0get separate isolated install dirs. No cross-contamination with pypi-built binaries of the same package.git+, the URL after the prefix must parse, the scheme must be one ofhttp/https/ssh/file, and non-file schemes must have a host. Semantic ref resolution (branch/tag/commit existence) is still delegated touvon first run.boxerpreRun) and runtime (pureselectInstallMethodhelper inbox/box_package.goreturns an error when bothGIT_SOURCEandINSTALL_WHEELSare set).Pre-existing bug discovered (and worked around)
The original spec proposed embedding the git source via
-ldflags "-X main.GIT_SOURCE=...". The smoke test surfaced that this does not work because of a pre-existing bug introduced in #14 (commit f19680f, "fix: Use environment variables for ldflags"):This silently broke the
uvbox wheelpath in main since #14 was merged — it sets-X main.INSTALL_WHEELS=yes, which fails the same way. No test exercises wheel mode end-to-end so nobody noticed. Reproduction:This PR does not fix the wheel bug — touching it requires re-validating the original Windows-via-uvx fix from #14 on Windows, which is out of scope here. The wheel path remains broken in main and should be addressed in a separate PR.
For git, this PR sidesteps GOFLAGS entirely by embedding the source in a small file (
box/git_source.txt) read at compile time via//go:embed. boxer'swriteGitSourceFilewrites the spec into this file beforego build. Empty file = pypi/wheel build, non-empty = git build. Same end result, different transport.Files
Runtime (
box/):box/box_package_git.go(new) —GIT_SOURCE(loaded from embeddedgit_source.txt),uvToolInstallGit(acceptspackageVersionfor signature parity, warns and drops it since the git ref is authoritative; capturesuvstdout into the returned error on failure),buildUvToolInstallFromArgspure helperbox/box_package.go— pureselectInstallMethod(gitSource, installWheels)helper dispatches to pypi/wheels/git; rejects the git+wheels combination at runtime.InstallPackagenow propagatesdownloadTemporaryFileerrors instead of swallowing them atDebuglevel (pre-existing silent failure fixed while on the hot path)box/config.go—ComputeIdentifierconditionally appendsGIT_SOURCE(no-op when empty)box/generate.go— adds emptygit_source.txtplaceholder generation, mirroring the existingwheels/placeholderpatternbox/config_identifier_test.go(new) — golden-hash regression test (with regeneration recipe) + git distinction testsbox/box_package_git_test.go(new) — pure-helper command-shape testsbox/box_package_test.go(new) —TestSelectInstallMethoddispatch matrix (pypi/wheels/git × default/conflict)Build-time (
boxer/):boxer/git.go(new) —buildGoBuildLdflagspure helper (without git, since git uses file embed),validateGitSource(URL-parsing, scheme whitelist, host check),writeGitSourceFileboxer/main.go— newgitCmdcobra command,GitSourceCLI var,validateGitSourceFlagin preRun (also enforces mutual exclusion withWheelsToEmbedand prints helpful hints on invalid input),writeGitSourceFilecall ininsertFilesIntoBoxRepositoryboxer/git_test.go(new) — ldflag regression tests for pypi/wheel,writeGitSourceFiletests,validateGitSourcepositive cases,TestValidateGitSource_RejectsMalformed(scheme typos, prefix-only, missing host),TestValidateGitSourceFlag_EmptyIsNoop(guards the "pypi/wheel builds unaffected" contract)Docs:
README.md— feature bullet updated, new "Build from a Git Repository" section, behavior of[package.version]for git builds, private repo auth note, runtimegitrequirementexamples/git/simple-app.toml(new) — minimal runnable example usingVaasuDevanS/cowsay-python.gitignore— addsbox/git_source.txtTest Plan
boxtest suite passes (go test ./...) including theComputeIdentifiergolden-hash regression guard and the newselectInstallMethoddispatch matrixboxertest suite passes including ldflag regression guards for the existing pypi/wheel paths and the newvalidateGitSourceURL-parsing casesgo vet ./...clean in both modulesuvbox git git+https://github.com/VaasuDevanS/cowsay-python --darwin --armbuilds, the resulting binary runs end-to-end (./cowsay -t "hi"prints the cow),self updatereports "Already up-to-date",self pathshows a git-distinct identifieruvbox pypistill works, produces a different identifier hash (separate XDG dir from the git build of the same package)Reviewers can reproduce the smoke test using the committed example config:
See
examples/git/simple-app.tomlfor the config, including the commented-out[package.version] auto-update = trueblock that flips the binary into "always re-resolve the git ref on every run" mode.Update — review round 1 (commit a38fe58)
Addressed findings from a multi-agent PR review pass. All changes are additive to the original design:
InstallPackage, now on the git hot path)GIT_SOURCE + INSTALL_WHEELSconflict at build time (boxer preRun) and runtime (selectInstallMethod)[package.version]is set on a git build —uvToolInstallGitlogslogger.Warninstead of silently ignoringuvstdout into error messages on git install failure, so resolver/auth output isn't discardedvalidateGitSourcewithnet/urlparsing — reject scheme typos, unsupported schemes, and missing hosts at build time instead of on end-user machinesbox/box_package_test.go(dispatch matrix) and expandedboxer/git_test.go(malformed-spec cases + empty-flag no-op guard)[package.version]section, golden-hash regeneration recipe, trimmed duplicated inline comments🤖 Generated with Claude Code