153 lines
5.5 KiB
Go
153 lines
5.5 KiB
Go
// Package forge defines the backend-neutral operations used by hosted delivery.
|
|
package forge
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
)
|
|
|
|
// Backend provides the hosted operations needed by the shared delivery
|
|
// workflow. Implementations own destination-specific rules and protocol
|
|
// details; the shared workflow uses only the logical values and evidence in
|
|
// this package.
|
|
type Backend interface {
|
|
// Preflight verifies credentials and access to the configured destination
|
|
// using read-only operations. It does not depend on a source tag or release.
|
|
Preflight(ctx context.Context) error
|
|
// TagCommit returns the commit observed for the complete tag.
|
|
TagCommit(ctx context.Context, tag string) (string, error)
|
|
// FindRelease returns the release for the complete tag. A missing release
|
|
// is reported with FailureNotFound.
|
|
FindRelease(ctx context.Context, tag string) (Release, error)
|
|
// CreateRelease creates the requested release and returns the protocol
|
|
// evidence even when an error occurs.
|
|
CreateRelease(ctx context.Context, request CreateReleaseRequest) (Release, WriteEvidence, error)
|
|
// ListAssets returns the assets attached to the release identified by handle.
|
|
ListAssets(ctx context.Context, releaseHandle any) ([]Asset, error)
|
|
// OpenAsset opens the remote asset identified by handle. The caller owns and
|
|
// must close the returned stream, including when reading it fails.
|
|
OpenAsset(ctx context.Context, assetHandle any) (io.ReadCloser, error)
|
|
// UploadAsset uploads content to the release identified by handle. The
|
|
// backend borrows content for the duration of this call and must finish any
|
|
// request or multipart work before returning; it must not close content.
|
|
UploadAsset(ctx context.Context, releaseHandle any, filename string, content io.Reader) (WriteEvidence, error)
|
|
}
|
|
|
|
// Release contains the logical release properties used by shared delivery.
|
|
// Handle is opaque to shared code and is interpreted only by the backend that
|
|
// produced it.
|
|
type Release struct {
|
|
URL string
|
|
Tag string
|
|
Title string
|
|
Body string
|
|
Draft bool
|
|
Prerelease bool
|
|
Handle any
|
|
}
|
|
|
|
// CreateReleaseRequest contains the release properties requested by shared
|
|
// delivery.
|
|
type CreateReleaseRequest struct {
|
|
Tag string
|
|
Commit string
|
|
Title string
|
|
Body string
|
|
Draft bool
|
|
Prerelease bool
|
|
}
|
|
|
|
// Asset contains the remote properties needed to compare an attachment with a
|
|
// declared local asset. Handle is opaque to shared code and is interpreted only
|
|
// by the backend that produced it.
|
|
type Asset struct {
|
|
Filename string
|
|
Size int64
|
|
Handle any
|
|
}
|
|
|
|
// PreflightFailureKind classifies a failure to verify credentials or access to
|
|
// a delivery destination.
|
|
type PreflightFailureKind string
|
|
|
|
const (
|
|
PreflightMissingCredential PreflightFailureKind = "missing_credential"
|
|
PreflightInvalidCredential PreflightFailureKind = "invalid_credential"
|
|
PreflightInsufficientPermissions PreflightFailureKind = "insufficient_permissions"
|
|
PreflightInaccessibleDestination PreflightFailureKind = "inaccessible_destination"
|
|
PreflightUnavailable PreflightFailureKind = "unavailable"
|
|
)
|
|
|
|
// PreflightFailure reports a classified credential or destination access
|
|
// failure. Err retains the underlying cause for diagnostics and cancellation
|
|
// identity.
|
|
type PreflightFailure struct {
|
|
Kind PreflightFailureKind
|
|
Err error
|
|
}
|
|
|
|
func (f *PreflightFailure) Error() string {
|
|
if f.Err != nil {
|
|
return string(f.Kind) + ": " + f.Err.Error()
|
|
}
|
|
return string(f.Kind)
|
|
}
|
|
|
|
// Unwrap returns the cause of the preflight failure, if any.
|
|
func (f *PreflightFailure) Unwrap() error { return f.Err }
|
|
|
|
// FailureKind classifies a backend-neutral delivery operation failure.
|
|
type FailureKind string
|
|
|
|
const (
|
|
FailureInvalid FailureKind = "invalid_request"
|
|
FailureNotFound FailureKind = "not_found"
|
|
FailureUnauthorized FailureKind = "unauthorized"
|
|
FailureConflict FailureKind = "conflict"
|
|
FailureMalformed FailureKind = "malformed_response"
|
|
FailureUnverifiable FailureKind = "unverifiable"
|
|
FailureTransport FailureKind = "transport"
|
|
FailureRejected FailureKind = "rejected"
|
|
FailureUnknown FailureKind = "unknown"
|
|
)
|
|
|
|
// Failure reports a backend-neutral operation failure. Backend-specific
|
|
// status and operation details belong in Err. Err is retained for errors.Is
|
|
// and errors.As inspection.
|
|
type Failure struct {
|
|
Kind FailureKind
|
|
Err error
|
|
}
|
|
|
|
func (f *Failure) Error() string {
|
|
if f.Err != nil {
|
|
return string(f.Kind) + ": " + f.Err.Error()
|
|
}
|
|
return string(f.Kind)
|
|
}
|
|
|
|
// Unwrap returns the cause of the operation failure, if any.
|
|
func (f *Failure) Unwrap() error { return f.Err }
|
|
|
|
// WriteDisposition describes the backend's evidence about a write operation.
|
|
type WriteDisposition string
|
|
|
|
const (
|
|
WriteNotAttempted WriteDisposition = "not_attempted"
|
|
WriteAccepted WriteDisposition = "accepted"
|
|
WriteRejected WriteDisposition = "rejected"
|
|
WriteConflict WriteDisposition = "conflict"
|
|
WriteUncertain WriteDisposition = "uncertain"
|
|
)
|
|
|
|
// WriteEvidence records whether a write was handed to the transport and what
|
|
// its acknowledgment establishes. Accepted means the backend received and
|
|
// decoded the required protocol acknowledgment; shared content checks still
|
|
// apply. Uncertain means the outcome could not be established. Attempted marks
|
|
// handoff to the transport and does not claim the server received the request.
|
|
// Evidence remains meaningful when the operation also returns an error.
|
|
type WriteEvidence struct {
|
|
Attempted bool
|
|
Disposition WriteDisposition
|
|
}
|