Publish the captured release tag
This commit is contained in:
@@ -21,6 +21,7 @@ type Candidate struct {
|
||||
RepositoryDir string
|
||||
Commit string
|
||||
Version string
|
||||
Note string
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
@@ -32,6 +33,22 @@ type Request struct {
|
||||
}
|
||||
|
||||
func Check(ctx context.Context, request Request) (Candidate, error) {
|
||||
captured, err := Capture(ctx, request)
|
||||
if err != nil {
|
||||
return Candidate{}, err
|
||||
}
|
||||
if err := Validate(ctx, request, captured); err != nil {
|
||||
return Candidate{}, err
|
||||
}
|
||||
if err := Recheck(ctx, captured, ""); err != nil {
|
||||
return Candidate{}, err
|
||||
}
|
||||
return captured, nil
|
||||
}
|
||||
|
||||
// Capture validates request identity and records one clean local candidate,
|
||||
// including the note bytes from the captured commit. It does not run checks.
|
||||
func Capture(ctx context.Context, request Request) (Candidate, error) {
|
||||
if !validStableVersion(request.Version) {
|
||||
return Candidate{}, fmt.Errorf("%w: %q", ErrInvalidVersion, request.Version)
|
||||
}
|
||||
@@ -68,36 +85,61 @@ func Check(ctx context.Context, request Request) (Candidate, error) {
|
||||
return Candidate{}, fmt.Errorf("local tag %q already exists", request.Version)
|
||||
}
|
||||
|
||||
captured := Candidate{RepositoryDir: repositoryDir, Commit: state.commit, Version: request.Version}
|
||||
return Candidate{RepositoryDir: repositoryDir, Commit: state.commit, Version: request.Version, Note: string(note)}, nil
|
||||
}
|
||||
|
||||
// Validate runs the complete selected validation once for the captured
|
||||
// candidate. A supplied callback replaces the default offline Go validation.
|
||||
func Validate(ctx context.Context, request Request, captured Candidate) error {
|
||||
var err error
|
||||
if request.Validate == nil {
|
||||
err = runDefaultValidation(ctx, captured.RepositoryDir, request.Output)
|
||||
} else {
|
||||
err = request.Validate(ctx, captured)
|
||||
}
|
||||
if err != nil {
|
||||
return Candidate{}, fmt.Errorf("validate candidate %s: %w", captured.Commit, err)
|
||||
return fmt.Errorf("validate candidate %s: %w", captured.Commit, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
current, err := inspectLocalState(ctx, repositoryDir)
|
||||
// Recheck verifies that the captured local source is unchanged. When
|
||||
// expectedTagObject is empty, the selected local version tag must still be
|
||||
// absent; otherwise the existing annotated tag must still have that object ID.
|
||||
func Recheck(ctx context.Context, captured Candidate, expectedTagObject string) error {
|
||||
current, err := inspectLocalState(ctx, captured.RepositoryDir)
|
||||
if err != nil {
|
||||
return Candidate{}, fmt.Errorf("recheck local candidate state: %w", err)
|
||||
return fmt.Errorf("recheck local candidate state: %w", err)
|
||||
}
|
||||
if current.branch != "main" {
|
||||
return Candidate{}, fmt.Errorf("release candidate branch changed during validation to %q", current.branch)
|
||||
return fmt.Errorf("release candidate branch changed to %q", current.branch)
|
||||
}
|
||||
if current.commit != captured.Commit {
|
||||
return Candidate{}, fmt.Errorf("HEAD changed during validation from %s to %s", captured.Commit, current.commit)
|
||||
return fmt.Errorf("HEAD changed from %s to %s", captured.Commit, current.commit)
|
||||
}
|
||||
if current.status != "" {
|
||||
return Candidate{}, fmt.Errorf("worktree or index changed during validation:\n%s", current.status)
|
||||
return fmt.Errorf("worktree or index changed:\n%s", current.status)
|
||||
}
|
||||
if exists, err := hasLocalTag(ctx, repositoryDir, request.Version); err != nil {
|
||||
return Candidate{}, fmt.Errorf("recheck local tag %q: %w", request.Version, err)
|
||||
} else if exists {
|
||||
return Candidate{}, fmt.Errorf("local tag %q appeared during validation", request.Version)
|
||||
if expectedTagObject == "" {
|
||||
if exists, err := hasLocalTag(ctx, captured.RepositoryDir, captured.Version); err != nil {
|
||||
return fmt.Errorf("recheck local tag %q: %w", captured.Version, err)
|
||||
} else if exists {
|
||||
return fmt.Errorf("local tag %q appeared during validation", captured.Version)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return captured, nil
|
||||
object, err := gitOutput(ctx, captured.RepositoryDir, "rev-parse", "--verify", "refs/tags/"+captured.Version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read local tag %q: %w", captured.Version, err)
|
||||
}
|
||||
tagType, err := gitOutput(ctx, captured.RepositoryDir, "cat-file", "-t", "refs/tags/"+captured.Version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("inspect local tag %q: %w", captured.Version, err)
|
||||
}
|
||||
if strings.TrimSpace(string(object)) != expectedTagObject || strings.TrimSpace(string(tagType)) != "tag" {
|
||||
return fmt.Errorf("local tag %q no longer identifies annotated tag object %s", captured.Version, expectedTagObject)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type localState struct {
|
||||
|
||||
@@ -213,7 +213,7 @@ func TestCheckRechecksHeadAndWorktreeAfterCallback(t *testing.T) {
|
||||
gitRun(t, repository, "add", "later.txt")
|
||||
gitRun(t, repository, "-c", "commit.gpgsign=false", "commit", "-m", "advance HEAD")
|
||||
},
|
||||
want: "HEAD changed during validation",
|
||||
want: "HEAD changed from",
|
||||
},
|
||||
{
|
||||
name: "worktree changes",
|
||||
@@ -223,7 +223,7 @@ func TestCheckRechecksHeadAndWorktreeAfterCallback(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
},
|
||||
want: "changed during validation",
|
||||
want: "worktree or index changed",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
|
||||
Reference in New Issue
Block a user