CloneRepo will clone the repository at the given URL into the given path. If a repository is already initialized at the given path, it will not be cloned again. The bool returned states whether the repository was cloned or not.
(ctx context.Context, logf func(string, ...any), opts CloneRepoOptions)
| 49 | // |
| 50 | // The bool returned states whether the repository was cloned or not. |
| 51 | func CloneRepo(ctx context.Context, logf func(string, ...any), opts CloneRepoOptions) (bool, error) { |
| 52 | parsed, err := ebutil.ParseRepoURL(opts.RepoURL) |
| 53 | if err != nil { |
| 54 | return false, fmt.Errorf("parse url %q: %w", opts.RepoURL, err) |
| 55 | } |
| 56 | |
| 57 | thinPack := true |
| 58 | |
| 59 | if !opts.ThinPack { |
| 60 | thinPack = false |
| 61 | logf("ThinPack options is false, Marking thin-pack as unsupported") |
| 62 | } else if parsed.Host == "dev.azure.com" { |
| 63 | // Azure DevOps requires capabilities multi_ack / multi_ack_detailed, |
| 64 | // which are not fully implemented and by default are included in |
| 65 | // transport.UnsupportedCapabilities. |
| 66 | // |
| 67 | // The initial clone operations require a full download of the repository, |
| 68 | // and therefore those unsupported capabilities are not as crucial, so |
| 69 | // by removing them from that list allows for the first clone to work |
| 70 | // successfully. |
| 71 | // |
| 72 | // Additional fetches will yield issues, therefore work always from a clean |
| 73 | // clone until those capabilities are fully supported. |
| 74 | // |
| 75 | // New commits and pushes against a remote worked without any issues. |
| 76 | // See: https://github.com/go-git/go-git/issues/64 |
| 77 | // |
| 78 | // This is knowingly not safe to call in parallel, but it seemed |
| 79 | // like the least-janky place to add a super janky hack. |
| 80 | thinPack = false |
| 81 | logf("Workaround for Azure DevOps: marking thin-pack as unsupported") |
| 82 | } |
| 83 | |
| 84 | if !thinPack { |
| 85 | transport.UnsupportedCapabilities = []capability.Capability{ |
| 86 | capability.ThinPack, |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | err = opts.Storage.MkdirAll(opts.Path, 0o755) |
| 91 | if err != nil { |
| 92 | return false, fmt.Errorf("mkdir %q: %w", opts.Path, err) |
| 93 | } |
| 94 | if parsed.Reference == "" && opts.SingleBranch { |
| 95 | parsed.Reference = "refs/heads/main" |
| 96 | } |
| 97 | fs, err := opts.Storage.Chroot(opts.Path) |
| 98 | if err != nil { |
| 99 | return false, fmt.Errorf("chroot %q: %w", opts.Path, err) |
| 100 | } |
| 101 | gitDir, err := fs.Chroot(".git") |
| 102 | if err != nil { |
| 103 | return false, fmt.Errorf("chroot .git: %w", err) |
| 104 | } |
| 105 | gitStorage := filesystem.NewStorage(gitDir, cache.NewObjectLRU(cache.DefaultMaxSize*10)) |
| 106 | fsStorage := filesystem.NewStorage(fs, cache.NewObjectLRU(cache.DefaultMaxSize*10)) |
| 107 | repo, err := git.Open(fsStorage, gitDir) |
| 108 | if errors.Is(err, git.ErrRepositoryNotExists) { |