mirror of
https://github.com/moby/buildkit.git
synced 2025-07-30 15:03:06 +03:00
git: ensure that pin matches checked-out commit
Previously, it was very possible for the CacheKey function to return a sha key that was *not* the checked out commit. There are two cases that I've encountered where this can happen: - An annotated tag will have the pin of the tag, and not the underlying commit, which will be HEAD after the checkout. - If multiple tags have the same path component (e.g. "mytag" and "abc/mytag") then the first alphabetical tag will be selected when (in this case "abc/mytag"). To avoid this kind of case, we can't just search for a single match in the results for ls-remote. There's no way to filter for just an exact match, so we need to scan through the output ourselves. Additionally, we need to dereference the annotated tags by also selecting refs ending in "^{}" - which have the commit that the tag points at. Finally, I've improved the test suite around this to check that: - The cache-key pin is equivalent to the checked out commit - We can check out non-master branches - That full ref syntax like "refs/heads/<branch-name>" and "refs/tags/<tag-name>" (or even "refs/<anything>") can be used. Signed-off-by: Justin Chadwell <me@jedevc.com>
This commit is contained in:
@ -365,20 +365,45 @@ func (gs *gitSourceHandler) CacheKey(ctx context.Context, g session.Group, index
|
||||
|
||||
// TODO: should we assume that remote tag is immutable? add a timer?
|
||||
|
||||
buf, err := git.Run(ctx, "ls-remote", "origin", ref)
|
||||
buf, err := git.Run(ctx, "ls-remote", "origin", ref, ref+"^{}")
|
||||
if err != nil {
|
||||
return "", "", nil, false, errors.Wrapf(err, "failed to fetch remote %s", urlutil.RedactCredentials(remote))
|
||||
}
|
||||
out := string(buf)
|
||||
idx := strings.Index(out, "\t")
|
||||
if idx == -1 {
|
||||
return "", "", nil, false, errors.Errorf("repository does not contain ref %s, output: %q", ref, string(out))
|
||||
lines := strings.Split(string(buf), "\n")
|
||||
|
||||
var (
|
||||
partialRef = "refs/" + strings.TrimPrefix(ref, "refs/")
|
||||
headRef = "refs/heads/" + strings.TrimPrefix(ref, "refs/heads/")
|
||||
tagRef = "refs/tags/" + strings.TrimPrefix(ref, "refs/tags/")
|
||||
annotatedTagRef = tagRef + "^{}"
|
||||
)
|
||||
var sha, headSha, tagSha string
|
||||
for _, line := range lines {
|
||||
lineSha, lineRef, _ := strings.Cut(line, "\t")
|
||||
switch lineRef {
|
||||
case headRef:
|
||||
headSha = lineSha
|
||||
case tagRef, annotatedTagRef:
|
||||
tagSha = lineSha
|
||||
case partialRef:
|
||||
sha = lineSha
|
||||
}
|
||||
}
|
||||
|
||||
sha := string(out[:idx])
|
||||
// git-checkout prefers branches in case of ambiguity
|
||||
if sha == "" {
|
||||
sha = headSha
|
||||
}
|
||||
if sha == "" {
|
||||
sha = tagSha
|
||||
}
|
||||
if sha == "" {
|
||||
return "", "", nil, false, errors.Errorf("repository does not contain ref %s, output: %q", ref, string(buf))
|
||||
}
|
||||
if !isCommitSHA(sha) {
|
||||
return "", "", nil, false, errors.Errorf("invalid commit sha %q", sha)
|
||||
}
|
||||
|
||||
cacheKey := gs.shaToCacheKey(sha)
|
||||
gs.cacheKey = cacheKey
|
||||
return cacheKey, sha, nil, true, nil
|
||||
|
Reference in New Issue
Block a user