Make product checks additive
This commit is contained in:
@@ -26,12 +26,12 @@ type Candidate struct {
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
RepositoryDir string
|
||||
Product string
|
||||
Version string
|
||||
Validate func(context.Context, Candidate) error
|
||||
AfterValidate func(context.Context, Candidate) error
|
||||
Output io.Writer
|
||||
RepositoryDir string
|
||||
Product string
|
||||
Version string
|
||||
AdditionalChecks func(context.Context, Candidate) error
|
||||
AfterValidate func(context.Context, Candidate) error
|
||||
Output io.Writer
|
||||
}
|
||||
|
||||
func Check(ctx context.Context, request Request) (Candidate, error) {
|
||||
@@ -95,18 +95,17 @@ func Capture(ctx context.Context, request Request) (Candidate, error) {
|
||||
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.
|
||||
// Validate runs the standard offline Go suite, followed by AdditionalChecks
|
||||
// when supplied, for the captured candidate.
|
||||
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 {
|
||||
if err := runDefaultValidation(ctx, captured.RepositoryDir, request.Output); err != nil {
|
||||
return fmt.Errorf("validate candidate %s: %w", captured.Commit, err)
|
||||
}
|
||||
if request.AdditionalChecks != nil {
|
||||
if err := request.AdditionalChecks(ctx, captured); err != nil {
|
||||
return fmt.Errorf("validate candidate %s: %w", captured.Commit, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestValidStableVersion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckCapturesCandidateAndCallsValidationOnce(t *testing.T) {
|
||||
func TestCheckCapturesCandidateAndCallsAdditionalChecksOnce(t *testing.T) {
|
||||
repository := newRepository(t, "# Example Product v1.2.3\n\nRelease note.\n")
|
||||
calls := 0
|
||||
var seen Candidate
|
||||
@@ -49,7 +49,7 @@ func TestCheckCapturesCandidateAndCallsValidationOnce(t *testing.T) {
|
||||
RepositoryDir: repository,
|
||||
Product: "Example Product",
|
||||
Version: testVersion,
|
||||
Validate: func(_ context.Context, captured Candidate) error {
|
||||
AdditionalChecks: func(_ context.Context, captured Candidate) error {
|
||||
calls++
|
||||
seen = captured
|
||||
return nil
|
||||
@@ -174,7 +174,7 @@ func TestCheckRequiresMatchingCommittedNote(t *testing.T) {
|
||||
RepositoryDir: repository,
|
||||
Product: "Example Product",
|
||||
Version: testVersion,
|
||||
Validate: func(context.Context, Candidate) error {
|
||||
AdditionalChecks: func(context.Context, Candidate) error {
|
||||
called = true
|
||||
return nil
|
||||
},
|
||||
@@ -230,7 +230,7 @@ func TestCheckRequiresMainBranchAndUnusedTag(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestCheckStopsOnCallbackFailure(t *testing.T) {
|
||||
func TestCheckStopsOnAdditionalCheckFailure(t *testing.T) {
|
||||
repository := newRepository(t, "# Example Product v1.2.3\n")
|
||||
want := errors.New("selected check failed")
|
||||
calls := 0
|
||||
@@ -238,7 +238,7 @@ func TestCheckStopsOnCallbackFailure(t *testing.T) {
|
||||
RepositoryDir: repository,
|
||||
Product: "Example Product",
|
||||
Version: testVersion,
|
||||
Validate: func(context.Context, Candidate) error {
|
||||
AdditionalChecks: func(context.Context, Candidate) error {
|
||||
calls++
|
||||
return want
|
||||
},
|
||||
@@ -287,7 +287,7 @@ func TestCheckRechecksHeadAndWorktreeAfterCallback(t *testing.T) {
|
||||
RepositoryDir: repository,
|
||||
Product: "Example Product",
|
||||
Version: testVersion,
|
||||
Validate: func(context.Context, Candidate) error {
|
||||
AdditionalChecks: func(context.Context, Candidate) error {
|
||||
test.validate(t, repository)
|
||||
return nil
|
||||
},
|
||||
@@ -305,7 +305,7 @@ func TestCheckRechecksLocalTagAfterCallback(t *testing.T) {
|
||||
RepositoryDir: repository,
|
||||
Product: "Example Product",
|
||||
Version: testVersion,
|
||||
Validate: func(context.Context, Candidate) error {
|
||||
AdditionalChecks: func(context.Context, Candidate) error {
|
||||
gitRun(t, repository, "tag", testVersion)
|
||||
return nil
|
||||
},
|
||||
@@ -316,7 +316,7 @@ func TestCheckRechecksLocalTagAfterCallback(t *testing.T) {
|
||||
}
|
||||
|
||||
func validRequest(repository string) Request {
|
||||
return Request{RepositoryDir: repository, Product: "Example Product", Version: testVersion, Validate: func(context.Context, Candidate) error { return nil }}
|
||||
return Request{RepositoryDir: repository, Product: "Example Product", Version: testVersion, AdditionalChecks: func(context.Context, Candidate) error { return nil }}
|
||||
}
|
||||
|
||||
func newRepository(t *testing.T, note string) string {
|
||||
|
||||
@@ -36,13 +36,13 @@ const (
|
||||
const recoveryTimeout = 30 * time.Second
|
||||
|
||||
type Request struct {
|
||||
RepositoryDir string
|
||||
Product string
|
||||
Version string
|
||||
Remote string
|
||||
Validate func(context.Context, candidate.Candidate) error
|
||||
AfterValidate func(context.Context, candidate.Candidate) error
|
||||
Output io.Writer
|
||||
RepositoryDir string
|
||||
Product string
|
||||
Version string
|
||||
Remote string
|
||||
AdditionalChecks func(context.Context, candidate.Candidate) error
|
||||
AfterValidate func(context.Context, candidate.Candidate) error
|
||||
Output io.Writer
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
@@ -55,7 +55,8 @@ type Result struct {
|
||||
}
|
||||
|
||||
// Publish validates one captured candidate and pushes only its annotated tag
|
||||
// object. A failed push receives one bounded authoritative tag query. Exact
|
||||
// object. It runs the standard Go suite, then AdditionalChecks when supplied.
|
||||
// A failed push receives one bounded authoritative tag query. Exact
|
||||
// object equality confirms publication; absence and conflict are classified,
|
||||
// while an unreadable result remains Unknown and preserves the push error.
|
||||
func Publish(ctx context.Context, request Request) (Result, error) {
|
||||
@@ -65,11 +66,11 @@ func Publish(ctx context.Context, request Request) (Result, error) {
|
||||
remoteName = "origin"
|
||||
}
|
||||
checks := candidate.Request{
|
||||
RepositoryDir: request.RepositoryDir,
|
||||
Product: request.Product,
|
||||
Version: request.Version,
|
||||
Validate: request.Validate,
|
||||
Output: request.Output,
|
||||
RepositoryDir: request.RepositoryDir,
|
||||
Product: request.Product,
|
||||
Version: request.Version,
|
||||
AdditionalChecks: request.AdditionalChecks,
|
||||
Output: request.Output,
|
||||
}
|
||||
captured, err := candidate.Capture(ctx, checks)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user