Add semantic configuration profile comparison
This commit is contained in:
@@ -27,10 +27,72 @@ type PipelineLoadOptions struct {
|
||||
// LoadPipelineWithOptions loads pipeline configuration with strict field
|
||||
// checking and optional named-profile selection.
|
||||
func LoadPipelineWithOptions(path string, opts PipelineLoadOptions) (*PipelineConfig, error) {
|
||||
cfg, err := loadComposedPipeline(path, opts)
|
||||
sources, err := loadPipelineCompositionSources(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load pipeline config: %w", err)
|
||||
}
|
||||
if _, err := selectPipelineProfile(sources.envelope, opts); err != nil {
|
||||
return nil, fmt.Errorf("load pipeline config: %w", err)
|
||||
}
|
||||
if err := sources.loadOverlays(); err != nil {
|
||||
return nil, fmt.Errorf("load pipeline config: %w", err)
|
||||
}
|
||||
cfg, err := sources.resolve(opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load pipeline config: %w", err)
|
||||
}
|
||||
return finalizeLoadedPipeline(path, cfg)
|
||||
}
|
||||
|
||||
// LoadPipelineProfilePair resolves two explicit named profiles from one parsed
|
||||
// pipeline root and its declared source set. Each result is independently
|
||||
// decoded, defaulted, and finalized so later resolution can safely mutate one
|
||||
// effective pipeline without affecting the other.
|
||||
func LoadPipelineProfilePair(path, leftProfile, rightProfile string) (*PipelineConfig, *PipelineConfig, error) {
|
||||
if _, err := normalizePipelineProfileName(leftProfile, "left profile selection"); err != nil {
|
||||
return nil, nil, fmt.Errorf("load left pipeline profile: %w", err)
|
||||
}
|
||||
if _, err := normalizePipelineProfileName(rightProfile, "right profile selection"); err != nil {
|
||||
return nil, nil, fmt.Errorf("load right pipeline profile: %w", err)
|
||||
}
|
||||
if leftProfile == rightProfile {
|
||||
return nil, nil, fmt.Errorf("load pipeline profiles: left and right profile selections must differ")
|
||||
}
|
||||
sources, err := loadPipelineCompositionSources(path)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("load pipeline config: %w", err)
|
||||
}
|
||||
leftOptions := PipelineLoadOptions{Profile: &leftProfile}
|
||||
rightOptions := PipelineLoadOptions{Profile: &rightProfile}
|
||||
if _, err := selectPipelineProfile(sources.envelope, leftOptions); err != nil {
|
||||
return nil, nil, fmt.Errorf("load left pipeline profile: %w", err)
|
||||
}
|
||||
if _, err := selectPipelineProfile(sources.envelope, rightOptions); err != nil {
|
||||
return nil, nil, fmt.Errorf("load right pipeline profile: %w", err)
|
||||
}
|
||||
if err := sources.loadOverlays(); err != nil {
|
||||
return nil, nil, fmt.Errorf("load pipeline config: %w", err)
|
||||
}
|
||||
left, err := sources.resolve(leftOptions)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("load left pipeline profile: %w", err)
|
||||
}
|
||||
right, err := sources.resolve(rightOptions)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("load right pipeline profile: %w", err)
|
||||
}
|
||||
left, err = finalizeLoadedPipeline(path, left)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
right, err = finalizeLoadedPipeline(path, right)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return left, right, nil
|
||||
}
|
||||
|
||||
func finalizeLoadedPipeline(path string, cfg *PipelineConfig) (*PipelineConfig, error) {
|
||||
cfg.resolution.publishDeclared = cfg.Publish != nil
|
||||
applyPipelineDefaults(cfg)
|
||||
if err := resolveNotariusPaths(cfg, path); err != nil {
|
||||
@@ -201,6 +263,23 @@ func LoadPipelineCampaign(pipelinePath string, pipeline *PipelineConfig, campaig
|
||||
if err != nil {
|
||||
return LoadedPipelineCampaign{}, err
|
||||
}
|
||||
return LoadPipelineCampaignWithParty(pipelinePath, pipeline, campaignPath, campaign, party)
|
||||
}
|
||||
|
||||
// LoadPipelineCampaignWithParty combines an already loaded pipeline and
|
||||
// campaign with one already resolved campaign-owned party. It is useful when
|
||||
// more than one independently resolved pipeline must be expanded against the
|
||||
// exact same party document.
|
||||
func LoadPipelineCampaignWithParty(pipelinePath string, pipeline *PipelineConfig, campaignPath string, campaign *CampaignConfig, party ResolvedParty) (LoadedPipelineCampaign, error) {
|
||||
if pipeline == nil {
|
||||
return LoadedPipelineCampaign{}, fmt.Errorf("pipeline config is required")
|
||||
}
|
||||
if campaign == nil {
|
||||
return LoadedPipelineCampaign{}, fmt.Errorf("campaign config is required")
|
||||
}
|
||||
if party.Mode == "" {
|
||||
return LoadedPipelineCampaign{}, fmt.Errorf("resolved campaign party is required")
|
||||
}
|
||||
if party.Mode == PartyModeCanonical {
|
||||
if err := validateCanonicalPartySelection(campaign, nil); err != nil {
|
||||
return LoadedPipelineCampaign{}, err
|
||||
|
||||
Reference in New Issue
Block a user