Make product checks additive
This commit is contained in:
155
publish_test.go
155
publish_test.go
@@ -21,6 +21,8 @@ func TestPublishPushesOnlyTheCapturedAnnotatedTag(t *testing.T) {
|
||||
repo := newPublishFixture(t)
|
||||
wrapper := installGitWrapper(t, repo, "pass")
|
||||
t.Setenv("PATH", wrapper.bin+string(os.PathListSeparator)+os.Getenv("PATH"))
|
||||
suiteRuns := filepath.Join(t.TempDir(), "suite-runs")
|
||||
t.Setenv("RELEASEKIT_FIXTURE_SUITE_RUNS", suiteRuns)
|
||||
refsBefore := gitText(t, repo.bare, "show-ref", "--heads", "--tags")
|
||||
commit := repo.commit
|
||||
var validations int
|
||||
@@ -28,8 +30,12 @@ func TestPublishPushesOnlyTheCapturedAnnotatedTag(t *testing.T) {
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(_ context.Context, candidate releasekit.Candidate) error {
|
||||
AdditionalChecks: func(_ context.Context, candidate releasekit.Candidate) error {
|
||||
validations++
|
||||
runs, readErr := os.ReadFile(suiteRuns)
|
||||
if readErr != nil || string(runs) != "ran\n" {
|
||||
return fmt.Errorf("standard suite runs before additional checks: contents=%q error=%v", runs, readErr)
|
||||
}
|
||||
if candidate.RepositoryDir != repo.work || candidate.Commit != commit || candidate.Version != "v1.2.3" {
|
||||
t.Fatalf("callback candidate = %#v", candidate)
|
||||
}
|
||||
@@ -42,6 +48,9 @@ func TestPublishPushesOnlyTheCapturedAnnotatedTag(t *testing.T) {
|
||||
if validations != 1 {
|
||||
t.Fatalf("validation calls = %d, want 1", validations)
|
||||
}
|
||||
if runs, err := os.ReadFile(suiteRuns); err != nil || string(runs) != "ran\n" {
|
||||
t.Fatalf("standard suite runs = %q, error = %v; want one run", runs, err)
|
||||
}
|
||||
if queries := countLines(t, wrapper.queryLog); queries != 3 {
|
||||
t.Fatalf("authoritative tag query count = %d, want 3 guards and no success read-back", queries)
|
||||
}
|
||||
@@ -84,6 +93,69 @@ func TestPublishPushesOnlyTheCapturedAnnotatedTag(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishFailedStandardSuiteSkipsAdditionalChecksAndTagCreation(t *testing.T) {
|
||||
repo := newPublishFixture(t)
|
||||
t.Setenv("RELEASEKIT_FAIL_FIXTURE_SUITE", "1")
|
||||
var checks int
|
||||
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error {
|
||||
checks++
|
||||
return nil
|
||||
},
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "fixture standard suite failure") {
|
||||
t.Fatalf("Publish() error = %v, want fixture standard suite failure", err)
|
||||
}
|
||||
if checks != 0 || result.TagObject != "" || result.State != releasekit.PublicationNotAttempted {
|
||||
t.Fatalf("failed standard suite result=%#v additional checks=%d", result, checks)
|
||||
}
|
||||
for _, command := range [][]string{
|
||||
{"git", "-C", repo.work, "show-ref", "--verify", "--quiet", "refs/tags/v1.2.3"},
|
||||
{"git", "--git-dir", repo.bare, "show-ref", "--verify", "--quiet", "refs/tags/v1.2.3"},
|
||||
} {
|
||||
if _, err := exec.Command(command[0], command[1:]...).CombinedOutput(); err == nil {
|
||||
t.Fatalf("failed standard suite created release tag with %v", command)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishAdditionalCheckFailurePreservesCauseAndPreventsTagCreation(t *testing.T) {
|
||||
repo := newPublishFixture(t)
|
||||
suiteRuns := filepath.Join(t.TempDir(), "suite-runs")
|
||||
t.Setenv("RELEASEKIT_FIXTURE_SUITE_RUNS", suiteRuns)
|
||||
wantErr := errors.New("additional product check failed")
|
||||
var checks int
|
||||
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error {
|
||||
checks++
|
||||
return wantErr
|
||||
},
|
||||
})
|
||||
if !errors.Is(err, wantErr) {
|
||||
t.Fatalf("Publish() error = %v, want wrapped additional-check error", err)
|
||||
}
|
||||
if runs, readErr := os.ReadFile(suiteRuns); readErr != nil || string(runs) != "ran\n" {
|
||||
t.Fatalf("standard suite runs = %q, error = %v; want one successful run", runs, readErr)
|
||||
}
|
||||
if checks != 1 || result.TagObject != "" || result.State != releasekit.PublicationNotAttempted {
|
||||
t.Fatalf("additional-check failure result=%#v checks=%d", result, checks)
|
||||
}
|
||||
for _, command := range [][]string{
|
||||
{"git", "-C", repo.work, "show-ref", "--verify", "--quiet", "refs/tags/v1.2.3"},
|
||||
{"git", "--git-dir", repo.bare, "show-ref", "--verify", "--quiet", "refs/tags/v1.2.3"},
|
||||
} {
|
||||
if _, err := exec.Command(command[0], command[1:]...).CombinedOutput(); err == nil {
|
||||
t.Fatalf("additional-check failure created release tag with %v", command)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishRejectedPushKeepsLocalTagAndReportsNotPublished(t *testing.T) {
|
||||
repo := newPublishFixture(t)
|
||||
wrapper := installGitWrapper(t, repo, "pass")
|
||||
@@ -93,10 +165,10 @@ func TestPublishRejectedPushKeepsLocalTagAndReportsNotPublished(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("Publish() succeeded despite rejected push hook")
|
||||
@@ -130,7 +202,7 @@ func TestPublishLostAcknowledgmentConfirmsExactRemoteObject(t *testing.T) {
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(context.Context, releasekit.Candidate) error {
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error {
|
||||
go func() {
|
||||
defer close(watcherDone)
|
||||
for {
|
||||
@@ -173,10 +245,10 @@ func TestPublishLostAcknowledgmentWithChangedEndpointRemainsUnknown(t *testing.T
|
||||
t.Setenv("PATH", wrapper.bin+string(os.PathListSeparator)+os.Getenv("PATH"))
|
||||
|
||||
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
})
|
||||
if err == nil || result.State != releasekit.PublicationUnknown || result.Phase != releasekit.PublicationReconciliation {
|
||||
t.Fatalf("result = %#v, error = %v", result, err)
|
||||
@@ -216,10 +288,10 @@ func TestPublishConflictingRemoteTagIsNotReportedAsAbsent(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
})
|
||||
if err == nil || result.State != releasekit.PublicationConflict || result.Phase != releasekit.PublicationReconciliation {
|
||||
t.Fatalf("result = %#v, error = %v", result, err)
|
||||
@@ -239,10 +311,10 @@ func TestPublishStopsWhenLocalTagChangesBeforePush(t *testing.T) {
|
||||
wrapper := installGitWrapperWithMutation(t, repo, conflictingObject)
|
||||
t.Setenv("PATH", wrapper.bin+string(os.PathListSeparator)+os.Getenv("PATH"))
|
||||
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
})
|
||||
if err == nil || result.State != releasekit.PublicationNotPublished || result.Phase != releasekit.PublicationTagCreation {
|
||||
t.Fatalf("result = %#v, error = %v", result, err)
|
||||
@@ -270,10 +342,10 @@ func TestPublishUnavailableReconciliationRemainsUnknownAndPreservesPushError(t *
|
||||
t.Fatal(err)
|
||||
}
|
||||
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
})
|
||||
if err == nil || result.State != releasekit.PublicationUnknown || result.Phase != releasekit.PublicationReconciliation {
|
||||
t.Fatalf("result = %#v, error = %v", result, err)
|
||||
@@ -303,10 +375,10 @@ func TestPublishUninterpretableReconciliationRemainsUnknown(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error { return nil },
|
||||
})
|
||||
if err == nil || result.State != releasekit.PublicationUnknown || result.Phase != releasekit.PublicationReconciliation {
|
||||
t.Fatalf("result = %#v, error = %v", result, err)
|
||||
@@ -330,7 +402,7 @@ func TestPublishRemoteConflictStopsBeforeValidation(t *testing.T) {
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(context.Context, releasekit.Candidate) error {
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error {
|
||||
validations++
|
||||
return nil
|
||||
},
|
||||
@@ -349,7 +421,7 @@ func TestPublishRemoteChangeDuringValidationPreventsLocalTag(t *testing.T) {
|
||||
RepositoryDir: repo.work,
|
||||
Product: "Sample App",
|
||||
Version: "v1.2.3",
|
||||
Validate: func(context.Context, releasekit.Candidate) error {
|
||||
AdditionalChecks: func(context.Context, releasekit.Candidate) error {
|
||||
gitRun(t, repo.bare, "update-ref", "refs/heads/main", repo.unrelatedCommit)
|
||||
return nil
|
||||
},
|
||||
@@ -493,6 +565,33 @@ func newPublishFixture(t *testing.T) publishFixture {
|
||||
gitRun(t, base, "init", "-b", "main", work)
|
||||
gitRun(t, work, "config", "user.name", "ReleaseKit Test")
|
||||
gitRun(t, work, "config", "user.email", "releasekit@example.invalid")
|
||||
writeFile(t, work, "go.mod", "module example.com/releasekit-publish-fixture\n\ngo 1.25.0\n")
|
||||
writeFile(t, work, "fixture_test.go", `package fixture
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFixture(t *testing.T) {
|
||||
if path := os.Getenv("RELEASEKIT_FIXTURE_SUITE_RUNS"); path != "" {
|
||||
file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o600)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := file.WriteString("ran\n"); err != nil {
|
||||
_ = file.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := file.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if os.Getenv("RELEASEKIT_FAIL_FIXTURE_SUITE") == "1" {
|
||||
t.Fatal("fixture standard suite failure")
|
||||
}
|
||||
}
|
||||
`)
|
||||
writeFile(t, work, "docs/releases/v1.2.3.md", releaseNote)
|
||||
writeFile(t, work, "source.txt", "candidate")
|
||||
gitRun(t, work, "add", ".")
|
||||
|
||||
Reference in New Issue
Block a user