Connect neutral delivery to the Gitea CLI
This commit is contained in:
109
delivery.go
109
delivery.go
@@ -2,10 +2,14 @@ package releasekit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
internalbuild "go.maximumdirect.net/releasekit/internal/build"
|
||||
internaldelivery "go.maximumdirect.net/releasekit/internal/delivery"
|
||||
"go.maximumdirect.net/releasekit/internal/forge"
|
||||
"go.maximumdirect.net/releasekit/internal/gitea"
|
||||
)
|
||||
|
||||
@@ -25,21 +29,57 @@ const (
|
||||
DeliveryUnknown DeliveryState = "unknown"
|
||||
)
|
||||
|
||||
// GiteaDestination supplies the hosted repository and explicit access token.
|
||||
type GiteaDestination struct {
|
||||
// Forge selects the hosted delivery backend.
|
||||
type Forge string
|
||||
|
||||
const (
|
||||
// ForgeGitea selects Gitea for hosted delivery.
|
||||
ForgeGitea Forge = "gitea"
|
||||
)
|
||||
|
||||
// DeliveryDestination supplies an explicitly selected hosted destination.
|
||||
type DeliveryDestination struct {
|
||||
Forge Forge
|
||||
BaseURL string
|
||||
Owner string
|
||||
Repository string
|
||||
Token string
|
||||
}
|
||||
|
||||
// DeliveryPreflightFailureKind classifies a failure while checking a delivery
|
||||
// destination's credentials and repository access.
|
||||
type DeliveryPreflightFailureKind string
|
||||
|
||||
const (
|
||||
DeliveryPreflightMissingCredential DeliveryPreflightFailureKind = "missing_credential"
|
||||
DeliveryPreflightInvalidCredential DeliveryPreflightFailureKind = "invalid_credential"
|
||||
DeliveryPreflightInsufficientPermissions DeliveryPreflightFailureKind = "insufficient_permissions"
|
||||
DeliveryPreflightInaccessibleDestination DeliveryPreflightFailureKind = "inaccessible_destination"
|
||||
DeliveryPreflightUnavailable DeliveryPreflightFailureKind = "unavailable"
|
||||
)
|
||||
|
||||
// DeliveryPreflightError reports a classified failure to verify a destination.
|
||||
type DeliveryPreflightError struct {
|
||||
Kind DeliveryPreflightFailureKind
|
||||
Err error
|
||||
}
|
||||
|
||||
func (err *DeliveryPreflightError) Error() string {
|
||||
if err.Err == nil {
|
||||
return fmt.Sprintf("delivery preflight %s", err.Kind)
|
||||
}
|
||||
return fmt.Sprintf("delivery preflight %s: %v", err.Kind, err.Err)
|
||||
}
|
||||
|
||||
func (err *DeliveryPreflightError) Unwrap() error { return err.Err }
|
||||
|
||||
// DeliveryAsset identifies a hosted asset by filename and SHA-256 digest.
|
||||
type DeliveryAsset struct {
|
||||
Filename string
|
||||
SHA256 string
|
||||
}
|
||||
|
||||
// DeliveryRequest identifies a local tagged checkout and its explicit Gitea
|
||||
// DeliveryRequest identifies a local tagged checkout and its explicit
|
||||
// destination. Build selects a managed build; Prebuilt supplies caller-owned
|
||||
// build output instead. They cannot both be set. Either may be nil for
|
||||
// page-only delivery when both are nil. Build with no targets, or an empty
|
||||
@@ -54,7 +94,7 @@ type DeliveryRequest struct {
|
||||
// ExpectedTag optionally requires the full CI event tag to match the
|
||||
// selected module's derived tag before building or making hosted requests.
|
||||
ExpectedTag string
|
||||
Destination GiteaDestination
|
||||
Destination DeliveryDestination
|
||||
// Build selects binaries to build in temporary storage outside the checkout.
|
||||
Build *BuildSpec
|
||||
// Prebuilt supplies an existing build whose files remain caller-owned.
|
||||
@@ -98,9 +138,9 @@ type DeliveryResult struct {
|
||||
// managed builds require their selected source files in the working tree.
|
||||
func Deliver(ctx context.Context, request DeliveryRequest) (DeliveryResult, error) {
|
||||
result := DeliveryResult{Version: request.Version, State: DeliveryNotAttempted}
|
||||
destination := gitea.Destination{
|
||||
BaseURL: request.Destination.BaseURL, Owner: request.Destination.Owner,
|
||||
Repository: request.Destination.Repository, Token: request.Destination.Token,
|
||||
backend, err := deliveryBackend(request.Destination)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
var prebuilt *internalbuild.Result
|
||||
if request.Prebuilt != nil {
|
||||
@@ -112,7 +152,7 @@ func Deliver(ctx context.Context, request DeliveryRequest) (DeliveryResult, erro
|
||||
Product: request.Product,
|
||||
Version: request.Version,
|
||||
ExpectedTag: request.ExpectedTag,
|
||||
Destination: destination,
|
||||
Backend: backend,
|
||||
Build: internalBuildSpec(request.Build),
|
||||
Prebuilt: prebuilt,
|
||||
Output: request.Output,
|
||||
@@ -129,10 +169,59 @@ func Deliver(ctx context.Context, request DeliveryRequest) (DeliveryResult, erro
|
||||
result.Pending = deliveryAssets(internalResult.Pending)
|
||||
result.Conflicting = deliveryAssets(internalResult.Conflicting)
|
||||
result.Uncertain = deliveryAssets(internalResult.Uncertain)
|
||||
return result, err
|
||||
return result, publicPreflightError(err)
|
||||
}
|
||||
|
||||
func deliveryAssets(assets []gitea.AssetIdentity) []DeliveryAsset {
|
||||
// PreflightDelivery checks destination credentials and repository access using
|
||||
// read-only backend operations. It does not require a checkout or published tag.
|
||||
func PreflightDelivery(ctx context.Context, destination DeliveryDestination) error {
|
||||
backend, err := deliveryBackend(destination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return publicPreflightError(backend.Preflight(ctx))
|
||||
}
|
||||
|
||||
func deliveryBackend(destination DeliveryDestination) (forge.Backend, error) {
|
||||
selection := Forge(strings.TrimSpace(string(destination.Forge)))
|
||||
switch selection {
|
||||
case ForgeGitea:
|
||||
return gitea.NewBackend(gitea.Destination{
|
||||
BaseURL: destination.BaseURL, Owner: destination.Owner,
|
||||
Repository: destination.Repository, Token: destination.Token,
|
||||
}, nil), nil
|
||||
case "":
|
||||
return nil, errors.New("delivery forge must be selected explicitly")
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported delivery forge %q", destination.Forge)
|
||||
}
|
||||
}
|
||||
|
||||
func publicPreflightError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
var failure *forge.PreflightFailure
|
||||
if !errors.As(err, &failure) {
|
||||
return err
|
||||
}
|
||||
kind := DeliveryPreflightUnavailable
|
||||
switch failure.Kind {
|
||||
case forge.PreflightMissingCredential:
|
||||
kind = DeliveryPreflightMissingCredential
|
||||
case forge.PreflightInvalidCredential:
|
||||
kind = DeliveryPreflightInvalidCredential
|
||||
case forge.PreflightInsufficientPermissions:
|
||||
kind = DeliveryPreflightInsufficientPermissions
|
||||
case forge.PreflightInaccessibleDestination:
|
||||
kind = DeliveryPreflightInaccessibleDestination
|
||||
case forge.PreflightUnavailable:
|
||||
kind = DeliveryPreflightUnavailable
|
||||
}
|
||||
return &DeliveryPreflightError{Kind: kind, Err: failure.Err}
|
||||
}
|
||||
|
||||
func deliveryAssets(assets []internaldelivery.AssetIdentity) []DeliveryAsset {
|
||||
result := make([]DeliveryAsset, 0, len(assets))
|
||||
for _, asset := range assets {
|
||||
result = append(result, DeliveryAsset{Filename: asset.Filename, SHA256: asset.SHA256})
|
||||
|
||||
Reference in New Issue
Block a user