From 2470fce79892398dabf56df6f76b047844b5801d Mon Sep 17 00:00:00 2001 From: Dias Saparov Date: Fri, 23 Jun 2023 17:30:04 +0100 Subject: [PATCH 1/5] introduce dependencies between projects and sort commands based on that --- cmd/digger/main.go | 12 +- cmd/digger/main_test.go | 9 +- go.mod | 2 + go.sum | 2 + pkg/configuration/config.go | 15 +-- pkg/configuration/converters.go | 56 +++++++++- pkg/configuration/digger_config.go | 30 ++--- pkg/configuration/digger_config_test.go | 143 +++++++++++++++++++++--- pkg/configuration/yaml.go | 15 +-- pkg/digger/digger.go | 20 ++++ pkg/digger/digger_test.go | 4 + pkg/integration/integration_test.go | 30 ++--- pkg/usage/usage.go | 2 +- 13 files changed, 267 insertions(+), 73 deletions(-) diff --git a/cmd/digger/main.go b/cmd/digger/main.go index 6b1a73993..5d22b2f8f 100644 --- a/cmd/digger/main.go +++ b/cmd/digger/main.go @@ -61,7 +61,7 @@ func gitHubCI(lock core_locking.Lock, policyChecker core_policy.Checker) { walker := configuration.FileSystemDirWalker{} - diggerConfig, err := configuration.LoadDiggerConfig("./", &walker) + diggerConfig, dependencyGraph, err := configuration.LoadDiggerConfig("./", &walker) if err != nil { reportErrorAndExit(githubActor, fmt.Sprintf("Failed to read Digger config. %s", err), 4) } @@ -115,7 +115,7 @@ func gitHubCI(lock core_locking.Lock, policyChecker core_policy.Checker) { if err != nil { reportErrorAndExit(githubActor, fmt.Sprintf("Failed to get current dir. %s", err), 4) } - allAppliesSuccessful, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, parsedGhContext.Repository, githubActor, eventName, prNumber, githubPrService, lock, reporter, planStorage, policyChecker, currentDir) + allAppliesSuccessful, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, &dependencyGraph, parsedGhContext.Repository, githubActor, eventName, prNumber, githubPrService, lock, reporter, planStorage, policyChecker, currentDir) if err != nil { reportErrorAndExit(githubActor, fmt.Sprintf("Failed to run commands. %s", err), 8) } @@ -153,7 +153,7 @@ func gitLabCI(lock core_locking.Lock, policyChecker core_policy.Checker) { } fmt.Printf("main: working dir: %s \n", currentDir) - diggerConfig, err := configuration.LoadDiggerConfig(currentDir, &walker) + diggerConfig, dependencyGraph, err := configuration.LoadDiggerConfig(currentDir, &walker) if err != nil { reportErrorAndExit(projectNamespace, fmt.Sprintf("Failed to read Digger config. %s", err), 4) } @@ -204,7 +204,7 @@ func gitLabCI(lock core_locking.Lock, policyChecker core_policy.Checker) { CiService: gitlabService, PrNumber: *gitLabContext.MergeRequestIId, } - allAppliesSuccess, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, gitLabContext.GitlabUserName, gitLabContext.EventType.String(), *gitLabContext.MergeRequestIId, gitlabService, lock, reporter, planStorage, policyChecker, currentDir) + allAppliesSuccess, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, &dependencyGraph, diggerProjectNamespace, gitLabContext.GitlabUserName, gitLabContext.EventType.String(), *gitLabContext.MergeRequestIId, gitlabService, lock, reporter, planStorage, policyChecker, currentDir) if err != nil { fmt.Printf("failed to execute command, %v", err) @@ -247,7 +247,7 @@ func azureCI(lock core_locking.Lock, policyChecker core_policy.Checker) { } fmt.Printf("main: working dir: %s \n", currentDir) - diggerConfig, err := configuration.LoadDiggerConfig(currentDir, &walker) + diggerConfig, dependencyGraph, err := configuration.LoadDiggerConfig(currentDir, &walker) if err != nil { reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to read Digger config. %s", err), 4) } @@ -282,7 +282,7 @@ func azureCI(lock core_locking.Lock, policyChecker core_policy.Checker) { CiService: azureService, PrNumber: prNumber, } - allAppliesSuccess, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, parsedAzureContext.BaseUrl, parsedAzureContext.EventType, prNumber, azureService, lock, reporter, planStorage, policyChecker, currentDir) + allAppliesSuccess, atLeastOneApply, err := digger.RunCommandsPerProject(commandsToRunPerProject, &dependencyGraph, diggerProjectNamespace, parsedAzureContext.BaseUrl, parsedAzureContext.EventType, prNumber, azureService, lock, reporter, planStorage, policyChecker, currentDir) if err != nil { reportErrorAndExit(parsedAzureContext.BaseUrl, fmt.Sprintf("Failed to run commands. %s", err), 8) } diff --git a/cmd/digger/main_test.go b/cmd/digger/main_test.go index f663f61cd..adae7951a 100644 --- a/cmd/digger/main_test.go +++ b/cmd/digger/main_test.go @@ -9,6 +9,7 @@ import ( "digger/pkg/reporting" "digger/pkg/utils" "fmt" + "github.com/dominikbraun/graph" "testing" "github.com/davecgh/go-spew/spew" @@ -875,6 +876,7 @@ func TestGitHubNewPullRequestContext(t *testing.T) { eventName := context.EventName diggerConfig := configuration.DiggerConfig{} + depGraph := graph.New(graph.StringHash) lock := &utils.MockLock{} prManager := &utils.MockPullRequestManager{ChangedFiles: []string{"dev/test.tf"}} planStorage := &utils.MockPlanStorage{} @@ -887,7 +889,7 @@ func TestGitHubNewPullRequestContext(t *testing.T) { PrNumber: prNumber, } commandsToRunPerProject, _, err := github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, map[string]configuration.Workflow{}) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, context.RepositoryOwner, context.Repository, eventName, prNumber, prManager, lock, reporter, planStorage, policyChecker, "") + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, context.RepositoryOwner, context.Repository, eventName, prNumber, prManager, lock, reporter, planStorage, policyChecker, "") assert.NoError(t, err) if err != nil { @@ -904,6 +906,7 @@ func TestGitHubNewCommentContext(t *testing.T) { ghEvent := context.Event eventName := context.EventName diggerConfig := configuration.DiggerConfig{} + depGraph := graph.New(graph.StringHash) lock := &utils.MockLock{} prManager := &utils.MockPullRequestManager{ChangedFiles: []string{"dev/test.tf"}} planStorage := &utils.MockPlanStorage{} @@ -916,9 +919,9 @@ func TestGitHubNewCommentContext(t *testing.T) { policyChecker := &utils.MockPolicyChecker{} commandsToRunPerProject, _, err := github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, map[string]configuration.Workflow{}) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, context.RepositoryOwner, context.Repository, eventName, prNumber, prManager, lock, reporter, planStorage, policyChecker, "") + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, context.RepositoryOwner, context.Repository, eventName, prNumber, prManager, lock, reporter, planStorage, policyChecker, "") - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, context.RepositoryOwner, context.Repository, eventName, prNumber, prManager, lock, reporter, planStorage, policyChecker, "") + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, context.RepositoryOwner, context.Repository, eventName, prNumber, prManager, lock, reporter, planStorage, policyChecker, "") assert.NoError(t, err) if err != nil { diff --git a/go.mod b/go.mod index db0321800..c98b7896c 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,8 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) +require github.com/dominikbraun/graph v0.22.3 // indirect + require ( cloud.google.com/go v0.110.0 // indirect cloud.google.com/go/compute v1.18.0 // indirect diff --git a/go.sum b/go.sum index d46b13c7e..6ebea29c1 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dominikbraun/graph v0.22.3 h1:2bbNzuMX+iKpM+XW1YPu7ch8IyXi/VbG7UYrRj2FHuI= +github.com/dominikbraun/graph v0.22.3/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= diff --git a/pkg/configuration/config.go b/pkg/configuration/config.go index 7b90a17c1..a6c384d6b 100644 --- a/pkg/configuration/config.go +++ b/pkg/configuration/config.go @@ -10,13 +10,14 @@ type DiggerConfig struct { } type Project struct { - Name string - Dir string - Workspace string - Terragrunt bool - Workflow string - IncludePatterns []string - ExcludePatterns []string + Name string + Dir string + Workspace string + Terragrunt bool + Workflow string + IncludePatterns []string + ExcludePatterns []string + DependencyProjects []string } type Workflow struct { diff --git a/pkg/configuration/converters.go b/pkg/configuration/converters.go index 98d2a8bca..d37e0e855 100644 --- a/pkg/configuration/converters.go +++ b/pkg/configuration/converters.go @@ -4,6 +4,7 @@ import ( "digger/pkg/core/models" "digger/pkg/utils" "fmt" + "github.com/dominikbraun/graph" "path/filepath" ) @@ -17,6 +18,7 @@ func copyProjects(projects []*ProjectYaml) []Project { p.Workflow, p.IncludePatterns, p.ExcludePatterns, + p.DependencyProjects, } result[i] = item } @@ -99,7 +101,7 @@ func copyWorkflows(workflows map[string]*WorkflowYaml) map[string]Workflow { return result } -func ConvertDiggerYamlToConfig(diggerYaml *DiggerConfigYaml, workingDir string, walker DirWalker) (*DiggerConfig, error) { +func ConvertDiggerYamlToConfig(diggerYaml *DiggerConfigYaml, workingDir string, walker DirWalker) (*DiggerConfig, graph.Graph[string, string], error) { var diggerConfig DiggerConfig const defaultWorkflowName = "default" @@ -145,15 +147,30 @@ func ConvertDiggerYamlToConfig(diggerYaml *DiggerConfigYaml, workingDir string, projectNames := make(map[string]bool) for _, project := range diggerConfig.Projects { if projectNames[project.Name] { - return nil, fmt.Errorf("project name '%s' is duplicated", project.Name) + return nil, nil, fmt.Errorf("project name '%s' is duplicated", project.Name) } projectNames[project.Name] = true } + // check project dependencies exist + for _, project := range diggerConfig.Projects { + for _, dependency := range project.DependencyProjects { + if !projectNames[dependency] { + return nil, nil, fmt.Errorf("project '%s' depends on '%s' which does not exist", project.Name, dependency) + } + } + } + + dependencyGraph, err := CreateProjectDependencyGraph(diggerConfig.Projects) + + if err != nil { + return nil, nil, fmt.Errorf("failed to create project dependency graph: %s", err.Error()) + } + if diggerYaml.GenerateProjectsConfig != nil { dirs, err := walker.GetDirs(workingDir) if err != nil { - return nil, err + return nil, nil, err } for _, dir := range dirs { @@ -177,5 +194,36 @@ func ConvertDiggerYamlToConfig(diggerYaml *DiggerConfigYaml, workingDir string, } } - return &diggerConfig, nil + return &diggerConfig, dependencyGraph, nil +} + +func CreateProjectDependencyGraph(projects []Project) (graph.Graph[string, string], error) { + g := graph.New(graph.StringHash, graph.Directed(), graph.PreventCycles()) + for _, project := range projects { + v, _ := g.Vertex(project.Name) + + if v == "" { + err := g.AddVertex(project.Name) + if err != nil { + return nil, err + } + } + for _, dependency := range project.DependencyProjects { + v, _ := g.Vertex(dependency) + + if v == "" { + err := g.AddVertex(dependency) + + if err != nil { + return nil, err + } + } + + err := g.AddEdge(dependency, project.Name) + if err != nil { + return nil, err + } + } + } + return g, nil } diff --git a/pkg/configuration/digger_config.go b/pkg/configuration/digger_config.go index d0c98ab4a..d6212fe11 100644 --- a/pkg/configuration/digger_config.go +++ b/pkg/configuration/digger_config.go @@ -4,6 +4,7 @@ import ( "digger/pkg/utils" "errors" "fmt" + "github.com/dominikbraun/graph" "gopkg.in/yaml.v3" "os" "path" @@ -61,50 +62,53 @@ func (walker *FileSystemDirWalker) GetDirs(workingDir string) ([]string, error) var ErrDiggerConfigConflict = errors.New("more than one digger config file detected, please keep either 'digger.yml' or 'digger.yaml'") -func LoadDiggerConfig(workingDir string, walker DirWalker) (*DiggerConfig, error) { +func LoadDiggerConfig(workingDir string, walker DirWalker) (*DiggerConfig, graph.Graph[string, string], error) { configYaml := &DiggerConfigYaml{} config := &DiggerConfig{} fileName, err := retrieveConfigFile(workingDir) if err != nil { if errors.Is(err, ErrDiggerConfigConflict) { - return nil, fmt.Errorf("error while retrieving config file: %v", err) + return nil, nil, fmt.Errorf("error while retrieving config file: %v", err) } } if fileName == "" { fmt.Println("No digger config found, using default one") config.Projects = make([]Project, 1) - config.Projects[0] = defaultProject() + project := defaultProject() + config.Projects[0] = project config.Workflows = make(map[string]Workflow) config.Workflows["default"] = *defaultWorkflow() - return config, nil + g := graph.New(graph.StringHash) + g.AddVertex(project.Name) + return config, g, nil } data, err := os.ReadFile(fileName) if err != nil { - return nil, fmt.Errorf("failed to read config file %s: %v", fileName, err) + return nil, nil, fmt.Errorf("failed to read config file %s: %v", fileName, err) } if err := yaml.Unmarshal(data, configYaml); err != nil { - return nil, fmt.Errorf("error parsing '%s': %v", fileName, err) + return nil, nil, fmt.Errorf("error parsing '%s': %v", fileName, err) } if (configYaml.Projects == nil || len(configYaml.Projects) == 0) && configYaml.GenerateProjectsConfig == nil { - return nil, fmt.Errorf("no projects configuration found in '%s'", fileName) + return nil, nil, fmt.Errorf("no projects configuration found in '%s'", fileName) } - c, err := ConvertDiggerYamlToConfig(configYaml, workingDir, walker) + config, projectDependencyGraph, err := ConvertDiggerYamlToConfig(configYaml, workingDir, walker) if err != nil { - return nil, err + return nil, nil, err } - for _, p := range c.Projects { - _, ok := c.Workflows[p.Workflow] + for _, p := range config.Projects { + _, ok := config.Workflows[p.Workflow] if !ok { - return nil, fmt.Errorf("failed to find workflow config '%s' for project '%s'", p.Workflow, p.Name) + return nil, nil, fmt.Errorf("failed to find workflow config '%s' for project '%s'", p.Workflow, p.Name) } } - return c, nil + return config, projectDependencyGraph, nil } func defaultProject() Project { diff --git a/pkg/configuration/digger_config_test.go b/pkg/configuration/digger_config_test.go index 8193b1089..0496a7a80 100644 --- a/pkg/configuration/digger_config_test.go +++ b/pkg/configuration/digger_config_test.go @@ -2,6 +2,7 @@ package configuration import ( "digger/pkg/core/models" + "github.com/dominikbraun/graph" "log" "os" "path" @@ -27,7 +28,7 @@ func setUp() (string, func()) { } func TestDiggerConfigFileDoesNotExist(t *testing.T) { - dg, err := LoadDiggerConfig("", &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig("", &FileSystemDirWalker{}) assert.NoError(t, err, "expected error to be not nil") assert.Equal(t, dg.Projects[0].Name, "default", "expected default project to have name 'default'") assert.Equal(t, dg.Projects[0].Dir, ".", "expected default project dir to be '.'") @@ -47,7 +48,7 @@ func TestDiggerConfigWhenMultipleConfigExist(t *testing.T) { t.Fatal(err) } - dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.Error(t, err, "expected error to be returned") assert.ErrorContains(t, err, ErrDiggerConfigConflict.Error(), "expected error to match target error") assert.Nil(t, dg, "expected diggerConfig to be nil") @@ -67,7 +68,7 @@ projects: deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.NoError(t, err, "expected error to be nil") assert.NotNil(t, dg, "expected digger config to be not nil") assert.Equal(t, "path/to/module/test", dg.GetDirectory("prod")) @@ -87,7 +88,7 @@ projects: deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.NoError(t, err, "expected error to be nil") assert.NotNil(t, dg, "expected digger config to be not nil") @@ -122,7 +123,7 @@ projects: deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.NoError(t, err, "expected error to be nil") assert.NotNil(t, dg, "expected digger config to be not nil") assert.Equal(t, "default", dg.Projects[0].Workflow) @@ -144,7 +145,7 @@ projects: deleteFile := createFile(path.Join(tempDir, "digger.yml"), diggerCfg) defer deleteFile() - dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.NoError(t, err, "expected error to be nil") assert.NotNil(t, dg, "expected digger config to be not nil") assert.Equal(t, "path/to/module", dg.GetDirectory("dev")) @@ -169,7 +170,7 @@ workflows: deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.NoError(t, err, "expected error to be nil") assert.Equal(t, models.Step{Action: "run", Value: "echo \"hello\"", Shell: ""}, dg.Workflows["myworkflow"].Plan.Steps[0], "parsed struct does not match expected struct") } @@ -214,7 +215,7 @@ workflows: deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.NoError(t, err, "expected error to be nil") assert.Equal(t, []EnvVar{ {Name: "TF_VAR_state", Value: "s3://mybucket/terraform.tfstate"}, @@ -254,7 +255,7 @@ workflows: deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.NoError(t, err, "expected error to be nil") assert.Equal(t, models.Step{Action: "run", Value: "rm -rf .terraform", Shell: ""}, dg.Workflows["dev"].Plan.Steps[0], "parsed struct does not match expected struct") assert.Equal(t, models.Step{Action: "init", ExtraArgs: nil, Shell: ""}, dg.Workflows["dev"].Plan.Steps[1], "parsed struct does not match expected struct") @@ -284,7 +285,7 @@ generate_projects: walker.Files = append(walker.Files, "dev/project") walker.Files = append(walker.Files, "testtt") - dg, err := LoadDiggerConfig(tempDir, walker) + dg, _, err := LoadDiggerConfig(tempDir, walker) assert.NoError(t, err, "expected error to be nil") assert.NotNil(t, dg, "expected digger config to be not nil") assert.Equal(t, "test1", dg.Projects[0].Name) @@ -314,7 +315,7 @@ generate_projects: walker.Files = append(walker.Files, "dev/project") walker.Files = append(walker.Files, "testtt") - dg, err := LoadDiggerConfig(tempDir, walker) + dg, _, err := LoadDiggerConfig(tempDir, walker) assert.NoError(t, err, "expected error to be nil") assert.NotNil(t, dg, "expected digger config to be not nil") assert.Equal(t, "test1", dg.Projects[0].Name) @@ -343,7 +344,7 @@ generate_projects: walker.Files = append(walker.Files, "dev/project") walker.Files = append(walker.Files, "testtt") - dg, err := LoadDiggerConfig(tempDir, walker) + dg, _, err := LoadDiggerConfig(tempDir, walker) assert.NoError(t, err, "expected error to be nil") assert.NotNil(t, dg, "expected digger config to be not nil") assert.Equal(t, "dev", dg.Projects[0].Name) @@ -360,7 +361,7 @@ func TestMissingProjectsReturnsError(t *testing.T) { defer deleteFile() walker := &MockDirWalker{} - _, err := LoadDiggerConfig(tempDir, walker) + _, _, err := LoadDiggerConfig(tempDir, walker) assert.ErrorContains(t, err, "no projects configuration found") } @@ -383,7 +384,7 @@ workflows: deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - dg, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + dg, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.NoError(t, err, "expected error to be nil") assert.NotNil(t, dg, "expected digger config to be not nil") assert.Equal(t, "my_custom_workflow", dg.Projects[0].Workflow) @@ -405,7 +406,7 @@ projects: deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + _, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.Error(t, err, "failed to find workflow config 'my_custom_workflow' for project 'my-first-app'") // steps block is missing for workflows @@ -420,7 +421,7 @@ workflows: deleteFile = createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - diggerConfig, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + diggerConfig, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.Equal(t, "my_custom_workflow", diggerConfig.Projects[0].Workflow) workflow, ok := diggerConfig.Workflows["my_custom_workflow"] assert.True(t, ok) @@ -449,11 +450,119 @@ workflows: deleteFile := createFile(path.Join(tempDir, "digger.yaml"), diggerCfg) defer deleteFile() - _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) + _, _, err := LoadDiggerConfig(tempDir, &FileSystemDirWalker{}) assert.Equal(t, "failed to find workflow config 'my_custom_workflow' for project 'my-first-app'", err.Error()) } +func TestDiggerConfigDependencyGraph(t *testing.T) { + p1 := Project{ + Name: "A", + DependencyProjects: []string{"B", "C"}, + } + + p2 := Project{ + Name: "B", + DependencyProjects: []string{"C"}, + } + + p3 := Project{ + Name: "C", + } + + p4 := Project{ + Name: "D", + } + + p5 := Project{ + Name: "E", + DependencyProjects: []string{"A"}, + } + + p6 := Project{ + Name: "F", + DependencyProjects: []string{"A", "B"}, + } + + projects := []Project{p1, p2, p3, p4, p5, p6} + + g, err := CreateProjectDependencyGraph(projects) + + assert.NoError(t, err, "expected error to be nil") + + orderedProjects, _ := graph.StableTopologicalSort(g, func(s string, s2 string) bool { + return s < s2 + }) + + assert.Equal(t, 6, len(orderedProjects)) + assert.Equal(t, []string{"C", "D", "B", "A", "E", "F"}, orderedProjects) +} + +func TestDiggerConfigDependencyGraph2(t *testing.T) { + p1 := Project{ + Name: "A", + DependencyProjects: []string{"B", "C", "D"}, + } + + p2 := Project{ + Name: "B", + DependencyProjects: []string{"E", "F"}, + } + + p3 := Project{ + Name: "C", + DependencyProjects: []string{ + "G", + }, + } + + p4 := Project{ + Name: "D", + DependencyProjects: []string{ + "H", "I", + }, + } + + projects := []Project{p1, p2, p3, p4} + + g, err := CreateProjectDependencyGraph(projects) + + assert.NoError(t, err, "expected error to be nil") + + orderedProjects, _ := graph.StableTopologicalSort(g, func(s string, s2 string) bool { + return s > s2 + }) + + assert.Equal(t, 9, len(orderedProjects)) + assert.Equal(t, []string{"I", "H", "G", "F", "E", "D", "C", "B", "A"}, orderedProjects) +} + +func TestDiggerConfigDependencyGraphWithCyclesFails(t *testing.T) { + p1 := Project{ + Name: "A", + DependencyProjects: []string{"B"}, + } + + p2 := Project{ + Name: "B", + DependencyProjects: []string{"C"}, + } + + p3 := Project{ + Name: "C", + DependencyProjects: []string{ + "A", + }, + } + + projects := []Project{p1, p2, p3} + + _, err := CreateProjectDependencyGraph(projects) + + assert.Error(t, err, "expected error on cycle") + assert.Equal(t, "edge would create a cycle", err.Error()) +} + func createTempDir() string { dir, err := os.MkdirTemp("", "tmp") if err != nil { diff --git a/pkg/configuration/yaml.go b/pkg/configuration/yaml.go index c0b80b2b8..f756a0f61 100644 --- a/pkg/configuration/yaml.go +++ b/pkg/configuration/yaml.go @@ -14,13 +14,14 @@ type DiggerConfigYaml struct { } type ProjectYaml struct { - Name string `yaml:"name"` - Dir string `yaml:"dir"` - Workspace string `yaml:"workspace"` - Terragrunt bool `yaml:"terragrunt"` - Workflow string `yaml:"workflow"` - IncludePatterns []string `yaml:"include_patterns,omitempty"` - ExcludePatterns []string `yaml:"exclude_patterns,omitempty"` + Name string `yaml:"name"` + Dir string `yaml:"dir"` + Workspace string `yaml:"workspace"` + Terragrunt bool `yaml:"terragrunt"` + Workflow string `yaml:"workflow"` + IncludePatterns []string `yaml:"include_patterns,omitempty"` + ExcludePatterns []string `yaml:"exclude_patterns,omitempty"` + DependencyProjects []string `yaml:"dependency_projects,omitempty"` } type WorkflowYaml struct { diff --git a/pkg/digger/digger.go b/pkg/digger/digger.go index 55fba5dc9..b989a3a7e 100644 --- a/pkg/digger/digger.go +++ b/pkg/digger/digger.go @@ -15,6 +15,7 @@ import ( "digger/pkg/usage" "errors" "fmt" + "github.com/dominikbraun/graph" "log" "os" "path" @@ -60,6 +61,7 @@ func DetectCI() CIName { func RunCommandsPerProject( commandsPerProject []models.ProjectCommand, + dependencyGraph *graph.Graph[string, string], projectNamespace string, requestedBy string, eventName string, @@ -81,6 +83,8 @@ func RunCommandsPerProject( fmt.Printf("Error while fetching user teams for CI service: %v", err) } + commandsPerProject = SortedCommandByDependency(commandsPerProject, dependencyGraph) + for _, projectCommands := range commandsPerProject { for _, command := range projectCommands.Commands { fmt.Printf("Running '%s' for project '%s'\n", command, projectCommands.ProjectName) @@ -264,6 +268,22 @@ func RunCommandsPerProject( return allAppliesSuccess, atLeastOneApply, nil } +func SortedCommandByDependency(project []models.ProjectCommand, dependencyGraph *graph.Graph[string, string]) []models.ProjectCommand { + var sortedCommands []models.ProjectCommand + sortedGraph, err := graph.TopologicalSort(*dependencyGraph) + if err != nil { + log.Fatalf("failed to sort commands by dependency, %v", err) + } + for _, node := range sortedGraph { + for _, command := range project { + if command.ProjectName == node { + sortedCommands = append(sortedCommands, command) + } + } + } + return sortedCommands +} + func MergePullRequest(ciService ci.CIService, prNumber int) { time.Sleep(5 * time.Second) combinedStatus, err := ciService.GetCombinedPullRequestStatus(prNumber) diff --git a/pkg/digger/digger_test.go b/pkg/digger/digger_test.go index 85b0dfa62..0b00bd9df 100644 --- a/pkg/digger/digger_test.go +++ b/pkg/digger/digger_test.go @@ -283,6 +283,10 @@ func allCommandsInOrderWithParams(terraformExecutor *MockTerraformExecutor, comm return commandStrings } +func TestSortedCommandByDependency(t *testing.T) { + +} + func TestParseWorkspace(t *testing.T) { var commentTests = []struct { in string diff --git a/pkg/integration/integration_test.go b/pkg/integration/integration_test.go index 89b2d3799..622ddd1cf 100644 --- a/pkg/integration/integration_test.go +++ b/pkg/integration/integration_test.go @@ -352,7 +352,7 @@ func TestHappyPath(t *testing.T) { terraform.CreateValidTerraformTestFile(dir) terraform.CreateSingleEnvDiggerYmlFile(dir) - diggerConfig, err := configuration.LoadDiggerConfig(dir, &configuration.FileSystemDirWalker{}) + diggerConfig, depGraph, err := configuration.LoadDiggerConfig(dir, &configuration.FileSystemDirWalker{}) assert.NoError(t, err) lock, err := locking.GetLock() @@ -408,7 +408,7 @@ func TestHappyPath(t *testing.T) { diggerProjectNamespace := repoOwner + "/" + repositoryName - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) assert.NoError(t, err) projectLock := &locking.PullRequestLock{ @@ -434,7 +434,7 @@ func TestHappyPath(t *testing.T) { assert.NoError(t, err) commandsToRunPerProject, _, err = dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows) assert.NoError(t, err) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) assert.NoError(t, err) println("--- digger apply comment ---") @@ -448,7 +448,7 @@ func TestHappyPath(t *testing.T) { assert.NoError(t, err) commandsToRunPerProject, _, err = dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows) assert.NoError(t, err) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) assert.NoError(t, err) projectLock = &locking.PullRequestLock{ @@ -471,7 +471,7 @@ func TestHappyPath(t *testing.T) { assert.NoError(t, err) commandsToRunPerProject, _, err = dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows) assert.NoError(t, err) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) assert.NoError(t, err) projectLock = &locking.PullRequestLock{ @@ -501,7 +501,7 @@ func TestMultiEnvHappyPath(t *testing.T) { terraform.CreateValidTerraformTestFile(dir) terraform.CreateMultiEnvDiggerYmlFile(dir) - diggerConfig, err := configuration.LoadDiggerConfig(dir, &configuration.FileSystemDirWalker{}) + diggerConfig, depGraph, err := configuration.LoadDiggerConfig(dir, &configuration.FileSystemDirWalker{}) assert.NoError(t, err) sess, err := session.NewSessionWithOptions(session.Options{ @@ -563,7 +563,7 @@ func TestMultiEnvHappyPath(t *testing.T) { CiService: githubPrService, PrNumber: prNumber, } - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, &dynamoDbLock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, &dynamoDbLock, reporter, planStorage, nil, dir) assert.NoError(t, err) projectLock := &locking.PullRequestLock{ @@ -588,7 +588,7 @@ func TestMultiEnvHappyPath(t *testing.T) { assert.NoError(t, err) commandsToRunPerProject, _, err = dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows) assert.NoError(t, err) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, &dynamoDbLock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, &dynamoDbLock, reporter, planStorage, nil, dir) assert.NoError(t, err) println("--- digger apply comment ---") @@ -602,7 +602,7 @@ func TestMultiEnvHappyPath(t *testing.T) { assert.NoError(t, err) commandsToRunPerProject, _, err = dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows) assert.NoError(t, err) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, &dynamoDbLock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, &dynamoDbLock, reporter, planStorage, nil, dir) assert.NoError(t, err) projectLock = &locking.PullRequestLock{ @@ -625,7 +625,7 @@ func TestMultiEnvHappyPath(t *testing.T) { assert.NoError(t, err) commandsToRunPerProject, _, err = dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows) assert.NoError(t, err) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, &dynamoDbLock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, &dynamoDbLock, reporter, planStorage, nil, dir) assert.NoError(t, err) projectLock = &locking.PullRequestLock{ @@ -721,7 +721,7 @@ workflows: terraform.CreateValidTerraformTestFile(dir) terraform.CreateCustomDiggerYmlFile(dir, diggerCfg) - diggerConfig, err := configuration.LoadDiggerConfig(dir, &configuration.FileSystemDirWalker{}) + diggerConfig, depGraph, err := configuration.LoadDiggerConfig(dir, &configuration.FileSystemDirWalker{}) assert.NoError(t, err) assert.NotNil(t, diggerConfig.Workflows) @@ -782,7 +782,7 @@ workflows: PrNumber: prNumber, } - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) assert.NoError(t, err) projectLock := &locking.PullRequestLock{ @@ -808,7 +808,7 @@ workflows: assert.NoError(t, err) commandsToRunPerProject, _, err = dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows) assert.NoError(t, err) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) assert.NoError(t, err) println("--- digger apply comment ---") @@ -822,7 +822,7 @@ workflows: assert.NoError(t, err) commandsToRunPerProject, _, err = dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows) assert.NoError(t, err) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) assert.NoError(t, err) projectLock = &locking.PullRequestLock{ @@ -844,7 +844,7 @@ workflows: assert.NoError(t, err) commandsToRunPerProject, _, err = dg_github.ConvertGithubEventToCommands(ghEvent, impactedProjects, requestedProject, diggerConfig.Workflows) assert.NoError(t, err) - _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) + _, _, err = digger.RunCommandsPerProject(commandsToRunPerProject, &depGraph, diggerProjectNamespace, repoOwner, eventName, prNumber, githubPrService, lock, reporter, planStorage, nil, dir) assert.NoError(t, err) projectLock = &locking.PullRequestLock{ diff --git a/pkg/usage/usage.go b/pkg/usage/usage.go index c6d4c1051..b48c6348d 100644 --- a/pkg/usage/usage.go +++ b/pkg/usage/usage.go @@ -77,7 +77,7 @@ func init() { fmt.Printf("Failed to get current dir. %s", err) } walker := configuration.FileSystemDirWalker{} - config, err := configuration.LoadDiggerConfig(currentDir, &walker) + config, _, err := configuration.LoadDiggerConfig(currentDir, &walker) if err != nil { return } From 084ac4b44b9246a68db473c27727c445b2edc1a6 Mon Sep 17 00:00:00 2001 From: Dias Saparov Date: Mon, 26 Jun 2023 11:14:58 +0100 Subject: [PATCH 2/5] order of commands --- pkg/digger/digger.go | 4 +++- pkg/digger/digger_test.go | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/pkg/digger/digger.go b/pkg/digger/digger.go index b989a3a7e..f0b9852de 100644 --- a/pkg/digger/digger.go +++ b/pkg/digger/digger.go @@ -270,7 +270,9 @@ func RunCommandsPerProject( func SortedCommandByDependency(project []models.ProjectCommand, dependencyGraph *graph.Graph[string, string]) []models.ProjectCommand { var sortedCommands []models.ProjectCommand - sortedGraph, err := graph.TopologicalSort(*dependencyGraph) + sortedGraph, err := graph.StableTopologicalSort(*dependencyGraph, func(s string, s2 string) bool { + return s < s2 + }) if err != nil { log.Fatalf("failed to sort commands by dependency, %v", err) } diff --git a/pkg/digger/digger_test.go b/pkg/digger/digger_test.go index 0b00bd9df..430298825 100644 --- a/pkg/digger/digger_test.go +++ b/pkg/digger/digger_test.go @@ -5,6 +5,7 @@ import ( "digger/pkg/core/models" "digger/pkg/reporting" "digger/pkg/utils" + "github.com/dominikbraun/graph" "sort" "strconv" "strings" @@ -284,6 +285,53 @@ func allCommandsInOrderWithParams(terraformExecutor *MockTerraformExecutor, comm } func TestSortedCommandByDependency(t *testing.T) { + // commandsPerProject []models.ProjectCommand, + // dependencyGraph *graph.Graph[string, string], + + commandsPerProject := []models.ProjectCommand{ + { + ProjectName: "project1", + Commands: []string{ + "command1", "command2", + }, + }, + { + ProjectName: "project2", + Commands: []string{ + "command3", "command4", + }, + }, + { + ProjectName: "project3", + Commands: []string{ + "command5", + }, + }, + { + ProjectName: "project4", + Commands: []string{ + "command6", + }, + }, + } + + dependencyGraph := graph.New(graph.StringHash, graph.PreventCycles(), graph.Directed()) + + dependencyGraph.AddVertex("project1") + dependencyGraph.AddVertex("project2") + dependencyGraph.AddVertex("project3") + dependencyGraph.AddVertex("project4") + + dependencyGraph.AddEdge("project2", "project1") + dependencyGraph.AddEdge("project3", "project2") + dependencyGraph.AddEdge("project4", "project1") + + sortedCommands := SortedCommandByDependency(commandsPerProject, &dependencyGraph) + + assert.Equal(t, "project3", sortedCommands[0].ProjectName) + assert.Equal(t, "project4", sortedCommands[1].ProjectName) + assert.Equal(t, "project2", sortedCommands[2].ProjectName) + assert.Equal(t, "project1", sortedCommands[3].ProjectName) } From 3868ca2245697346c9268f9bc8935ddbe8fa9ff8 Mon Sep 17 00:00:00 2001 From: Dias Saparov Date: Mon, 26 Jun 2023 11:26:30 +0100 Subject: [PATCH 3/5] order of commands --- pkg/configuration/yaml.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/configuration/yaml.go b/pkg/configuration/yaml.go index f756a0f61..2d26e1618 100644 --- a/pkg/configuration/yaml.go +++ b/pkg/configuration/yaml.go @@ -21,7 +21,7 @@ type ProjectYaml struct { Workflow string `yaml:"workflow"` IncludePatterns []string `yaml:"include_patterns,omitempty"` ExcludePatterns []string `yaml:"exclude_patterns,omitempty"` - DependencyProjects []string `yaml:"dependency_projects,omitempty"` + DependencyProjects []string `yaml:"depends_on,omitempty"` } type WorkflowYaml struct { From 90e6a732c1c7f3f85b51925930724a67ed92c5bb Mon Sep 17 00:00:00 2001 From: Dias Saparov Date: Mon, 26 Jun 2023 11:32:22 +0100 Subject: [PATCH 4/5] order of commands --- pkg/digger/digger.go | 4 ++-- pkg/digger/digger_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/digger/digger.go b/pkg/digger/digger.go index f0b9852de..4b9c209f2 100644 --- a/pkg/digger/digger.go +++ b/pkg/digger/digger.go @@ -83,7 +83,7 @@ func RunCommandsPerProject( fmt.Printf("Error while fetching user teams for CI service: %v", err) } - commandsPerProject = SortedCommandByDependency(commandsPerProject, dependencyGraph) + commandsPerProject = SortedCommandsByDependency(commandsPerProject, dependencyGraph) for _, projectCommands := range commandsPerProject { for _, command := range projectCommands.Commands { @@ -268,7 +268,7 @@ func RunCommandsPerProject( return allAppliesSuccess, atLeastOneApply, nil } -func SortedCommandByDependency(project []models.ProjectCommand, dependencyGraph *graph.Graph[string, string]) []models.ProjectCommand { +func SortedCommandsByDependency(project []models.ProjectCommand, dependencyGraph *graph.Graph[string, string]) []models.ProjectCommand { var sortedCommands []models.ProjectCommand sortedGraph, err := graph.StableTopologicalSort(*dependencyGraph, func(s string, s2 string) bool { return s < s2 diff --git a/pkg/digger/digger_test.go b/pkg/digger/digger_test.go index 430298825..b04f958ba 100644 --- a/pkg/digger/digger_test.go +++ b/pkg/digger/digger_test.go @@ -326,7 +326,7 @@ func TestSortedCommandByDependency(t *testing.T) { dependencyGraph.AddEdge("project3", "project2") dependencyGraph.AddEdge("project4", "project1") - sortedCommands := SortedCommandByDependency(commandsPerProject, &dependencyGraph) + sortedCommands := SortedCommandsByDependency(commandsPerProject, &dependencyGraph) assert.Equal(t, "project3", sortedCommands[0].ProjectName) assert.Equal(t, "project4", sortedCommands[1].ProjectName) From 88845bcafbaa7887dfb5ed50151c627c20e94716 Mon Sep 17 00:00:00 2001 From: Dias Saparov Date: Mon, 26 Jun 2023 11:44:38 +0100 Subject: [PATCH 5/5] order of commands --- cmd/digger/main_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/digger/main_test.go b/cmd/digger/main_test.go index adae7951a..13b13fa54 100644 --- a/cmd/digger/main_test.go +++ b/cmd/digger/main_test.go @@ -876,7 +876,7 @@ func TestGitHubNewPullRequestContext(t *testing.T) { eventName := context.EventName diggerConfig := configuration.DiggerConfig{} - depGraph := graph.New(graph.StringHash) + depGraph := graph.New(graph.StringHash, graph.Directed()) lock := &utils.MockLock{} prManager := &utils.MockPullRequestManager{ChangedFiles: []string{"dev/test.tf"}} planStorage := &utils.MockPlanStorage{} @@ -906,7 +906,7 @@ func TestGitHubNewCommentContext(t *testing.T) { ghEvent := context.Event eventName := context.EventName diggerConfig := configuration.DiggerConfig{} - depGraph := graph.New(graph.StringHash) + depGraph := graph.New(graph.StringHash, graph.Directed()) lock := &utils.MockLock{} prManager := &utils.MockPullRequestManager{ChangedFiles: []string{"dev/test.tf"}} planStorage := &utils.MockPlanStorage{}