Skip to content

Commit 57334dc

Browse files
authored
Merge pull request #180 from commitdev/process-modules-as-a-graph
Added dependsOn to module and project config, switched apply to apply…
2 parents 29d07b7 + 2ceb5a0 commit 57334dc

File tree

9 files changed

+349
-46
lines changed

9 files changed

+349
-46
lines changed

go.mod

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ module github.com/commitdev/zero
33
go 1.13
44

55
require (
6-
github.com/aws/aws-sdk-go v1.25.33
7-
github.com/chzyer/logex v1.1.10 // indirect
8-
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
9-
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
6+
github.com/aws/aws-sdk-go v1.30.12
107
github.com/coreos/go-semver v0.2.0
11-
github.com/google/go-cmp v0.3.0
8+
github.com/google/go-cmp v0.3.1
129
github.com/google/uuid v1.1.1
13-
github.com/hashicorp/go-getter v1.4.0
10+
github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02
11+
github.com/hashicorp/terraform v0.12.26
1412
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect
1513
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
1614
github.com/k0kubun/pp v3.0.1+incompatible
@@ -23,7 +21,7 @@ require (
2321
github.com/mattn/go-colorable v0.1.2 // indirect
2422
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
2523
github.com/spf13/cobra v0.0.6
26-
github.com/stretchr/testify v1.4.0
24+
github.com/stretchr/testify v1.5.1
2725
github.com/termie/go-shutil v0.0.0-20140729215957-bcacb06fecae
2826
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b // indirect
2927
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect

go.sum

Lines changed: 220 additions & 9 deletions
Large diffs are not rendered by default.

internal/apply/apply.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/commitdev/zero/internal/module"
1313
"github.com/commitdev/zero/internal/util"
14+
"github.com/hashicorp/terraform/dag"
1415

1516
"github.com/commitdev/zero/internal/config/globalconfig"
1617
"github.com/commitdev/zero/internal/config/projectconfig"
@@ -50,8 +51,18 @@ Only a single environment may be suitable for an initial test, but for a real sy
5051
func applyAll(dir string, projectConfig projectconfig.ZeroProjectConfig, applyEnvironments []string) {
5152
environmentArg := fmt.Sprintf("ENVIRONMENT=%s", strings.Join(applyEnvironments, ","))
5253

53-
// Go through each of the modules and run `make`
54-
for _, mod := range projectConfig.Modules {
54+
graph := projectConfig.GetDAG()
55+
56+
// Walk the graph of modules and run `make`
57+
root := []dag.Vertex{projectconfig.GraphRootName}
58+
graph.DepthFirstWalk(root, func(v dag.Vertex, depth int) error {
59+
// Don't process the root
60+
if depth == 0 {
61+
return nil
62+
}
63+
64+
name := v.(string)
65+
mod := projectConfig.Modules[name]
5566
// Add env vars for the makefile
5667
envList := []string{
5768
environmentArg,
@@ -72,7 +83,8 @@ func applyAll(dir string, projectConfig projectconfig.ZeroProjectConfig, applyEn
7283
envList = util.AppendProjectEnvToCmdEnv(mod.Parameters, envList)
7384
envList = util.AppendProjectEnvToCmdEnv(credentials.AsEnvVars(), envList)
7485
util.ExecuteCommand(exec.Command("make"), modulePath, envList)
75-
}
86+
return nil
87+
})
7688
}
7789

7890
// promptEnvironments Prompts the user for the environments to apply against and returns a slice of strings representing the environments

internal/config/moduleconfig/module_config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type ModuleConfig struct {
1010
Name string
1111
Description string
1212
Author string
13+
DependsOn []string `yaml:"dependsOn,omitempty"`
1314
TemplateConfig `yaml:"template"`
1415
RequiredCredentials []string `yaml:"requiredCredentials"`
1516
Parameters []Parameter

internal/config/projectconfig/project_config.go

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,27 @@ import (
44
"io/ioutil"
55
"log"
66

7+
"github.com/hashicorp/terraform/dag"
78
"github.com/k0kubun/pp"
89
yaml "gopkg.in/yaml.v2"
910
)
1011

12+
// GraphRootName represents the root of the graph of modules in a project
13+
const GraphRootName = "graphRoot"
14+
1115
type ZeroProjectConfig struct {
1216
Name string `yaml:"name"`
1317
ShouldPushRepositories bool
14-
Infrastructure Infrastructure // TODO simplify and flatten / rename?
1518
Parameters map[string]string
1619
Modules Modules `yaml:"modules"`
1720
}
1821

19-
type Infrastructure struct {
20-
AWS *AWS
21-
}
22-
23-
type AWS struct {
24-
AccountID string `yaml:"accountId"`
25-
Region string
26-
Terraform terraform // TODO simplify and flatten?
27-
}
28-
29-
type terraform struct {
30-
RemoteState bool
31-
}
32-
3322
type Modules map[string]Module
3423

3524
type Module struct {
25+
DependsOn []string `yaml:"dependsOn,omitempty"`
3626
Parameters Parameters `yaml:"parameters,omitempty"`
37-
Files Files `yaml:"files,omitempty"`
27+
Files Files
3828
}
3929

4030
type Parameters map[string]string
@@ -63,9 +53,33 @@ func (c *ZeroProjectConfig) Print() {
6353
pp.Println(c)
6454
}
6555

66-
func NewModule(parameters Parameters, directory string, repository string, source string) Module {
56+
// GetDAG returns a graph of the module names used in this project config
57+
func (c *ZeroProjectConfig) GetDAG() dag.AcyclicGraph {
58+
var g dag.AcyclicGraph
59+
60+
// Add vertices to graph
61+
g.Add(GraphRootName)
62+
for name := range c.Modules {
63+
g.Add(name)
64+
}
65+
66+
// Connect modules in graph
67+
for name, m := range c.Modules {
68+
if len(m.DependsOn) == 0 {
69+
g.Connect(dag.BasicEdge(GraphRootName, name))
70+
} else {
71+
for _, dependencyName := range m.DependsOn {
72+
g.Connect(dag.BasicEdge(dependencyName, name))
73+
}
74+
}
75+
}
76+
return g
77+
}
78+
79+
func NewModule(parameters Parameters, directory string, repository string, source string, dependsOn []string) Module {
6780
return Module{
6881
Parameters: parameters,
82+
DependsOn: dependsOn,
6983
Files: Files{
7084
Directory: directory,
7185
Repository: repository,

internal/config/projectconfig/project_config_test.go

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import (
44
"io/ioutil"
55
"log"
66
"os"
7+
"path/filepath"
78
"testing"
89

910
"github.com/commitdev/zero/internal/config/projectconfig"
11+
"github.com/commitdev/zero/internal/constants"
1012
"github.com/google/go-cmp/cmp"
1113
"github.com/google/go-cmp/cmp/cmpopts"
14+
"github.com/stretchr/testify/assert"
1215
)
1316

1417
func TestLoadConfig(t *testing.T) {
@@ -37,9 +40,9 @@ func TestLoadConfig(t *testing.T) {
3740
func eksGoReactSampleModules() projectconfig.Modules {
3841
parameters := projectconfig.Parameters{"a": "b"}
3942
return projectconfig.Modules{
40-
"aws-eks-stack": projectconfig.NewModule(parameters, "zero-aws-eks-stack", "github.com/something/repo1", "github.com/commitdev/zero-aws-eks-stack"),
41-
"deployable-backend": projectconfig.NewModule(parameters, "zero-deployable-backend", "github.com/something/repo2", "github.com/commitdev/zero-deployable-backend"),
42-
"deployable-react-frontend": projectconfig.NewModule(parameters, "zero-deployable-react-frontend", "github.com/something/repo3", "github.com/commitdev/zero-deployable-react-frontend"),
43+
"aws-eks-stack": projectconfig.NewModule(parameters, "zero-aws-eks-stack", "github.com/something/repo1", "github.com/commitdev/zero-aws-eks-stack", []string{}),
44+
"deployable-backend": projectconfig.NewModule(parameters, "zero-deployable-backend", "github.com/something/repo2", "github.com/commitdev/zero-deployable-backend", []string{}),
45+
"deployable-react-frontend": projectconfig.NewModule(parameters, "zero-deployable-react-frontend", "github.com/something/repo3", "github.com/commitdev/zero-deployable-react-frontend", []string{}),
4346
}
4447
}
4548

@@ -74,3 +77,37 @@ modules:
7477
source: github.com/commitdev/zero-deployable-react-frontend
7578
`
7679
}
80+
81+
func TestProjectConfigModuleGraph(t *testing.T) {
82+
configPath := filepath.Join("../../../tests/test_data/projectconfig/", constants.ZeroProjectYml)
83+
84+
t.Run("Should generate a valid, correct graph based on the project config", func(t *testing.T) {
85+
pc := projectconfig.LoadConfig(configPath)
86+
graph := pc.GetDAG()
87+
88+
// Validate the graph
89+
assert.NoError(t, graph.Validate())
90+
91+
// Check the structure of the graph
92+
root, err := graph.Root()
93+
assert.NoError(t, err)
94+
assert.Equal(t, "graphRoot", root)
95+
96+
want := `graphRoot
97+
project1
98+
project1
99+
project2
100+
project3
101+
project2
102+
project4
103+
project3
104+
project4
105+
project5
106+
project4
107+
project5
108+
`
109+
assert.Equal(t, want, graph.String())
110+
111+
})
112+
113+
}

internal/generate/generate_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestGenerateModules(t *testing.T) {
2929
projectConfig := projectconfig.ZeroProjectConfig{
3030
Name: "foo",
3131
Modules: projectconfig.Modules{
32-
"mod1": projectconfig.NewModule(map[string]string{"test": "bar"}, tmpDir, "n/a", baseTestFixturesDir),
32+
"mod1": projectconfig.NewModule(map[string]string{"test": "bar"}, tmpDir, "n/a", baseTestFixturesDir, []string{}),
3333
},
3434
}
3535

internal/init/init.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func Init(outDir string) *projectconfig.ZeroProjectConfig {
6868
}
6969

7070
}
71-
projectConfig.Modules[moduleName] = projectconfig.NewModule(projectModuleParams, repoName, repoURL, mappedSources[moduleName])
71+
projectConfig.Modules[moduleName] = projectconfig.NewModule(projectModuleParams, repoName, repoURL, mappedSources[moduleName], module.DependsOn)
7272
}
7373

7474
// TODO: load ~/.zero/config.yml (or credentials)
@@ -308,11 +308,7 @@ func chooseStack(reg registry.Registry) []string {
308308

309309
func defaultProjConfig() projectconfig.ZeroProjectConfig {
310310
return projectconfig.ZeroProjectConfig{
311-
Name: "",
312-
Infrastructure: projectconfig.Infrastructure{
313-
AWS: nil,
314-
},
315-
311+
Name: "",
316312
Parameters: map[string]string{},
317313
Modules: projectconfig.Modules{},
318314
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Graph shape:
2+
# 2
3+
# / \
4+
# 1 4
5+
# \ /
6+
# 3 - 5
7+
8+
name: graph_test
9+
10+
modules:
11+
project1:
12+
parameters:
13+
foo: bar
14+
project2:
15+
dependsOn:
16+
- project1
17+
parameters:
18+
baz: qux
19+
project3:
20+
dependsOn:
21+
- project1
22+
parameters:
23+
baz: qux
24+
project4:
25+
dependsOn:
26+
- project2
27+
- project3
28+
parameters:
29+
baz: qux
30+
project5:
31+
dependsOn:
32+
- project3
33+
parameters:
34+
baz: qux

0 commit comments

Comments
 (0)