Preserve asset inspection error causes through delivery
This commit is contained in:
@@ -124,6 +124,7 @@ func uploadMissingAssets(ctx context.Context, backend forge.Backend, releaseHand
|
||||
result = UploadResult{State: Partial}
|
||||
preflightConflict := false
|
||||
preflightUnverifiable := false
|
||||
var inspectionErrors []error
|
||||
var missing []artifact.ExpectedAsset
|
||||
pending := make(map[string]struct{}, len(expected))
|
||||
// Keep the initial observation order and compact pending identities once,
|
||||
@@ -152,17 +153,20 @@ func uploadMissingAssets(ctx context.Context, backend forge.Backend, releaseHand
|
||||
case AssetUnverifiable:
|
||||
preflightUnverifiable = true
|
||||
result.Uncertain = append(result.Uncertain, item)
|
||||
if observation.Err != nil {
|
||||
inspectionErrors = append(inspectionErrors, fmt.Errorf("verify existing attachment %q: %w", item.Filename, observation.Err))
|
||||
}
|
||||
default:
|
||||
return result, &forge.Failure{Kind: forge.FailureInvalid, Err: fmt.Errorf("asset %q has no inspection result", observation.Expected.Filename)}
|
||||
}
|
||||
}
|
||||
if preflightConflict {
|
||||
result.State = Conflict
|
||||
return result, &forge.Failure{Kind: forge.FailureConflict, Err: errors.New("one or more existing attachments conflict")}
|
||||
return result, &forge.Failure{Kind: forge.FailureConflict, Err: errors.Join(errors.New("one or more existing attachments conflict"), errors.Join(inspectionErrors...))}
|
||||
}
|
||||
if preflightUnverifiable {
|
||||
result.State = NotAttempted
|
||||
return result, &forge.Failure{Kind: forge.FailureUnverifiable, Err: errors.New("one or more existing attachments could not be verified")}
|
||||
return result, &forge.Failure{Kind: forge.FailureUnverifiable, Err: errors.Join(errors.New("one or more existing attachments could not be verified"), errors.Join(inspectionErrors...))}
|
||||
}
|
||||
if len(pending) == 0 {
|
||||
result.State = Complete
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.maximumdirect.net/releasekit/internal/artifact"
|
||||
@@ -173,6 +174,35 @@ func TestUploadMissingAssetsStopsBeforeWritesForConflictOrUnverifiableContent(t
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadMissingAssetsPreservesInspectionCausesAndConflictPrecedence(t *testing.T) {
|
||||
readErr := errors.New("asset download failed")
|
||||
for _, conflict := range []bool{false, true} {
|
||||
name := "unverifiable"
|
||||
if conflict {
|
||||
name = "conflict"
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
backend := &assetBackend{}
|
||||
inspection := Inspection{Assets: []AssetInspection{
|
||||
{Expected: expectedAsset("canceled.bin", []byte("a")), State: AssetUnverifiable, Err: context.Canceled},
|
||||
{Expected: expectedAsset("unreadable.bin", []byte("b")), State: AssetUnverifiable, Err: readErr},
|
||||
}}
|
||||
wantState, wantKind := NotAttempted, forge.FailureUnverifiable
|
||||
if conflict {
|
||||
inspection.Assets = append(inspection.Assets, AssetInspection{Expected: expectedAsset("conflicting.bin", []byte("c")), State: AssetConflicting})
|
||||
wantState, wantKind = Conflict, forge.FailureConflict
|
||||
}
|
||||
result, err := uploadMissingAssets(context.Background(), backend, "release", inspection)
|
||||
if !isForgeFailure(err, wantKind) || result.State != wantState || len(result.Uncertain) != 2 || len(backend.uploadNames) != 0 {
|
||||
t.Fatalf("result = %#v, error %v", result, err)
|
||||
}
|
||||
if !errors.Is(err, context.Canceled) || !errors.Is(err, readErr) || !strings.Contains(err.Error(), "canceled.bin") || !strings.Contains(err.Error(), "unreadable.bin") {
|
||||
t.Fatalf("aggregate lost cause or asset context: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadMissingAssetsReconcilesOnceAndKeepsLaterAssetsPending(t *testing.T) {
|
||||
assets := []artifact.ExpectedAsset{
|
||||
expectedAsset("a.bin", []byte("a")),
|
||||
|
||||
Reference in New Issue
Block a user