Move release page recovery into shared delivery
This commit is contained in:
91
internal/delivery/page.go
Normal file
91
internal/delivery/page.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package delivery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go.maximumdirect.net/releasekit/internal/forge"
|
||||
)
|
||||
|
||||
func coordinateRelease(ctx context.Context, backend forge.Backend, tag, commit, note string) (forge.Release, forge.WriteEvidence, error) {
|
||||
observedCommit, err := backend.TagCommit(ctx, tag)
|
||||
if err != nil {
|
||||
return forge.Release{}, forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, err
|
||||
}
|
||||
if observedCommit != commit {
|
||||
return forge.Release{}, forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, &forge.Failure{
|
||||
Kind: forge.FailureConflict,
|
||||
Err: fmt.Errorf("hosted tag %q targets %q, want %q", tag, observedCommit, commit),
|
||||
}
|
||||
}
|
||||
|
||||
existing, err := backend.FindRelease(ctx, tag)
|
||||
if err == nil {
|
||||
if !matchesExistingRelease(existing, tag, note) {
|
||||
return forge.Release{}, forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, &forge.Failure{
|
||||
Kind: forge.FailureConflict,
|
||||
Err: errors.New("existing release does not match the committed note and stable tag"),
|
||||
}
|
||||
}
|
||||
return existing, forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, nil
|
||||
}
|
||||
if !isForgeFailure(err, forge.FailureNotFound) {
|
||||
return forge.Release{}, forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, err
|
||||
}
|
||||
|
||||
request := forge.CreateReleaseRequest{
|
||||
Tag: tag, Commit: commit, Title: releaseNoteTitle(note), Body: note,
|
||||
}
|
||||
created, evidence, createErr := backend.CreateRelease(ctx, request)
|
||||
if createErr == nil && matchesCreatedRelease(created, request) {
|
||||
return created, evidence, nil
|
||||
}
|
||||
if createErr == nil {
|
||||
createErr = &forge.Failure{Kind: forge.FailureMalformed, Err: errors.New("created release does not match the requested stable release")}
|
||||
}
|
||||
if evidence.Disposition != forge.WriteConflict && evidence.Disposition != forge.WriteUncertain && !isForgeFailure(createErr, forge.FailureMalformed) {
|
||||
return forge.Release{}, evidence, createErr
|
||||
}
|
||||
|
||||
return reconcileReleaseCreate(ctx, backend, tag, note, evidence, createErr)
|
||||
}
|
||||
|
||||
func reconcileReleaseCreate(ctx context.Context, backend forge.Backend, tag, note string, evidence forge.WriteEvidence, createErr error) (forge.Release, forge.WriteEvidence, error) {
|
||||
existing, lookupErr := backend.FindRelease(ctx, tag)
|
||||
if lookupErr == nil {
|
||||
if matchesExistingRelease(existing, tag, note) {
|
||||
return existing, evidence, nil
|
||||
}
|
||||
return forge.Release{}, evidence, &forge.Failure{Kind: forge.FailureConflict, Err: errors.Join(createErr, errors.New("reconciled release does not match the committed note and stable tag"))}
|
||||
}
|
||||
if isForgeFailure(lookupErr, forge.FailureNotFound) {
|
||||
if evidence.Disposition == forge.WriteConflict {
|
||||
return forge.Release{}, evidence, &forge.Failure{Kind: forge.FailureConflict, Err: createErr}
|
||||
}
|
||||
return forge.Release{}, evidence, &forge.Failure{Kind: forge.FailureUnknown, Err: createErr}
|
||||
}
|
||||
return forge.Release{}, evidence, &forge.Failure{Kind: forge.FailureUnknown, Err: errors.Join(createErr, lookupErr)}
|
||||
}
|
||||
|
||||
func matchesExistingRelease(release forge.Release, tag, note string) bool {
|
||||
return release.Tag == tag && release.Body == note && !release.Draft && !release.Prerelease
|
||||
}
|
||||
|
||||
func matchesCreatedRelease(release forge.Release, request forge.CreateReleaseRequest) bool {
|
||||
return release.Tag == request.Tag && release.Body == request.Body && release.Title == request.Title && !release.Draft && !release.Prerelease
|
||||
}
|
||||
|
||||
func releaseNoteTitle(note string) string {
|
||||
first := strings.SplitN(note, "\n", 2)[0]
|
||||
if !strings.HasPrefix(first, "# ") {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(strings.TrimPrefix(first, "# "))
|
||||
}
|
||||
|
||||
func isForgeFailure(err error, kind forge.FailureKind) bool {
|
||||
var failure *forge.Failure
|
||||
return errors.As(err, &failure) && failure.Kind == kind
|
||||
}
|
||||
Reference in New Issue
Block a user