Anchor dependency preparation to checkout root
This commit is contained in:
@@ -41,7 +41,11 @@ For binary profiles, call `PrepareBuildDependencies` with a
|
||||
`DependencyPreparationRequest` selecting the repository and module after
|
||||
checkout preparation and before delivery. It runs `go mod download` in that
|
||||
module with workspace discovery disabled and the available compatible local Go
|
||||
toolchain.
|
||||
toolchain. Inside a Git checkout, `RepositoryDir` can name a subdirectory;
|
||||
`ModuleDir` is interpreted relative to the containing checkout root, and an
|
||||
empty selection chooses that root. Previously, a supplied checkout subdirectory
|
||||
acted as the selection base. Outside a checkout, the supplied directory remains
|
||||
the base for `ModuleDir`.
|
||||
The operation may use the network and updates the Go module cache while
|
||||
preserving the caller's proxy, private-module, credential, and cache settings.
|
||||
If checksums are missing, Go may update `go.sum`. For binary CI delivery, prepare
|
||||
|
||||
@@ -110,8 +110,7 @@ and CLI publication tests. Use the offline environment specified in Stage 10.
|
||||
|
||||
**Status:** complete. `go test ./internal/git` passes offline, including real
|
||||
checkout, worktree, alias, standalone, missing-Git, diagnostic, and failure
|
||||
cases. The public Go-only preparation composition check is deferred to Stage 3,
|
||||
where preparation adopts discovery.
|
||||
cases. The public Go-only preparation composition check passed in Stage 3.
|
||||
|
||||
**Files:** `internal/git/source.go` or a focused companion file, Git tests, and
|
||||
`internal/process/process.go` only if an existing invocation capability proves
|
||||
@@ -172,7 +171,9 @@ checkout, discovery fails with the missing-Git cause before Go runs.
|
||||
|
||||
## Stage 3: Apply checkout-root selection to dependency preparation
|
||||
|
||||
**Status:** pending. **Depends on:** Stage 2.
|
||||
**Status:** complete. Public preparation and CLI `TestCIDeliver` checks pass
|
||||
offline, including checkout-relative, symlink, standalone, and missing-Git
|
||||
selection. **Depends on:** Stage 2.
|
||||
|
||||
**Files:** `preparation.go`, `preparation_test.go`, and
|
||||
`docs/consumers/delivery.md`'s preparation guidance.
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go.maximumdirect.net/releasekit/internal/git"
|
||||
internalpreparation "go.maximumdirect.net/releasekit/internal/preparation"
|
||||
"go.maximumdirect.net/releasekit/internal/releaseidentity"
|
||||
)
|
||||
@@ -37,11 +38,13 @@ func PrepareTaggedCheckout(ctx context.Context, request TaggedCheckoutRequest) e
|
||||
}
|
||||
|
||||
// DependencyPreparationRequest selects the repository module whose dependencies
|
||||
// should be prepared.
|
||||
// should be prepared. Within a checkout, RepositoryDir may name any directory
|
||||
// in it; ModuleDir is resolved from the checkout root. Outside a checkout,
|
||||
// ModuleDir is resolved from RepositoryDir.
|
||||
type DependencyPreparationRequest struct {
|
||||
RepositoryDir string
|
||||
// ModuleDir selects a repository-relative module directory; empty selects
|
||||
// the repository root.
|
||||
// ModuleDir selects a directory relative to the checkout root or standalone
|
||||
// RepositoryDir; empty selects that base.
|
||||
ModuleDir string
|
||||
}
|
||||
|
||||
@@ -55,7 +58,15 @@ func PrepareBuildDependencies(ctx context.Context, request DependencyPreparation
|
||||
if strings.TrimSpace(request.RepositoryDir) == "" {
|
||||
return errors.New("repository directory is required")
|
||||
}
|
||||
selection, err := releaseidentity.ResolveSelection(request.RepositoryDir, request.ModuleDir)
|
||||
base := request.RepositoryDir
|
||||
root, found, err := git.DiscoverRepositoryRoot(ctx, base)
|
||||
if err != nil {
|
||||
return fmt.Errorf("discover dependency preparation repository: %w", err)
|
||||
}
|
||||
if found {
|
||||
base = root
|
||||
}
|
||||
selection, err := releaseidentity.ResolveSelection(base, request.ModuleDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resolve dependency preparation module: %w", err)
|
||||
}
|
||||
|
||||
@@ -249,6 +249,65 @@ func TestPrepareBuildDependenciesUsesSelectedModuleDirectory(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareBuildDependenciesSelectsFromCheckoutRoot(t *testing.T) {
|
||||
repo := t.TempDir()
|
||||
buildGit(t, repo, "init")
|
||||
nested := filepath.Join(repo, "nested")
|
||||
child := filepath.Join(nested, "child")
|
||||
if err := os.MkdirAll(child, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink("nested/child", filepath.Join(repo, "link")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bin := t.TempDir()
|
||||
marker := filepath.Join(t.TempDir(), "directory")
|
||||
if err := os.WriteFile(filepath.Join(bin, "go"), []byte("#!/bin/sh\nprintf '%s' \"$PWD\" > \"$PREPARE_DIR_MARKER\"\n"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("PATH", bin+string(os.PathListSeparator)+os.Getenv("PATH"))
|
||||
t.Setenv("PREPARE_DIR_MARKER", marker)
|
||||
for _, tc := range []struct{ dir, module, want string }{
|
||||
{repo, "", repo}, {child, "", repo}, {repo, "nested", nested},
|
||||
{child, "nested", nested}, {child, "link/..", nested},
|
||||
} {
|
||||
err := releasekit.PrepareBuildDependencies(context.Background(), releasekit.DependencyPreparationRequest{RepositoryDir: tc.dir, ModuleDir: tc.module})
|
||||
got, readErr := os.ReadFile(marker)
|
||||
if err != nil || readErr != nil || string(got) != tc.want {
|
||||
t.Fatalf("selection %q, %q = %q, error %v, read %v; want %q", tc.dir, tc.module, got, err, readErr, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareBuildDependenciesWithoutGit(t *testing.T) {
|
||||
repo := t.TempDir()
|
||||
buildGit(t, repo, "init")
|
||||
standalone := t.TempDir()
|
||||
bin := t.TempDir()
|
||||
marker := filepath.Join(t.TempDir(), "go-ran")
|
||||
if err := os.WriteFile(filepath.Join(bin, "go"), []byte("#!/bin/sh\nprintf ran > \"$PREPARE_DIR_MARKER\"\n"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("PATH", bin)
|
||||
t.Setenv("PREPARE_DIR_MARKER", marker)
|
||||
if err := releasekit.PrepareBuildDependencies(context.Background(), releasekit.DependencyPreparationRequest{RepositoryDir: standalone}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := os.Stat(marker); err != nil {
|
||||
t.Fatalf("Go did not run: %v", err)
|
||||
}
|
||||
if err := os.Remove(marker); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := releasekit.PrepareBuildDependencies(context.Background(), releasekit.DependencyPreparationRequest{RepositoryDir: repo})
|
||||
if !errors.Is(err, exec.ErrNotFound) {
|
||||
t.Fatalf("checkout error = %v, want missing Git", err)
|
||||
}
|
||||
if _, err := os.Stat(marker); !os.IsNotExist(err) {
|
||||
t.Fatalf("Go ran after discovery failure: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func publishPreparationTag(t *testing.T, repository string) string {
|
||||
t.Helper()
|
||||
return publishPreparationTagNamed(t, repository, "v1.2.3")
|
||||
|
||||
Reference in New Issue
Block a user