59 lines
2.2 KiB
Go
59 lines
2.2 KiB
Go
package git
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// PrepareTaggedCheckout fetches one explicit tag ref, checks its peeled commit
|
|
// against expectedCommit, and checks out that commit detached.
|
|
func PrepareTaggedCheckout(ctx context.Context, repositoryDir, tag, remote, expectedCommit string) error {
|
|
if err := checkTagRef(ctx, repositoryDir, tag); err != nil {
|
|
return err
|
|
}
|
|
if !validObjectID(expectedCommit) {
|
|
return fmt.Errorf("invalid tagged checkout commit %q for tag %q", expectedCommit, tag)
|
|
}
|
|
ref := "refs/tags/" + tag
|
|
if _, err := run(ctx, repositoryDir, nil, "fetch", "--no-tags", remote, ref+":"+ref); err != nil {
|
|
return fmt.Errorf("fetch tag %s from remote %s: %w", tag, remote, err)
|
|
}
|
|
source, err := InspectTaggedSource(ctx, repositoryDir, tag)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !strings.EqualFold(source.TagCommit, expectedCommit) {
|
|
return fmt.Errorf("tag %s resolves to commit %s, expected %s", tag, source.TagCommit, expectedCommit)
|
|
}
|
|
if _, err := run(ctx, repositoryDir, nil, "checkout", "--detach", source.TagCommit); err != nil {
|
|
return fmt.Errorf("check out tag %s at %s: %w", tag, source.TagCommit, err)
|
|
}
|
|
return VerifyTaggedCheckout(ctx, repositoryDir, tag, expectedCommit)
|
|
}
|
|
|
|
// VerifyTaggedCheckout confirms that the existing local tag, HEAD, and clean
|
|
// worktree all identify the expected commit. It does not fetch or check out.
|
|
func VerifyTaggedCheckout(ctx context.Context, repositoryDir, tag, expectedCommit string) error {
|
|
if err := checkTagRef(ctx, repositoryDir, tag); err != nil {
|
|
return err
|
|
}
|
|
if !validObjectID(expectedCommit) {
|
|
return fmt.Errorf("invalid tagged checkout commit %q for tag %q", expectedCommit, tag)
|
|
}
|
|
source, err := InspectTaggedSource(ctx, repositoryDir, tag)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if source.Status != "" {
|
|
return fmt.Errorf("tagged checkout must be clean:\n%s", source.Status)
|
|
}
|
|
if !strings.EqualFold(source.TagCommit, expectedCommit) {
|
|
return fmt.Errorf("tag %s resolves to commit %s, expected %s", tag, source.TagCommit, expectedCommit)
|
|
}
|
|
if !strings.EqualFold(source.Head, expectedCommit) {
|
|
return fmt.Errorf("checkout HEAD is %s, expected %s", source.Head, expectedCommit)
|
|
}
|
|
return nil
|
|
}
|