Skip to content

Commit

Permalink
Rd 357 change detection should also occur when sop file has changed (#…
Browse files Browse the repository at this point in the history
…392)

<!--

Describe in detail the changes you are proposing, and the rationale.

-->

<!--

Link all GitHub issues fixed by this PR, and add references to prior
related PRs.

-->

Fixes #

### NEW FEATURES | UPGRADE NOTES | ENHANCEMENTS | BUG FIXES |
EXPERIMENTS

<!--

Write a short description of your changes. Examples:

- Fixed a bug
- Added a new feature
- Updated documentation

--> 

-
  • Loading branch information
demeyerthom committed Apr 22, 2024
2 parents b59ceff + a9312b0 commit 4e102ec
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 60 deletions.
3 changes: 3 additions & 0 deletions .changes/unreleased/Fixed-20240412-145530.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Fixed
body: Added sops file to hash
time: 2024-04-12T14:55:30.417315506+02:00
23 changes: 18 additions & 5 deletions internal/graph/dependency.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func ToDependencyGraph(cfg *config.MachConfig, outPath string) (*Graph, error) {

p := path.Join(outPath, projectIdentifier)

project := NewProject(g, p, projectIdentifier, cfg.MachComposer.Deployment.Type, cfg)
project := NewProject(g, p, projectIdentifier, cfg.MachComposer.Deployment.Type, *cfg)

err := g.AddVertex(project)
if err != nil {
Expand All @@ -38,7 +38,13 @@ func ToDependencyGraph(cfg *config.MachConfig, outPath string) (*Graph, error) {

for _, siteConfig := range cfg.Sites {
p = path.Join(project.Path(), siteConfig.Identifier)
site := NewSite(g, p, siteConfig.Identifier, siteConfig.Deployment.Type, project, siteConfig)
site := NewSite(g, p,
siteConfig.Identifier,
siteConfig.Deployment.Type,
project,
*cfg,
siteConfig,
)

err = g.AddVertex(site)
if err != nil {
Expand All @@ -51,11 +57,18 @@ func ToDependencyGraph(cfg *config.MachConfig, outPath string) (*Graph, error) {
}

for _, componentConfig := range siteConfig.Components {
log.Debug().Msgf("Deploying site component %s separately", componentConfig.Name)
log.Debug().Msgf("Deploying site component %s separately",
componentConfig.Name)

p = path.Join(site.Path(), componentConfig.Name)
component := NewSiteComponent(g, p, componentConfig.Name, componentConfig.Deployment.Type, site,
siteConfig, componentConfig)
component := NewSiteComponent(g, p,
componentConfig.Name,
componentConfig.Deployment.Type,
site,
*cfg,
siteConfig,
componentConfig,
)

err = g.AddVertex(component)
if err != nil {
Expand Down
46 changes: 30 additions & 16 deletions internal/graph/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,25 @@ import (
"github.com/mach-composer/mach-composer-cli/internal/utils"
)

func HashSiteComponentConfig(sc config.SiteComponentConfig) (string, error) {
func HashSiteComponent(sc *SiteComponent) (string, error) {
var err error
var tfHash string
var variablesHash string

// If the source is local, we include the hash of the directory.
if sc.Definition.Source.IsType(config.SourceTypeLocal) {
tfHash, err = utils.ComputeDirHash(string(sc.Definition.Source))
if sc.SiteComponentConfig.Definition.Source.IsType(config.SourceTypeLocal) {
tfHash, err = utils.ComputeDirHash(string(sc.SiteComponentConfig.Definition.Source))
if err != nil {
return "", err
}
}

// If a variables file has been set, we include the hash in the component hash.
// This is necessary because the variables file can be changed without
// changing the config itself, which would not update the hash. It is very costly though,
// as it will rerun all the components in the project
if sc.ProjectConfig.MachComposer.VariablesFile != "" {
variablesHash, err = utils.ComputeFileHash(sc.ProjectConfig.MachComposer.VariablesFile)
if err != nil {
return "", err
}
Expand All @@ -26,26 +38,28 @@ func HashSiteComponentConfig(sc config.SiteComponentConfig) (string, error) {
Source config.Source `json:"source"`
Branch string `json:"branch"`
} `json:"definition"`
Variables variable.VariablesMap `json:"variables"`
Secrets variable.VariablesMap `json:"secrets"`
DependsOn []string `json:"depends_on"`
Terraform string `json:"terraform"`
Variables variable.VariablesMap `json:"variables"`
Secrets variable.VariablesMap `json:"secrets"`
DependsOn []string `json:"depends_on"`
Terraform string `json:"terraform"`
VariablesFile string `json:"variables_file"`
}{
Name: sc.Name,
Name: sc.SiteComponentConfig.Name,
Definition: struct {
Name string `json:"name"`
Version string `json:"version"`
Source config.Source `json:"source"`
Branch string `json:"branch"`
}{
Name: sc.Definition.Name,
Version: sc.Definition.Version,
Source: sc.Definition.Source,
Branch: sc.Definition.Branch,
Name: sc.SiteComponentConfig.Definition.Name,
Version: sc.SiteComponentConfig.Definition.Version,
Source: sc.SiteComponentConfig.Definition.Source,
Branch: sc.SiteComponentConfig.Definition.Branch,
},
Variables: sc.Variables,
Secrets: sc.Secrets,
DependsOn: sc.DependsOn,
Terraform: tfHash,
Variables: sc.SiteComponentConfig.Variables,
Secrets: sc.SiteComponentConfig.Secrets,
DependsOn: sc.SiteComponentConfig.DependsOn,
Terraform: tfHash,
VariablesFile: variablesHash,
})
}
118 changes: 93 additions & 25 deletions internal/graph/hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,99 @@ import (
func TestHashSiteComponentConfigOk(t *testing.T) {
val, _ := variable.NewScalarVariable("value1")

h, err := HashSiteComponentConfig(config.SiteComponentConfig{
Name: "site-component-1",
Variables: variable.VariablesMap{
"var1": val,
},
Secrets: variable.VariablesMap{},
Definition: &config.ComponentConfig{
Name: "site-component-1",
Source: "testdata/dirhash",
h, err := HashSiteComponent(&SiteComponent{
SiteComponentConfig: config.SiteComponentConfig{
Name: "site-component-1",
Variables: variable.VariablesMap{
"var1": val,
},
Secrets: variable.VariablesMap{},
Definition: &config.ComponentConfig{
Name: "site-component-1",
Source: "testdata/dirhash",
},
},
})

assert.NoError(t, err)
assert.Equal(t, "28ea13834f4d36a8799267a372d3a8d4bb8353097fcbd3b2445005b702e9ac8b", h)
assert.Equal(t, "fbdafc38bdec19d852c8a31e3e09a63df076fb1ab7a82b4e920429346bf8652f", h)
}

func TestHashSiteComponentConfigChanged(t *testing.T) {
val, _ := variable.NewScalarVariable("value1")
cfg := config.SiteComponentConfig{
Name: "site-component-1",
Variables: variable.VariablesMap{
"var1": val,
},
Secrets: variable.VariablesMap{},
Definition: &config.ComponentConfig{
Name: "site-component-1",
Source: "testdata/dirhash",
n := &SiteComponent{
SiteComponentConfig: config.SiteComponentConfig{
Name: "site-component-1",
Variables: variable.VariablesMap{
"var1": val,
},
Secrets: variable.VariablesMap{},
Definition: &config.ComponentConfig{
Name: "site-component-1",
Source: "testdata/dirhash",
},
},
}

h1, err := HashSiteComponentConfig(cfg)
h1, err := HashSiteComponent(n)

cfg.DependsOn = []string{"site-component-2"}
n.SiteComponentConfig.DependsOn = []string{"site-component-2"}

h2, err := HashSiteComponentConfig(cfg)
h2, err := HashSiteComponent(n)

assert.NoError(t, err)
assert.NotEqual(t, h1, h2)
}

func TestHashSiteComponentConfigGithubSource(t *testing.T) {
val, _ := variable.NewScalarVariable("value1")
n := &SiteComponent{
SiteComponentConfig: config.SiteComponentConfig{
Name: "site-component-1",
Variables: variable.VariablesMap{
"var1": val,
},
Secrets: variable.VariablesMap{},
Definition: &config.ComponentConfig{
Name: "site-component-1",
Source: "testdata/dirhash",
},
},
}

h, err := HashSiteComponent(n)

assert.NoError(t, err)
assert.Equal(t, "fbdafc38bdec19d852c8a31e3e09a63df076fb1ab7a82b4e920429346bf8652f", h)
}

func TestHashSiteComponentConfigVariableFileOK(t *testing.T) {
val, _ := variable.NewScalarVariable("value1")

h, err := HashSiteComponent(&SiteComponent{
ProjectConfig: config.MachConfig{
MachComposer: config.MachComposer{
VariablesFile: "testdata/variables-1.yaml",
},
},
SiteComponentConfig: config.SiteComponentConfig{
Name: "site-component-1",
Variables: variable.VariablesMap{
"var1": val,
},
Secrets: variable.VariablesMap{},
Definition: &config.ComponentConfig{
Name: "site-component-1",
Source: "testdata/dirhash",
},
},
})

assert.NoError(t, err)
assert.Equal(t, "93270be1128022f9bad163959e8ff036f3b443991d8fbe463f51a9b01e46be11", h)
}

func TestHashSiteComponentConfigVariablesFileChanged(t *testing.T) {
val, _ := variable.NewScalarVariable("value1")
cfg := config.SiteComponentConfig{
Name: "site-component-1",
Expand All @@ -60,12 +112,28 @@ func TestHashSiteComponentConfigGithubSource(t *testing.T) {
Secrets: variable.VariablesMap{},
Definition: &config.ComponentConfig{
Name: "site-component-1",
Source: "git::github.com:hashicorp/example.git",
Source: "testdata/dirhash",
},
}

h, err := HashSiteComponentConfig(cfg)
h1, err := HashSiteComponent(&SiteComponent{
ProjectConfig: config.MachConfig{
MachComposer: config.MachComposer{
VariablesFile: "testdata/variables-1.yaml",
},
},
SiteComponentConfig: cfg,
})

h2, err := HashSiteComponent(&SiteComponent{
ProjectConfig: config.MachConfig{
MachComposer: config.MachComposer{
VariablesFile: "testdata/variables-2.yaml",
},
},
SiteComponentConfig: cfg,
})

assert.NoError(t, err)
assert.Equal(t, "de87afc8419dcd29e3e8cbe2e47b5026593ac0975555fe3d0f341eb3e0cf5785", h)
assert.NotEqual(t, h1, h2)
}
4 changes: 2 additions & 2 deletions internal/graph/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import (

type Project struct {
baseNode
ProjectConfig *config.MachConfig
ProjectConfig config.MachConfig
}

func NewProject(g graph.Graph[string, Node], path, identifier string, deploymentType config.DeploymentType,
projectConfig *config.MachConfig) *Project {
projectConfig config.MachConfig) *Project {
return &Project{
baseNode: newBaseNode(g, path, identifier, ProjectType, nil, deploymentType),
ProjectConfig: projectConfig,
Expand Down
17 changes: 10 additions & 7 deletions internal/graph/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import (

type Site struct {
baseNode
NestedNodes []*SiteComponent
SiteConfig config.SiteConfig
NestedNodes []*SiteComponent
ProjectConfig config.MachConfig
SiteConfig config.SiteConfig
}

func NewSite(g graph.Graph[string, Node], path, identifier string, deploymentType config.DeploymentType, ancestor Node,
siteConfig config.SiteConfig) *Site {
func NewSite(g graph.Graph[string, Node], path, identifier string,
deploymentType config.DeploymentType, ancestor Node,
projectConfig config.MachConfig, siteConfig config.SiteConfig) *Site {
return &Site{
baseNode: newBaseNode(g, path, identifier, SiteType, ancestor, deploymentType),
SiteConfig: siteConfig,
baseNode: newBaseNode(g, path, identifier, SiteType, ancestor, deploymentType),
ProjectConfig: projectConfig,
SiteConfig: siteConfig,
}
}

Expand All @@ -25,7 +28,7 @@ func (s *Site) Hash() (string, error) {

var hashes []string
for _, component := range s.NestedNodes {
h, err := HashSiteComponentConfig(component.SiteComponentConfig)
h, err := HashSiteComponent(component)
if err != nil {
return "", err
}
Expand Down
15 changes: 10 additions & 5 deletions internal/graph/site_component.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,25 @@ import (

type SiteComponent struct {
baseNode
ProjectConfig config.MachConfig
SiteConfig config.SiteConfig
SiteComponentConfig config.SiteComponentConfig
}

func NewSiteComponent(g graph.Graph[string, Node], path, identifier string, deploymentType config.DeploymentType,
ancestor Node, siteConfig config.SiteConfig, siteComponentConfig config.SiteComponentConfig) *SiteComponent {
func NewSiteComponent(
g graph.Graph[string, Node], path, identifier string, deploymentType config.DeploymentType,
ancestor Node, projectConfig config.MachConfig, siteConfig config.SiteConfig, siteComponentConfig config.SiteComponentConfig,
) *SiteComponent {
return &SiteComponent{
baseNode: newBaseNode(g, path, identifier, SiteComponentType, ancestor, deploymentType),
SiteConfig: siteConfig, SiteComponentConfig: siteComponentConfig,
baseNode: newBaseNode(g, path, identifier, SiteComponentType, ancestor, deploymentType),
ProjectConfig: projectConfig,
SiteConfig: siteConfig,
SiteComponentConfig: siteComponentConfig,
}
}

func (sc *SiteComponent) Hash() (string, error) {
return HashSiteComponentConfig(sc.SiteComponentConfig)
return HashSiteComponent(sc)
}

func SortSiteComponentNodes(nodes []*SiteComponent) {
Expand Down
1 change: 1 addition & 0 deletions internal/graph/testdata/variables-1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
random_value: "hello-world"
1 change: 1 addition & 0 deletions internal/graph/testdata/variables-2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
random_value: "world-hello"
8 changes: 8 additions & 0 deletions internal/utils/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/hex"
"encoding/json"
"golang.org/x/mod/sumdb/dirhash"
"io"
"os"
)

func ComputeHash(t interface{}) (string, error) {
Expand All @@ -21,3 +23,9 @@ func ComputeHash(t interface{}) (string, error) {
func ComputeDirHash(path string) (string, error) {
return dirhash.HashDir(path, "", dirhash.DefaultHash)
}

func ComputeFileHash(filePath string) (string, error) {
return dirhash.Hash1([]string{filePath}, func(name string) (io.ReadCloser, error) {
return os.Open(name)
})
}

0 comments on commit 4e102ec

Please sign in to comment.