Return write evidence from Gitea operations

This commit is contained in:
2026-11-01 18:02:05 +00:00
parent 02bd120aed
commit ddac9e3c73
4 changed files with 280 additions and 22 deletions

View File

@@ -2,6 +2,7 @@ package gitea
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
@@ -75,6 +76,92 @@ func (b *Backend) Preflight(ctx context.Context) error {
return nil
}
func (b *Backend) CreateRelease(ctx context.Context, request forge.CreateReleaseRequest) (forge.Release, forge.WriteEvidence, error) {
if strings.TrimSpace(request.Tag) == "" || !validObjectID(request.Commit) {
return forge.Release{}, forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, &forge.Failure{
Kind: forge.FailureInvalid, Err: errors.New("a full tag and lowercase Git commit ID are required"),
}
}
_, apiRoot, err := b.destinationAPI("create release")
if err != nil {
return forge.Release{}, forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, err
}
body, err := json.Marshal(createReleaseRequest{
TagName: request.Tag, TargetCommitish: request.Commit,
Name: request.Title, Body: request.Body,
Draft: request.Draft, Prerelease: request.Prerelease,
})
if err != nil {
return forge.Release{}, forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, &forge.Failure{Kind: forge.FailureInvalid, Err: err}
}
created, status, err := b.client.postRelease(ctx, b.client.httpClient(), b.destination.Token, apiRoot+"/releases", body)
if err == nil && created.ID <= 0 {
err = failure(FailureMalformed, "verify created release", status, errors.New("release response does not contain a positive ID"))
}
evidence := writeEvidence(status, err)
if err != nil {
return forge.Release{}, evidence, neutralFailure(err)
}
return forge.Release{
URL: created.URL,
Tag: created.TagName,
Title: created.Title,
Body: created.Body,
Draft: created.Draft,
Prerelease: created.Prerelease,
Handle: releaseHandle{id: created.ID},
}, evidence, nil
}
func (b *Backend) UploadAsset(ctx context.Context, handle any, filename string, content io.Reader) (forge.WriteEvidence, error) {
release, ok := handle.(releaseHandle)
if !ok || release.id <= 0 {
return forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, &forge.Failure{Kind: forge.FailureInvalid, Err: errors.New("release handle was not created by the Gitea backend")}
}
if strings.TrimSpace(filename) == "" || content == nil {
return forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, &forge.Failure{Kind: forge.FailureInvalid, Err: errors.New("asset filename and content reader are required")}
}
_, apiRoot, err := b.destinationAPI("upload release asset")
if err != nil {
return forge.WriteEvidence{Disposition: forge.WriteNotAttempted}, err
}
status, err := b.client.uploadAsset(ctx, b.client.httpClient(), b.destination.Token, apiRoot, release.id, filename, content)
evidence := writeEvidence(status, err)
if err != nil {
return evidence, neutralFailure(err)
}
return evidence, nil
}
func writeEvidence(status int, err error) forge.WriteEvidence {
evidence := forge.WriteEvidence{Attempted: status != 0, Disposition: forge.WriteNotAttempted}
var backendFailure *Failure
if err != nil && errors.As(err, &backendFailure) && backendFailure.Kind == FailureTransport {
evidence.Attempted = true
}
if !evidence.Attempted {
return evidence
}
if err == nil {
evidence.Disposition = forge.WriteAccepted
return evidence
}
if status == http.StatusConflict {
evidence.Disposition = forge.WriteConflict
return evidence
}
if status >= http.StatusInternalServerError || errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
evidence.Disposition = forge.WriteUncertain
return evidence
}
if errors.As(err, &backendFailure) && (backendFailure.Kind == FailureTransport || backendFailure.Kind == FailureMalformed) {
evidence.Disposition = forge.WriteUncertain
return evidence
}
evidence.Disposition = forge.WriteRejected
return evidence
}
func (repository repositoryResponse) matches(destination Destination) bool {
if repository.ID <= 0 || !strings.EqualFold(repository.Name, destination.Repository) {
return false
@@ -237,3 +324,5 @@ func neutralFailure(err error) error {
}
return &forge.Failure{Kind: kind, Err: err}
}
var _ forge.Backend = (*Backend)(nil)