Preserve page creation outcomes through recovery
This commit is contained in:
@@ -111,7 +111,7 @@ func Deliver(ctx context.Context, request Request) (Result, error) {
|
||||
inspection, err := (gitea.Client{}).InspectAssets(ctx, request.Destination, releaseResult.Release.ID, request.Assets)
|
||||
if err != nil {
|
||||
result.State = NotAttempted
|
||||
if releaseResult.Created {
|
||||
if releaseResult.WriteAttempted {
|
||||
result.State = Partial
|
||||
}
|
||||
result.Uncertain = assetIdentities(request.Assets)
|
||||
|
||||
@@ -75,8 +75,9 @@ type Release struct {
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Release Release
|
||||
Created bool
|
||||
Release Release
|
||||
Created bool
|
||||
WriteAttempted bool // a create request was issued, including reconciled creates.
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
@@ -150,7 +151,12 @@ func (c Client) EnsureRelease(ctx context.Context, request Request) (Result, err
|
||||
}
|
||||
created, postStatus, postErr := c.postRelease(ctx, client, request.Destination.Token, apiRoot+"/releases", body)
|
||||
if postErr == nil {
|
||||
return acceptCreated(created, request)
|
||||
result, verifyErr := acceptCreated(created, request)
|
||||
if verifyErr == nil {
|
||||
result.WriteAttempted = true
|
||||
return result, nil
|
||||
}
|
||||
postErr = verifyErr
|
||||
}
|
||||
if !shouldReconcileWrite(postStatus, postErr) {
|
||||
return Result{}, postErr
|
||||
@@ -162,6 +168,7 @@ func (c Client) EnsureRelease(ctx context.Context, request Request) (Result, err
|
||||
if retryErr == nil {
|
||||
result, matchErr := acceptExisting(retry, request)
|
||||
if matchErr == nil {
|
||||
result.WriteAttempted = true
|
||||
return result, nil
|
||||
}
|
||||
return Result{}, failure(FailureConflict, "resolve release creation", postStatus, matchErr)
|
||||
|
||||
@@ -339,3 +339,57 @@ func failureKind(t *testing.T, err error) FailureKind {
|
||||
func contains(value, substring string) bool {
|
||||
return len(substring) > 0 && len(value) >= len(substring) && strings.Contains(value, substring)
|
||||
}
|
||||
|
||||
func TestEnsureReleaseReconcilesInconsistentSuccessfulCreate(t *testing.T) {
|
||||
for _, mode := range []string{"matching", "conflicting", "unavailable"} {
|
||||
t.Run(mode, func(t *testing.T) {
|
||||
posts, lookups := 0, 0
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.Contains(r.URL.Path, "/tags/") && !strings.Contains(r.URL.Path, "/releases/"):
|
||||
writeTag(t, w, testCommit)
|
||||
case strings.Contains(r.URL.Path, "/releases/tags/"):
|
||||
lookups++
|
||||
if posts == 0 {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if mode == "unavailable" {
|
||||
http.Error(w, "unavailable", 503)
|
||||
return
|
||||
}
|
||||
body := testNote
|
||||
if mode == "conflicting" {
|
||||
body = "other content"
|
||||
}
|
||||
writeRelease(t, w, releaseFixture{title: "Example v1.2.3", body: body})
|
||||
case r.Method == http.MethodPost:
|
||||
posts++
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
json.NewEncoder(w).Encode(releaseResponse{ID: 10, TagName: "v1.2.3", Name: "inconsistent title", Body: testNote})
|
||||
default:
|
||||
t.Errorf("unexpected request %s", r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
result, err := testClient(server).EnsureRelease(context.Background(), testRequest(server.URL))
|
||||
if posts != 1 || lookups != 2 {
|
||||
t.Fatalf("posts=%d lookups=%d", posts, lookups)
|
||||
}
|
||||
switch mode {
|
||||
case "matching":
|
||||
if err != nil || !result.WriteAttempted {
|
||||
t.Fatalf("result=%#v err=%v", result, err)
|
||||
}
|
||||
case "conflicting":
|
||||
if failureKind(t, err) != FailureConflict {
|
||||
t.Fatal(err)
|
||||
}
|
||||
case "unavailable":
|
||||
if failureKind(t, err) != FailureUnknown {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user