diff --git a/.changes/unreleased/Fixed-20241210-120846.yaml b/.changes/unreleased/Fixed-20241210-120846.yaml new file mode 100644 index 00000000..24b98c9f --- /dev/null +++ b/.changes/unreleased/Fixed-20241210-120846.yaml @@ -0,0 +1,3 @@ +kind: Fixed +body: Re-added site targeting on plan and apply +time: 2024-12-10T12:08:46.512121798+01:00 diff --git a/docs/src/reference/cli/mach-composer_apply.md b/docs/src/reference/cli/mach-composer_apply.md index ae53ca3d..d097be35 100644 --- a/docs/src/reference/cli/mach-composer_apply.md +++ b/docs/src/reference/cli/mach-composer_apply.md @@ -17,7 +17,7 @@ mach-composer apply [flags] -h, --help help for apply --ignore-change-detection Ignore change detection to run even if the components are considered up to date --ignore-version Skip MACH composer version check - --output-path string Outputs path to store the generated files. (default "deployments") + -o, --output-path string Outputs path to store the generated files. (default "deployments") -s, --site string Site to parse. If not set parse all sites. --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) diff --git a/docs/src/reference/cli/mach-composer_components.md b/docs/src/reference/cli/mach-composer_components.md index a0d53bbd..c5acea97 100644 --- a/docs/src/reference/cli/mach-composer_components.md +++ b/docs/src/reference/cli/mach-composer_components.md @@ -12,8 +12,7 @@ mach-composer components [flags] -f, --file string YAML file to parse. (default "main.yml") -h, --help help for components --ignore-version Skip MACH composer version check - --output-path string Outputs path to store the generated files. (default "deployments") - -s, --site string Site to parse. If not set parse all sites. + -o, --output-path string Outputs path to store the generated files. (default "deployments") --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) ``` diff --git a/docs/src/reference/cli/mach-composer_generate.md b/docs/src/reference/cli/mach-composer_generate.md index 5db4b74f..d6a7f5f5 100644 --- a/docs/src/reference/cli/mach-composer_generate.md +++ b/docs/src/reference/cli/mach-composer_generate.md @@ -12,8 +12,7 @@ mach-composer generate [flags] -f, --file string YAML file to parse. (default "main.yml") -h, --help help for generate --ignore-version Skip MACH composer version check - --output-path string Outputs path to store the generated files. (default "deployments") - -s, --site string Site to parse. If not set parse all sites. + -o, --output-path string Outputs path to store the generated files. (default "deployments") --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) ``` diff --git a/docs/src/reference/cli/mach-composer_graph.md b/docs/src/reference/cli/mach-composer_graph.md index 5297afa8..bd5c6139 100644 --- a/docs/src/reference/cli/mach-composer_graph.md +++ b/docs/src/reference/cli/mach-composer_graph.md @@ -25,8 +25,7 @@ mach-composer graph [flags] -f, --file string YAML file to parse. (default "main.yml") -h, --help help for graph --ignore-version Skip MACH composer version check - --output-path string Outputs path to store the generated files. (default "deployments") - -s, --site string Site to parse. If not set parse all sites. + -o, --output-path string Outputs path to store the generated files. (default "deployments") --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) ``` diff --git a/docs/src/reference/cli/mach-composer_init.md b/docs/src/reference/cli/mach-composer_init.md index e3b66bc8..93e9f5fb 100644 --- a/docs/src/reference/cli/mach-composer_init.md +++ b/docs/src/reference/cli/mach-composer_init.md @@ -12,7 +12,7 @@ mach-composer init [flags] -f, --file string YAML file to parse. (default "main.yml") -h, --help help for init --ignore-version Skip MACH composer version check - --output-path string Outputs path to store the generated files. (default "deployments") + -o, --output-path string Outputs path to store the generated files. (default "deployments") -s, --site string Site to parse. If not set parse all sites. --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) diff --git a/docs/src/reference/cli/mach-composer_plan.md b/docs/src/reference/cli/mach-composer_plan.md index 94ea4169..f7954e75 100644 --- a/docs/src/reference/cli/mach-composer_plan.md +++ b/docs/src/reference/cli/mach-composer_plan.md @@ -16,7 +16,7 @@ mach-composer plan [flags] --ignore-change-detection Ignore change detection to run even if the components are considered up to date --ignore-version Skip MACH composer version check --lock Acquire a lock on the state file before running terraform plan (default true) - --output-path string Outputs path to store the generated files. (default "deployments") + -o, --output-path string Outputs path to store the generated files. (default "deployments") -s, --site string Site to parse. If not set parse all sites. --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) diff --git a/docs/src/reference/cli/mach-composer_show-plan.md b/docs/src/reference/cli/mach-composer_show-plan.md index 2886aa53..890df4fc 100644 --- a/docs/src/reference/cli/mach-composer_show-plan.md +++ b/docs/src/reference/cli/mach-composer_show-plan.md @@ -15,8 +15,7 @@ mach-composer show-plan [flags] --ignore-change-detection Ignore change detection to run even if the components are considered up to date --ignore-version Skip MACH composer version check --no-color Disable color output - --output-path string Outputs path to store the generated files. (default "deployments") - -s, --site string Site to parse. If not set parse all sites. + -o, --output-path string Outputs path to store the generated files. (default "deployments") --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) ``` diff --git a/docs/src/reference/cli/mach-composer_sites.md b/docs/src/reference/cli/mach-composer_sites.md index 13e736a8..dff986c8 100644 --- a/docs/src/reference/cli/mach-composer_sites.md +++ b/docs/src/reference/cli/mach-composer_sites.md @@ -12,8 +12,7 @@ mach-composer sites [flags] -f, --file string YAML file to parse. (default "main.yml") -h, --help help for sites --ignore-version Skip MACH composer version check - --output-path string Outputs path to store the generated files. (default "deployments") - -s, --site string Site to parse. If not set parse all sites. + -o, --output-path string Outputs path to store the generated files. (default "deployments") --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) ``` diff --git a/docs/src/reference/cli/mach-composer_terraform.md b/docs/src/reference/cli/mach-composer_terraform.md index 817b7f01..38b9dd5d 100644 --- a/docs/src/reference/cli/mach-composer_terraform.md +++ b/docs/src/reference/cli/mach-composer_terraform.md @@ -13,8 +13,7 @@ mach-composer terraform [flags] -h, --help help for terraform --ignore-change-detection Ignore change detection to run even if the components are considered up to date. Per default the proxy will ignore change detection (default true) --ignore-version Skip MACH composer version check - --output-path string Outputs path to store the generated files. (default "deployments") - -s, --site string Site to parse. If not set parse all sites. + -o, --output-path string Outputs path to store the generated files. (default "deployments") --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) ``` diff --git a/docs/src/reference/cli/mach-composer_validate.md b/docs/src/reference/cli/mach-composer_validate.md index ad9ed964..4c7e325d 100644 --- a/docs/src/reference/cli/mach-composer_validate.md +++ b/docs/src/reference/cli/mach-composer_validate.md @@ -20,8 +20,7 @@ mach-composer validate [flags] -f, --file string YAML file to parse. (default "main.yml") -h, --help help for validate --ignore-version Skip MACH composer version check - --output-path string Outputs path to store the generated files. (default "deployments") - -s, --site string Site to parse. If not set parse all sites. + -o, --output-path string Outputs path to store the generated files. (default "deployments") --validation-path string Directory path to store files required for configuration validation. (default "validations") --var-file string Use a variable file to parse the configuration with. -w, --workers int The number of workers to use (default 1) diff --git a/internal/cmd/apply.go b/internal/cmd/apply.go index 9c9acb9f..5808d65e 100644 --- a/internal/cmd/apply.go +++ b/internal/cmd/apply.go @@ -16,6 +16,7 @@ var applyFlags struct { autoApprove bool destroy bool components []string + site string numWorkers int ignoreChangeDetection bool } @@ -37,6 +38,7 @@ func init() { applyCmd.Flags().BoolVarP(&applyFlags.forceInit, "force-init", "", false, "Force terraform initialization. By default mach-composer will reuse existing terraform resources") applyCmd.Flags().BoolVarP(&applyFlags.autoApprove, "auto-approve", "", false, "Suppress a terraform init for improved speed (not recommended for production usage)") applyCmd.Flags().BoolVarP(&applyFlags.destroy, "destroy", "", false, "Destroy option is a convenient way to destroy all remote objects managed by this mach config") + applyCmd.Flags().StringVarP(&applyFlags.site, "site", "s", "", "Site to parse. If not set parse all sites.") applyCmd.Flags().StringArrayVarP(&applyFlags.components, "component", "c", nil, "") applyCmd.Flags().BoolVarP(&applyFlags.ignoreChangeDetection, "ignore-change-detection", "", false, "Ignore change detection to run even if the components are considered up to date") } @@ -50,7 +52,7 @@ func applyFunc(cmd *cobra.Command, _ []string) error { defer cfg.Close() ctx := cmd.Context() - dg, err := graph.ToDeploymentGraph(cfg, commonFlags.outputPath) + dg, err := graph.ToDeploymentGraph(cfg, commonFlags.outputPath, graph.WithTargetSiteName(applyFlags.site)) if err != nil { return err } diff --git a/internal/cmd/common.go b/internal/cmd/common.go index b589cec2..de04dd19 100644 --- a/internal/cmd/common.go +++ b/internal/cmd/common.go @@ -17,7 +17,6 @@ import ( type CommonFlags struct { configFile string - siteName string ignoreVersion bool outputPath string varFile string @@ -29,9 +28,8 @@ var commonFlags CommonFlags func registerCommonFlags(cmd *cobra.Command) { cmd.Flags().StringVarP(&commonFlags.configFile, "file", "f", "main.yml", "YAML file to parse.") cmd.Flags().StringVarP(&commonFlags.varFile, "var-file", "", "", "Use a variable file to parse the configuration with.") - cmd.Flags().StringVarP(&commonFlags.siteName, "site", "s", "", "Site to parse. If not set parse all sites.") cmd.Flags().BoolVarP(&commonFlags.ignoreVersion, "ignore-version", "", false, "Skip MACH composer version check") - cmd.Flags().StringVarP(&commonFlags.outputPath, "output-path", "", "deployments", + cmd.Flags().StringVarP(&commonFlags.outputPath, "output-path", "o", "deployments", "Outputs path to store the generated files.") cmd.Flags().IntVarP(&commonFlags.workers, "workers", "w", 1, "The number of workers to use") @@ -39,10 +37,6 @@ func registerCommonFlags(cmd *cobra.Command) { } func preprocessCommonFlags(cmd *cobra.Command) { - if commonFlags.siteName != "" { - log.Warn().Msgf("Site option not implemented") - } - handleError(cmd.MarkFlagFilename("var-file", "yml", "yaml")) handleError(cmd.MarkFlagFilename("file", "yml", "yaml")) diff --git a/internal/cmd/init.go b/internal/cmd/init.go index 6ac555d3..8a49a9de 100644 --- a/internal/cmd/init.go +++ b/internal/cmd/init.go @@ -11,6 +11,10 @@ import ( "github.com/mach-composer/mach-composer-cli/internal/runner" ) +var initFlags struct { + site string +} + var initCmd = &cobra.Command{ Use: "init", Short: "Initialize site directories Terraform files.", @@ -28,6 +32,7 @@ var initCmd = &cobra.Command{ func init() { registerCommonFlags(initCmd) + initCmd.Flags().StringVarP(&initFlags.site, "site", "s", "", "Site to parse. If not set parse all sites.") } func initFunc(cmd *cobra.Command, _ []string) error { @@ -35,7 +40,7 @@ func initFunc(cmd *cobra.Command, _ []string) error { defer cfg.Close() ctx := cmd.Context() - dg, err := graph.ToDeploymentGraph(cfg, commonFlags.outputPath) + dg, err := graph.ToDeploymentGraph(cfg, commonFlags.outputPath, graph.WithTargetSiteName(initFlags.site)) if err != nil { return err } diff --git a/internal/cmd/plan.go b/internal/cmd/plan.go index a019cc20..0d7c38af 100644 --- a/internal/cmd/plan.go +++ b/internal/cmd/plan.go @@ -13,6 +13,7 @@ import ( var planFlags struct { forceInit bool + site string components []string lock bool ignoreChangeDetection bool @@ -33,6 +34,7 @@ var planCmd = &cobra.Command{ func init() { registerCommonFlags(planCmd) planCmd.Flags().BoolVarP(&planFlags.forceInit, "force-init", "", false, "Force terraform initialization. By default mach-composer will reuse existing terraform resources") + planCmd.Flags().StringVarP(&planFlags.site, "site", "s", "", "Site to parse. If not set parse all sites.") planCmd.Flags().StringArrayVarP(&planFlags.components, "component", "c", nil, "") planCmd.Flags().BoolVarP(&planFlags.lock, "lock", "", true, "Acquire a lock on the state file before running terraform plan") planCmd.Flags().BoolVarP(&planFlags.ignoreChangeDetection, "ignore-change-detection", "", false, "Ignore change detection to run even if the components are considered up to date") @@ -47,7 +49,7 @@ func planFunc(cmd *cobra.Command, _ []string) error { defer cfg.Close() ctx := cmd.Context() - dg, err := graph.ToDeploymentGraph(cfg, commonFlags.outputPath) + dg, err := graph.ToDeploymentGraph(cfg, commonFlags.outputPath, graph.WithTargetSiteName(planFlags.site)) if err != nil { return err } diff --git a/internal/graph/deployment.go b/internal/graph/deployment.go index 9f504265..8150d6e2 100644 --- a/internal/graph/deployment.go +++ b/internal/graph/deployment.go @@ -7,20 +7,45 @@ import ( "github.com/mach-composer/mach-composer-cli/internal/config" ) +type options struct { + siteTarget string +} + +type Option func(o *options) + +func WithTargetSiteName(site string) Option { + return func(o *options) { + o.siteTarget = site + } +} + // ToDeploymentGraph converts a MachConfig to a Graph ready for deployment. // This means that all nodes that are not independently deployable are pruned from the graph. -func ToDeploymentGraph(cfg *config.MachConfig, outPath string) (*Graph, error) { +func ToDeploymentGraph(cfg *config.MachConfig, outPath string, opts ...Option) (*Graph, error) { + o := options{ + siteTarget: "", + } + + for _, opt := range opts { + opt(&o) + } + g, err := ToDependencyGraph(cfg, outPath) if err != nil { return nil, err } - if err = validateDeployment(g); err != nil { + if err := validateDeployment(g); err != nil { return nil, err } // Remove all nodes that are not independent to site node - if err = reduceNodes(g); err != nil { + if err := reduceNodes(g); err != nil { + return nil, err + } + + //Prune to only include the site node if provided + if err := targetSiteNode(g, o.siteTarget); err != nil { return nil, err } @@ -132,3 +157,34 @@ func reduceNodes(g *Graph) error { return pErr } + +func targetSiteNode(g *Graph, site string) error { + if site == "" { + return nil + } + + if !g.VertexExists(site) { + return fmt.Errorf("site node %s does not exist", site) + } + + for _, v := range g.VerticesByType(SiteType) { + if v.Identifier() != site { + var pErr error + _ = graph.DFS(g.Graph, v.Path(), func(p string) bool { + n, err := g.Graph.Vertex(p) + if err != nil { + pErr = err + return true + } + + n.SetTargeted(false) + + return false + }) + + return pErr + } + } + + return nil +} diff --git a/internal/graph/deployment_test.go b/internal/graph/deployment_test.go index e3ed8404..35cb18f7 100644 --- a/internal/graph/deployment_test.go +++ b/internal/graph/deployment_test.go @@ -89,3 +89,154 @@ func TestToDeploymentGraphSimple(t *testing.T) { "main/site-1/site-component-2": {}, }, am) } + +func TestTargetSiteNodeDoesNotExist(t *testing.T) { + cfg := &config.MachConfig{ + Filename: "main", + MachComposer: config.MachComposer{ + Deployment: config.Deployment{ + Type: config.DeploymentSite, + }, + }, + + Sites: []config.SiteConfig{ + { + Name: "site 1", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + Identifier: "site-1", + Components: []config.SiteComponentConfig{ + { + Name: "site-component-1", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + }, + }, + }, + }, + } + + g, err := ToDeploymentGraph(cfg, "") + assert.NoError(t, err) + + err = targetSiteNode(g, "site-2") + assert.ErrorContains(t, err, "site-2 does not exist") +} + +func TestTargetSiteNodeAll(t *testing.T) { + cfg := &config.MachConfig{ + Filename: "main", + MachComposer: config.MachComposer{ + Deployment: config.Deployment{ + Type: config.DeploymentSite, + }, + }, + + Sites: []config.SiteConfig{ + { + Name: "site 1", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + Identifier: "site-1", + Components: []config.SiteComponentConfig{ + { + Name: "site-component-1", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + }, + }, + }, + { + Name: "site 2", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + Identifier: "site-2", + Components: []config.SiteComponentConfig{ + { + Name: "site-component-1", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + }, + }, + }, + }, + } + + g, err := ToDeploymentGraph(cfg, "") + assert.NoError(t, err) + + err = targetSiteNode(g, "") + assert.NoError(t, err) + + var siteVertices = g.VerticesByType(SiteType) + assert.Len(t, siteVertices, 2) + + for _, v := range siteVertices { + assert.True(t, v.Targeted()) + } +} + +func TestTargetSiteNodeTargeted(t *testing.T) { + cfg := &config.MachConfig{ + Filename: "main", + MachComposer: config.MachComposer{ + Deployment: config.Deployment{ + Type: config.DeploymentSite, + }, + }, + + Sites: []config.SiteConfig{ + { + Name: "site 1", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + Identifier: "site-1", + Components: []config.SiteComponentConfig{ + { + Name: "site-component-1", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + }, + }, + }, + { + Name: "site 2", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + Identifier: "site-2", + Components: []config.SiteComponentConfig{ + { + Name: "site-component-1", + Deployment: &config.Deployment{ + Type: config.DeploymentSite, + }, + }, + }, + }, + }, + } + + g, err := ToDeploymentGraph(cfg, "") + assert.NoError(t, err) + + err = targetSiteNode(g, "site-1") + assert.NoError(t, err) + + var siteVertices = g.VerticesByType(SiteType) + assert.Len(t, siteVertices, 2) + + site1 := g.VertexByIdentifier("site-1") + assert.True(t, site1.Targeted()) + + site2 := g.VertexByIdentifier("site-2") + assert.False(t, site2.Targeted()) +} diff --git a/internal/graph/graph.go b/internal/graph/graph.go index 49a070af..5222fba6 100644 --- a/internal/graph/graph.go +++ b/internal/graph/graph.go @@ -28,6 +28,32 @@ func (g *Graph) Vertices() Vertices { return vertices } +func (g *Graph) VerticesByType(typ Type) Vertices { + v := g.Vertices() + var vertices Vertices + + for _, node := range v { + if node.Type() == typ { + vertices = append(vertices, node) + } + } + + return vertices +} + +func (g *Graph) VertexByIdentifier(identifier string) Node { + for _, v := range g.Vertices() { + if v.Identifier() == identifier { + return v + } + } + return nil +} + +func (g *Graph) VertexExists(identifier string) bool { + return g.VertexByIdentifier(identifier) != nil +} + // Routes determines all the possible paths between two nodes func (g *Graph) Routes(source, target string) ([]Path, error) { var routes []Path diff --git a/internal/graph/mocks.go b/internal/graph/mocks.go index f513e309..fd82ca10 100644 --- a/internal/graph/mocks.go +++ b/internal/graph/mocks.go @@ -33,8 +33,9 @@ func CreateGraphMock( type NodeMock struct { mock.Mock - tainted bool - oldHash string + tainted bool + targeted bool + oldHash string } func (n *NodeMock) SetOldHash(hash string) { @@ -79,6 +80,11 @@ func (n *NodeMock) Tainted() bool { return n.tainted } +func (n *NodeMock) Targeted() bool { + args := n.Called() + return args.Bool(0) +} + func (n *NodeMock) Hash() (string, error) { args := n.Called() return args.String(0), args.Error(1) @@ -88,6 +94,10 @@ func (n *NodeMock) SetTainted(tainted bool) { n.tainted = tainted } +func (n *NodeMock) SetTargeted(targeted bool) { + n.targeted = targeted +} + func (n *NodeMock) HasChanges() (bool, error) { args := n.Called() return args.Bool(0), args.Error(1) diff --git a/internal/graph/node.go b/internal/graph/node.go index 1f97c523..ea336f0d 100644 --- a/internal/graph/node.go +++ b/internal/graph/node.go @@ -34,9 +34,12 @@ type Node interface { //Independent returns true if the node can be deployed independently, false otherwise Independent() bool - //Tainted indicates if. + //Tainted indicates if the node has been changed since the last deployment Tainted() bool + //Targeted indicates if the node should be deployed + Targeted() bool + //Hash returns the hash of the node. The hash is based on the node's configuration as well as the configuration of any //related components. This can be compared to other hashes to determine whether a node has changed Hash() (string, error) @@ -44,6 +47,9 @@ type Node interface { //SetTainted sets the tainted status of the node SetTainted(tainted bool) + //SetTargeted sets the target status of the node. If the node is a target it will be deployed + SetTargeted(target bool) + //ResetGraph resets the graph of the node. If the graph the node belongs to the node graphs must also be reset, //as these are used to determine the parents of the node resetGraph(graph.Graph[string, Node]) @@ -63,10 +69,11 @@ type baseNode struct { ancestor Node deploymentType config.DeploymentType tainted bool + targeted bool oldHash string } -func newBaseNode(graph graph.Graph[string, Node], path string, identifier string, typ Type, ancestor Node, deploymentType config.DeploymentType) baseNode { +func newBaseNode(graph graph.Graph[string, Node], path string, identifier string, typ Type, ancestor Node, deploymentType config.DeploymentType, targeted bool) baseNode { return baseNode{graph: graph, path: path, identifier: identifier, @@ -74,6 +81,7 @@ func newBaseNode(graph graph.Graph[string, Node], path string, identifier string ancestor: ancestor, deploymentType: deploymentType, tainted: false, + targeted: targeted, } } @@ -89,6 +97,14 @@ func (n *baseNode) Tainted() bool { return n.tainted } +func (n *baseNode) SetTargeted(ignored bool) { + n.targeted = ignored +} + +func (n *baseNode) Targeted() bool { + return n.targeted +} + func (n *baseNode) Path() string { return n.path } diff --git a/internal/graph/project.go b/internal/graph/project.go index a678bade..2cb0c273 100644 --- a/internal/graph/project.go +++ b/internal/graph/project.go @@ -13,7 +13,7 @@ type Project struct { func NewProject(g graph.Graph[string, Node], path, identifier string, deploymentType config.DeploymentType, projectConfig config.MachConfig) *Project { return &Project{ - baseNode: newBaseNode(g, path, identifier, ProjectType, nil, deploymentType), + baseNode: newBaseNode(g, path, identifier, ProjectType, nil, deploymentType, false), ProjectConfig: projectConfig, } } diff --git a/internal/graph/site.go b/internal/graph/site.go index 59c1d07e..2d2ff984 100644 --- a/internal/graph/site.go +++ b/internal/graph/site.go @@ -17,7 +17,7 @@ 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), + baseNode: newBaseNode(g, path, identifier, SiteType, ancestor, deploymentType, true), ProjectConfig: projectConfig, SiteConfig: siteConfig, } diff --git a/internal/graph/site_component.go b/internal/graph/site_component.go index 3b2c0257..6ac0fd07 100644 --- a/internal/graph/site_component.go +++ b/internal/graph/site_component.go @@ -18,7 +18,7 @@ func NewSiteComponent( ancestor Node, projectConfig config.MachConfig, siteConfig config.SiteConfig, siteComponentConfig config.SiteComponentConfig, ) *SiteComponent { return &SiteComponent{ - baseNode: newBaseNode(g, path, identifier, SiteComponentType, ancestor, deploymentType), + baseNode: newBaseNode(g, path, identifier, SiteComponentType, ancestor, deploymentType, true), ProjectConfig: projectConfig, SiteConfig: siteConfig, SiteComponentConfig: siteComponentConfig, diff --git a/internal/runner/graph.go b/internal/runner/graph.go index f8dceabc..5edd234a 100644 --- a/internal/runner/graph.go +++ b/internal/runner/graph.go @@ -77,6 +77,11 @@ func (gr *GraphRunner) run(ctx context.Context, g *graph.Graph, f executorFunc, continue } + if n.Targeted() == false { + log.Info().Msgf("Skipping %s because it is not targeted", n.Identifier()) + continue + } + if err := sem.Acquire(ctx, 1); err != nil { return err } diff --git a/internal/runner/graph_test.go b/internal/runner/graph_test.go index 6664254c..0a812027 100644 --- a/internal/runner/graph_test.go +++ b/internal/runner/graph_test.go @@ -23,24 +23,28 @@ func TestGraphRunnerMultipleLevels(t *testing.T) { site.On("Path").Return("site-1") site.On("Hash").Return("site-1", nil) site.On("Type").Return(internalgraph.SiteType) + site.On("Targeted").Return(true) component1 := new(internalgraph.NodeMock) component1.On("Identifier").Return("component-1") component1.On("Path").Return("component-1") component1.On("Hash").Return("component-1", nil) component1.On("Type").Return(internalgraph.SiteComponentType) + component1.On("Targeted").Return(true) component2 := new(internalgraph.NodeMock) component2.On("Identifier").Return("component-2") component2.On("Path").Return("component-2") component2.On("Hash").Return("component-2", nil) component2.On("Type").Return(internalgraph.SiteComponentType) + component2.On("Targeted").Return(true) component3 := new(internalgraph.NodeMock) component3.On("Identifier").Return("component-3") component3.On("Path").Return("component-3") component3.On("Hash").Return("component-3", nil) component3.On("Type").Return(internalgraph.SiteComponentType) + component3.On("Targeted").Return(true) graph := internalgraph.CreateGraphMock( map[string]internalgraph.Node{ @@ -76,6 +80,44 @@ func TestGraphRunnerMultipleLevels(t *testing.T) { assert.Equal(t, []string{"component-2", "component-3"}, called) } +func TestGraphRunnerTargeted(t *testing.T) { + project := new(internalgraph.NodeMock) + project.On("Identifier").Return("main") + project.On("Path").Return("main") + project.On("Hash").Return("main", nil) + project.On("Type").Return(internalgraph.ProjectType) + + site := new(internalgraph.NodeMock) + site.On("Identifier").Return("site-1") + site.On("Path").Return("site-1") + site.On("Hash").Return("site-1", nil) + site.On("Type").Return(internalgraph.SiteType) + site.On("Targeted").Return(false) + + graph := internalgraph.CreateGraphMock( + map[string]internalgraph.Node{ + "main": project, + "site-1": site, + }, + project, + internalgraph.EdgeMock{Source: "main", Target: "site-1"}, + ) + + runner := GraphRunner{workers: 1} + runner.hash = hash.NewMemoryMapHandler() + runner.batch = batcher.NaiveBatchFunc() + + var called []string + + err := runner.run(context.Background(), graph, func(ctx context.Context, node internalgraph.Node) error { + called = append(called, node.Identifier()) + return nil + }, false) + + assert.NoError(t, err) + assert.Len(t, called, 0) +} + func TestGraphRunnerError(t *testing.T) { project := new(internalgraph.NodeMock) project.On("Identifier").Return("main") @@ -88,24 +130,28 @@ func TestGraphRunnerError(t *testing.T) { site.On("Path").Return("site-1") site.On("Hash").Return("site-1", nil) site.On("Type").Return(internalgraph.SiteType) + site.On("Targeted").Return(true) component1 := new(internalgraph.NodeMock) component1.On("Identifier").Return("component-1") component1.On("Path").Return("component-1") component1.On("Hash").Return("component-1", nil) component1.On("Type").Return(internalgraph.SiteComponentType) + component1.On("Targeted").Return(true) component2 := new(internalgraph.NodeMock) component2.On("Identifier").Return("component-2") component2.On("Path").Return("component-2") component2.On("Hash").Return("component-2", nil) component2.On("Type").Return(internalgraph.SiteComponentType) + component2.On("Targeted").Return(true) component3 := new(internalgraph.NodeMock) component3.On("Identifier").Return("component-3") component3.On("Path").Return("component-3") component3.On("Hash").Return("component-3", nil) component3.On("Type").Return(internalgraph.SiteComponentType) + component3.On("Targeted").Return(true) graph := internalgraph.CreateGraphMock( map[string]internalgraph.Node{