Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing graph pipeline validation #1011

Merged
merged 3 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 41 additions & 10 deletions models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@ package models

import (
"fmt"
"slices"
"strings"
"time"

envmanModels "github.com/bitrise-io/envman/models"
stepmanModels "github.com/bitrise-io/stepman/models"
)

type GraphPipelineAlwaysRunMode string

const (
GraphPipelineAlwaysRunModeOff GraphPipelineAlwaysRunMode = "off"
GraphPipelineAlwaysRunModeWorkflow GraphPipelineAlwaysRunMode = "workflow"
)

const (
FormatVersion = "17"
FormatVersion = "18"
StepListItemWithKey = "with"
StepListItemStepBundleKeyPrefix = "bundle::"
)
Expand Down Expand Up @@ -39,12 +47,12 @@ type StepListStepItemModel map[string]stepmanModels.StepModel
type StepListItemModel map[string]interface{}

type PipelineModel struct {
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Triggers Triggers `json:"triggers,omitempty" yaml:"triggers,omitempty"`
Stages []StageListItemModel `json:"stages,omitempty" yaml:"stages,omitempty"`
Workflows DagWorkflowListItemModel `json:"workflows,omitempty" yaml:"workflows,omitempty"`
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Triggers Triggers `json:"triggers,omitempty" yaml:"triggers,omitempty"`
Stages []StageListItemModel `json:"stages,omitempty" yaml:"stages,omitempty"`
Workflows GraphPipelineWorkflowListItemModel `json:"workflows,omitempty" yaml:"workflows,omitempty"`
}

type StageListItemModel map[string]StageModel
Expand All @@ -65,10 +73,33 @@ type StageWorkflowModel struct {
RunIf string `json:"run_if,omitempty" yaml:"run_if,omitempty"`
}

type DagWorkflowListItemModel map[string]DagWorkflowModel
type GraphPipelineWorkflowListItemModel map[string]GraphPipelineWorkflowModel

type GraphPipelineWorkflowModel struct {
DependsOn []string `json:"depends_on,omitempty" yaml:"depends_on,omitempty"`
AbortOnFail bool `json:"abort_on_fail,omitempty" yaml:"abort_on_fail,omitempty"`
RunIf GraphPipelineRunIfModel `json:"run_if,omitempty" yaml:"run_if,omitempty"`
ShouldAlwaysRun GraphPipelineAlwaysRunMode `json:"should_always_run,omitempty" yaml:"should_always_run,omitempty"`
}

type GraphPipelineRunIfModel struct {
Expression string `json:"expression,omitempty" yaml:"expression,omitempty"`
}

func (d *GraphPipelineAlwaysRunMode) UnmarshalYAML(unmarshal func(interface{}) error) error {
var value string
if err := unmarshal(&value); err != nil {
return err
}

allowedValues := []string{string(GraphPipelineAlwaysRunModeOff), string(GraphPipelineAlwaysRunModeWorkflow)}
if !slices.Contains(allowedValues, value) {
return fmt.Errorf("%s is not a valid should_always_run value (%s)", value, allowedValues)
}

*d = GraphPipelineAlwaysRunMode(value)

type DagWorkflowModel struct {
DependsOn []string `json:"depends_on,omitempty" yaml:"depends_on,omitempty"`
return nil
}

type WorkflowListItemModel map[string]WorkflowModel
Expand Down
58 changes: 58 additions & 0 deletions models/models_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (

"github.com/bitrise-io/stepman/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
)

func TestStatusReasonSuccess(t *testing.T) {
Expand Down Expand Up @@ -191,3 +193,59 @@ func TestShortReason(t *testing.T) {

assert.Equal(t, expected, actual)
}

func TestGraphPipelineWorkflow(t *testing.T) {
testCases := []struct {
rawYML string
errorExpected bool
}{
{
rawYML: `
pipelines:
pipeline1:
workflows:
workflow1:
abort_on_fail: true
should_always_run: off
run_if:
expression: "custom-expression"
workflows:
workflow1: {}
`,
},
{
rawYML: `
pipelines:
pipeline1:
workflows:
workflow1:
abort_on_fail: false
should_always_run: workflow
workflows:
workflow1: {}
`,
},
{
rawYML: `
pipelines:
pipeline1:
workflows:
workflow1:
should_always_run: none
workflows:
workflow1: {}
`,
errorExpected: true,
},
}

for _, testCase := range testCases {
config := BitriseDataModel{}
err := yaml.Unmarshal([]byte(testCase.rawYML), &config)
if testCase.errorExpected {
require.Error(t, err)
} else {
require.NoError(t, err)
}
}
}