Integrate artifact locks into publish
This commit is contained in:
@@ -114,26 +114,45 @@ func (publishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: build runtime artifact catalog: %w", err)
|
||||
}
|
||||
publishOutputs, skippedOptionalOutputs, skippedUnselectedOutputs, lockedOutputs, err := resolvePublishOutputs(
|
||||
sessionPaths,
|
||||
m,
|
||||
publishRules, err := resolvePublishRules(
|
||||
runtimeCatalog,
|
||||
env.Config.Pipeline.Publish.Outputs,
|
||||
env.Config.Pipeline.Publish.Locks,
|
||||
env.SelectedArtifactKeys,
|
||||
runPrefix,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: resolve publish output rules: %w", err)
|
||||
}
|
||||
initialLocks, err := readPublishOutputLocks(ctx, env.ObjectStore, sessionPrefix, publishRules)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: read publish output locks: %w", err)
|
||||
}
|
||||
var priorCommit *artifacts.RemoteCommitManifest
|
||||
if publishRulesNeedPriorCommit(publishRules, initialLocks) {
|
||||
priorCommit, err = loadPriorPublishCommit(ctx, env.ObjectStore, sessionPrefix, m.Campaign, m.SessionID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: load prior current commit: %w", err)
|
||||
}
|
||||
}
|
||||
discoveredOutputs, err := discoverPublishOutputs(sessionPaths, m, runtimeCatalog, publishRules, initialLocks)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: discover publish outputs: %w", err)
|
||||
}
|
||||
outputPlan, err := buildPublishOutputPlan(sessionPrefix, runPrefix, publishRules, discoveredOutputs, initialLocks, priorCommit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: plan publish outputs: %w", err)
|
||||
}
|
||||
|
||||
runUploaded := publishUploadPaths(runFiles)
|
||||
publishedUploaded := publishOutputPaths(publishOutputs)
|
||||
publishedUploaded := publishOutputPaths(outputPlan)
|
||||
previousUploaded := publishUploadPaths(previousFiles)
|
||||
commitKey := artifacts.S3RunCommitKey(sessionPrefix, runID)
|
||||
pointerKey := artifacts.S3CurrentCommitPointerKey(sessionPrefix)
|
||||
|
||||
transfers, err := buildPublishTransferPlan(runPrefix, runFiles, runSources, previousFiles, previousSources, publishOutputs)
|
||||
carriedDeclarations, err := verifyCarriedPublishOutputs(ctx, env.ObjectStore, outputPlan)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: %w", err)
|
||||
}
|
||||
transfers, err := buildPublishTransferPlan(runPrefix, runFiles, runSources, previousFiles, previousSources, outputPlan)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: build immutable upload mapping: %w", err)
|
||||
}
|
||||
@@ -146,9 +165,7 @@ func (publishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
||||
runUploaded,
|
||||
publishedUploaded,
|
||||
previousUploaded,
|
||||
skippedOptionalOutputs,
|
||||
skippedUnselectedOutputs,
|
||||
lockedOutputs,
|
||||
outputPlan,
|
||||
commitKey,
|
||||
pointerKey,
|
||||
))
|
||||
@@ -165,10 +182,11 @@ func (publishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
||||
// Durability boundary: transfer every declared immutable object, write the
|
||||
// immutable commit, perform pre-pointer checks, then write the sole mutable
|
||||
// current pointer exactly once.
|
||||
declarations, err := uploadPublishTransfers(ctx, env.ObjectStore, uploader, transfers)
|
||||
uploadedDeclarations, err := uploadPublishTransfers(ctx, env.ObjectStore, uploader, transfers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: %w", err)
|
||||
}
|
||||
declarations := combinePublishDeclarations(uploadedDeclarations, carriedDeclarations)
|
||||
committed, err := writeImmutablePublishCommit(
|
||||
ctx,
|
||||
env.ObjectStore,
|
||||
@@ -182,51 +200,24 @@ func (publishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("publish: %w", err)
|
||||
}
|
||||
if err := revalidatePublishCommitLocks(ctx, env, publishOutputs); err != nil {
|
||||
if err := revalidatePublishOutputLocks(ctx, env.ObjectStore, sessionPrefix, outputPlan); err != nil {
|
||||
return nil, fmt.Errorf("publish: revalidate locks before current commit selection: %w", err)
|
||||
}
|
||||
if err := writePublishCurrentPointer(ctx, uploader, committed); err != nil {
|
||||
return nil, fmt.Errorf("publish: %w", err)
|
||||
}
|
||||
|
||||
return &StageResult{
|
||||
Metadata: map[string]any{
|
||||
"stage": "publish",
|
||||
"uploaded": true,
|
||||
"s3_bucket": bucket,
|
||||
"s3_run_prefix": runPrefix,
|
||||
"run_files_uploaded": len(runUploaded),
|
||||
"run_uploaded_paths": runUploaded,
|
||||
"published_files_uploaded": len(publishedUploaded),
|
||||
"published_paths": publishedUploaded,
|
||||
"previous_files_uploaded": len(previousUploaded),
|
||||
"previous_uploaded_paths": previousUploaded,
|
||||
"skipped_optional_outputs": skippedOptionalOutputs,
|
||||
"skipped_unselected_outputs": skippedUnselectedOutputMetadata(skippedUnselectedOutputs),
|
||||
"locked_output_count": len(lockedOutputs),
|
||||
"locked_outputs": lockedOutputMetadata(lockedOutputs),
|
||||
"remote_commit_key": commitKey,
|
||||
"current_commit_pointer_key": pointerKey,
|
||||
"audio_upload_skipped": true,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func revalidatePublishCommitLocks(ctx context.Context, env *Env, outputs []publishOutput) error {
|
||||
if env == nil || env.RevalidatePublishLocks == nil || len(outputs) == 0 {
|
||||
return nil
|
||||
}
|
||||
locks, err := env.RevalidatePublishLocks(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lockSet := publishLockSet(locks)
|
||||
for _, output := range outputs {
|
||||
if lock, locked := lockSet[output.Source]; locked {
|
||||
return fmt.Errorf("source %q is locked: %s", output.Source, strings.TrimSpace(lock.Reason))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return &StageResult{Metadata: publishMetadata(
|
||||
bucket,
|
||||
runPrefix,
|
||||
runID,
|
||||
runUploaded,
|
||||
publishedUploaded,
|
||||
previousUploaded,
|
||||
outputPlan,
|
||||
commitKey,
|
||||
pointerKey,
|
||||
)}, nil
|
||||
}
|
||||
|
||||
func publishDisabled(env *Env) bool {
|
||||
@@ -310,9 +301,7 @@ func publishMetadata(
|
||||
runUploaded []string,
|
||||
publishedUploaded []string,
|
||||
previousUploaded []string,
|
||||
skippedOptionalOutputs []string,
|
||||
skippedUnselectedOutputs []publishSkippedUnselectedOutput,
|
||||
lockedOutputs []publishLockedOutput,
|
||||
outputPlan *publishOutputPlan,
|
||||
commitKey string,
|
||||
pointerKey string,
|
||||
) map[string]any {
|
||||
@@ -328,40 +317,9 @@ func publishMetadata(
|
||||
"published_paths": append([]string(nil), publishedUploaded...),
|
||||
"previous_files_uploaded": len(previousUploaded),
|
||||
"previous_uploaded_paths": append([]string(nil), previousUploaded...),
|
||||
"skipped_optional_outputs": append([]string(nil), skippedOptionalOutputs...),
|
||||
"skipped_unselected_outputs": skippedUnselectedOutputMetadata(skippedUnselectedOutputs),
|
||||
"locked_output_count": len(lockedOutputs),
|
||||
"locked_outputs": lockedOutputMetadata(lockedOutputs),
|
||||
"publish_output_outcomes": publishOutputOutcomeMetadata(outputPlan),
|
||||
"remote_commit_key": commitKey,
|
||||
"current_commit_pointer_key": pointerKey,
|
||||
"audio_upload_skipped": true,
|
||||
}
|
||||
}
|
||||
|
||||
func skippedUnselectedOutputMetadata(skipped []publishSkippedUnselectedOutput) []map[string]any {
|
||||
out := make([]map[string]any, 0, len(skipped))
|
||||
for _, item := range skipped {
|
||||
out = append(out, map[string]any{
|
||||
"source": item.Source,
|
||||
"dest": item.Dest,
|
||||
"required": item.Required,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func lockedOutputMetadata(locked []publishLockedOutput) []map[string]any {
|
||||
out := make([]map[string]any, 0, len(locked))
|
||||
for _, item := range locked {
|
||||
out = append(out, map[string]any{
|
||||
"source": item.Source,
|
||||
"dest": item.Dest,
|
||||
"remote_key": item.RemoteKey,
|
||||
"reason": item.Reason,
|
||||
"required": item.Required,
|
||||
"local_path": item.LocalPath,
|
||||
"provenance": item.Provenance,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user