Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ if err != nil {
fmt.Println(commit, cache.DiskBytes("https://github.com/git-pkgs/clone"))
```

Call `Submodules` on the prepared checkout to read pinned identities without changing `Prepare`'s return values. Declared submodules that could not be fetched are included with `Initialized` set to false, `Status` set to `SubmoduleStatusUnavailable`, and a credential-free error string.

```go
submodules, err := clone.Submodules(ctx, "/tmp/job/src")
if err != nil {
log.Fatal(err)
}
for _, submodule := range submodules {
fmt.Println(submodule.Path, submodule.PURL, submodule.Status)
}
```

When a historical commit is missing from the shallow cache, `EnsureCommit` unshallows the checkout:

```go
Expand Down
14 changes: 11 additions & 3 deletions ensure.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,13 @@ func updateSubmodules(ctx context.Context, retry Retry, dst string, enabled bool
if !enabled {
return nil
}
if _, err := retry.Do(ctx, Command{
policy := retry.Resolved()
if _, err := policy.Run(ctx, dst, remoteEnv(), "submodule", "sync", "--recursive"); err != nil {
if ctxErr := ctx.Err(); ctxErr != nil {
return ctxErr
}
}
if _, err := policy.Do(ctx, Command{
Label: "submodule",
Dir: dst,
Env: remoteEnv(),
Expand All @@ -124,7 +130,7 @@ func fetchRef(ctx context.Context, retry Retry, url, dst, ref string, full bool)
if target == "" {
target = "HEAD" //nolint:goconst // Git's default ref is clearest by its literal name.
}
args := []string{"-C", dst, "fetch", "--quiet"} //nolint:goconst // Git argv is clearer with literal subcommands and flags.
args := []string{"-C", dst, "fetch", "--quiet", "--no-recurse-submodules"} //nolint:goconst // Git argv is clearer with literal subcommands and flags.
if full {
out, _ := policy.Run(ctx, "", nil, "-C", dst, "rev-parse", "--is-shallow-repository")
if strings.TrimSpace(out) == "true" {
Expand All @@ -140,7 +146,9 @@ func fetchRef(ctx context.Context, retry Retry, url, dst, ref string, full bool)
if err != nil {
return fmt.Errorf("%s: %w", strings.TrimSpace(out), err)
}
out, err = policy.Run(ctx, "", nil, "-C", dst, "reset", "--quiet", "--hard", "FETCH_HEAD")
out, err = policy.Run(ctx, "", nil,
"-C", dst, "reset", "--quiet", "--hard", "--no-recurse-submodules", "FETCH_HEAD",
)
if err != nil {
return fmt.Errorf("%s: %w", strings.TrimSpace(out), err)
}
Expand Down
31 changes: 22 additions & 9 deletions ensure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,10 @@ func TestEnsureWithOptionsIgnoresSubmoduleFailure(t *testing.T) {
t.Fatal(err)
}

var submoduleArgs []string
var submoduleEnv []string
var syncArgs []string
var syncEnv []string
var updateArgs []string
var updateEnv []string
retry := Retry{
Attempts: 1,
Run: func(_ context.Context, dir string, env []string, args ...string) (string, error) {
Expand All @@ -222,8 +224,13 @@ func TestEnsureWithOptionsIgnoresSubmoduleFailure(t *testing.T) {
if dir != dst {
t.Errorf("submodule dir = %q, want %q", dir, dst)
}
submoduleArgs = append([]string(nil), args...)
submoduleEnv = append([]string(nil), env...)
if slices.Contains(args, "sync") {
syncArgs = append([]string(nil), args...)
syncEnv = append([]string(nil), env...)
return "", nil
}
updateArgs = append([]string(nil), args...)
updateEnv = append([]string(nil), env...)
return "fatal: repository not found", errGitExit
default:
return "", errors.New("unexpected Git command")
Expand All @@ -237,12 +244,18 @@ func TestEnsureWithOptionsIgnoresSubmoduleFailure(t *testing.T) {
); err != nil {
t.Fatalf("EnsureWithOptions: %v", err)
}
wantArgs := []string{"submodule", "update", "--init", "--recursive", "--depth", "1"}
if !slices.Equal(submoduleArgs, wantArgs) {
t.Errorf("submodule args = %v, want %v", submoduleArgs, wantArgs)
wantSyncArgs := []string{"submodule", "sync", "--recursive"}
if !slices.Equal(syncArgs, wantSyncArgs) {
t.Errorf("submodule sync args = %v, want %v", syncArgs, wantSyncArgs)
}
wantUpdateArgs := []string{"submodule", "update", "--init", "--recursive", "--depth", "1"}
if !slices.Equal(updateArgs, wantUpdateArgs) {
t.Errorf("submodule update args = %v, want %v", updateArgs, wantUpdateArgs)
}
if !slices.Contains(submoduleEnv, "GIT_PROTOCOL_FROM_USER=0") {
t.Errorf("submodule env = %v", submoduleEnv)
for name, env := range map[string][]string{"sync": syncEnv, "update": updateEnv} {
if !slices.Contains(env, "GIT_PROTOCOL_FROM_USER=0") {
t.Errorf("submodule %s env = %v", name, env)
}
}
}

Expand Down
10 changes: 9 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,12 @@ module github.com/git-pkgs/clone

go 1.25.6

require github.com/git-pkgs/magic v0.2.0
require (
github.com/git-pkgs/magic v0.2.0
github.com/git-pkgs/purl v0.1.17
)

require (
github.com/git-pkgs/vers v0.3.1 // indirect
github.com/package-url/packageurl-go v0.1.6 // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
github.com/git-pkgs/magic v0.2.0 h1:c7HqVxnP8c88EaVMH0/KraDFVTcmiXckRiSvNZEnvMQ=
github.com/git-pkgs/magic v0.2.0/go.mod h1:3ndidt+yvFaI1M0aEkkzkOlFnLPkeVQASIUojazcxCI=
github.com/git-pkgs/purl v0.1.17 h1:oRSd8tqllTLl74Wa4WnuqU500hXd9OdUnImOEswQUVE=
github.com/git-pkgs/purl v0.1.17/go.mod h1:7u7ora8tQdrkS7Auclr5v8dCJdjN4ej6AbrvYZi2b7k=
github.com/git-pkgs/vers v0.3.1 h1:jy/ht2wIRJI5zQrccm6GTeYr+hGFwe2z8LV1HOr4Wco=
github.com/git-pkgs/vers v0.3.1/go.mod h1:biTbSQK1qdbrsxDEKnqe3Jzclxz8vW6uDcwKjfUGcOo=
github.com/package-url/packageurl-go v0.1.6 h1:YO3p6u1XmCUliivUg/qWphaY8vI6hxSnnPv7Bfg3m5M=
github.com/package-url/packageurl-go v0.1.6/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0=
Loading