config/plan.go

Summary

Maintainability
A
40 mins
Test Coverage
package config

import "fmt"

type Plan struct {
    Name        string   `json:"-"`
    Disabled    string   `json:"disabled,omitempty"`
    Extends     string   `json:"extends,omitempty"`
    Stages      []*Stage `json:"stages,omitempty"`
    Environment []string `json:"environment,omitempty"`
}

func (p *Plan) Clone() *Plan {
    stages := []*Stage{}
    for _, stage := range p.Stages {
        stages = append(stages, stage)
    }

    environment := []string{}
    for _, value := range p.Environment {
        environment = append(environment, value)
    }

    return &Plan{
        Name:        p.Name,
        Disabled:    p.Disabled,
        Extends:     p.Extends,
        Stages:      stages,
        Environment: environment,
    }
}

func (p *Plan) Merge(child *Plan) error {
    for _, stage := range child.Stages {
        if err := p.AddStage(stage); err != nil {
            return err
        }
    }

    p.Disabled = extendString(child.Disabled, p.Disabled)
    p.Environment = append(p.Environment, child.Environment...)
    return nil
}

func (p *Plan) AddStage(stage *Stage) error {
    if stage.BeforeStage != "" && stage.AfterStage != "" {
        return fmt.Errorf(
            "before_stage and after_stage declared in %s/%s",
            p.Name,
            stage.Name,
        )
    }

    if index := p.StageIndex(stage.Name); index >= 0 {
        if stage.BeforeStage != "" || stage.AfterStage != "" {
            return fmt.Errorf(
                "%s/%s exists in parent config, but before_stage or after_stage is also declared",
                p.Name,
                stage.Name,
            )
        }

        p.Stages[index] = stage
        return nil
    }

    targetStage := stage.Name

    if stage.BeforeStage != "" {
        if index := p.StageIndex(stage.BeforeStage); index >= 0 {
            p.InsertStage(stage, index)
            return nil
        }

        targetStage = stage.BeforeStage
    }

    if stage.AfterStage != "" {
        if index := p.StageIndex(stage.AfterStage); index >= 0 {
            p.InsertStage(stage, index+1)
            return nil
        }

        targetStage = stage.AfterStage
    }

    return fmt.Errorf(
        "stage %s/%s not declared in parent config",
        p.Name,
        targetStage,
    )
}

func (p *Plan) StageIndex(name string) int {
    if name == "" {
        return -1
    }

    for i, stage := range p.Stages {
        if stage.Name == name {
            return i
        }
    }

    return -1
}

func (p *Plan) InsertStage(stage *Stage, index int) {
    p.Stages = append(p.Stages, nil)
    copy(p.Stages[index+1:], p.Stages[index:])
    p.Stages[index] = stage
}