From 5a76192bebd6bc29f7ddc6b4984b43022a76b941 Mon Sep 17 00:00:00 2001 From: Antoine Gelloz Date: Mon, 3 Jun 2024 16:53:18 +0200 Subject: [PATCH] refact(GenerateDAG): improved testing --- pkg/dag/dag.go | 24 ++ pkg/dag/printer.go | 97 +++++ pkg/dib/generate_dag.go | 4 +- pkg/dib/generate_dag_test.go | 388 +++++++++++++----- pkg/graphviz/graphviz_test.go | 10 +- .../bullseye/external-parent/Dockerfile | 3 +- .../docker/bullseye/multistage/included.txt | 0 .../docker/bullseye/sub-image/.dockerignore | 1 + .../docker/bullseye/sub-image/ignored.txt | 0 test/fixtures/docker/root/Dockerfile | 2 + .../docker/root/root-as-well/Dockerfile | 2 + 11 files changed, 416 insertions(+), 115 deletions(-) create mode 100644 pkg/dag/printer.go create mode 100644 test/fixtures/docker/bullseye/multistage/included.txt create mode 100644 test/fixtures/docker/bullseye/sub-image/.dockerignore create mode 100644 test/fixtures/docker/bullseye/sub-image/ignored.txt create mode 100644 test/fixtures/docker/root/Dockerfile create mode 100644 test/fixtures/docker/root/root-as-well/Dockerfile diff --git a/pkg/dag/dag.go b/pkg/dag/dag.go index 99ea40c7f..beeda669b 100644 --- a/pkg/dag/dag.go +++ b/pkg/dag/dag.go @@ -1,8 +1,12 @@ package dag import ( + "cmp" + "slices" + "strings" "sync" + "github.com/radiofrance/dib/internal/logger" "golang.org/x/sync/errgroup" "gopkg.in/yaml.v3" ) @@ -203,3 +207,23 @@ func createUniqueVisitorErr(visitor NodeVisitorFuncErr) NodeVisitorFuncErr { return uniqueVisitor } + +func sort(a, b *Node) int { + return cmp.Compare(strings.ToLower(a.Image.ShortName), strings.ToLower(b.Image.ShortName)) +} + +func (d *DAG) Sprint(name string) string { + d.WalkInDepth(func(node *Node) { + slices.SortFunc(node.Children(), sort) + }) + slices.SortFunc(d.nodes, sort) + rootNode := &Node{ + Image: &Image{Name: name}, + children: d.nodes, + } + res, err := defaultPrinter.WithRoot(rootNode).Srender() + if err != nil { + logger.Fatalf(err.Error()) + } + return res +} diff --git a/pkg/dag/printer.go b/pkg/dag/printer.go new file mode 100644 index 000000000..8454836a8 --- /dev/null +++ b/pkg/dag/printer.go @@ -0,0 +1,97 @@ +package dag + +import ( + "fmt" + "io" + "strings" + + "github.com/pterm/pterm" +) + +var defaultPrinter = GraphPrinter{ + TopRightCornerString: "└", + TopRightDownString: "├", + HorizontalString: "─", + VerticalString: "│", + RightDownLeftString: "┬", + Indent: 3, +} + +type GraphPrinter struct { + Root *Node + TreeStyle *pterm.Style + TextStyle *pterm.Style + TopRightCornerString string + TopRightDownString string + HorizontalString string + VerticalString string + RightDownLeftString string + Indent int + Writer io.Writer +} + +// WithRoot returns a new GraphPrinter with a specific Root node. +func (p GraphPrinter) WithRoot(root *Node) *GraphPrinter { + p.Root = root + return &p +} + +// Render prints the graph to the terminal. +func (p GraphPrinter) Render() error { + s, _ := p.Srender() + pterm.Fprintln(p.Writer, s) + + return nil +} + +// Srender renders the graph as a string. +func (p GraphPrinter) Srender() (string, error) { + if p.TreeStyle == nil { + p.TreeStyle = pterm.NewStyle() + } + if p.TextStyle == nil { + p.TextStyle = pterm.NewStyle() + } + + var result string + if p.Root.Image.Name != "" { + result += p.TextStyle.Sprint(p.Root.Image.Name) + "\n" + } + result += walkOverTree(p.Root.Children(), p, "") + return result, nil +} + +func walkOverTree(nodes []*Node, printer GraphPrinter, prefix string) string { + var res string + for nodeIndex, node := range nodes { + txt := fmt.Sprintf("%s [%s]\n", node.Image.ShortName, node.Image.Hash) + if len(nodes) > nodeIndex+1 { // if not last in nodes + if len(node.Children()) == 0 { // if there are no children + res += prefix + printer.TreeStyle.Sprint(printer.TopRightDownString) + + strings.Repeat(printer.TreeStyle.Sprint(printer.HorizontalString), printer.Indent) + + printer.TextStyle.Sprint(txt) + } else { // if there are children + res += prefix + printer.TreeStyle.Sprint(printer.TopRightDownString) + + strings.Repeat(printer.TreeStyle.Sprint(printer.HorizontalString), printer.Indent-1) + + printer.TreeStyle.Sprint(printer.RightDownLeftString) + + printer.TextStyle.Sprint(txt) + res += walkOverTree(node.Children(), printer, + prefix+printer.TreeStyle.Sprint(printer.VerticalString)+strings.Repeat(" ", printer.Indent-1)) + } + } else if len(nodes) == nodeIndex+1 { // if last in nodes + if len(node.Children()) == 0 { // if there are no children + res += prefix + printer.TreeStyle.Sprint(printer.TopRightCornerString) + + strings.Repeat(printer.TreeStyle.Sprint(printer.HorizontalString), printer.Indent) + + printer.TextStyle.Sprint(txt) + } else { // if there are children + res += prefix + printer.TreeStyle.Sprint(printer.TopRightCornerString) + + strings.Repeat(printer.TreeStyle.Sprint(printer.HorizontalString), printer.Indent-1) + + printer.TreeStyle.Sprint(printer.RightDownLeftString) + + printer.TextStyle.Sprint(txt) + res += walkOverTree(node.Children(), printer, + prefix+strings.Repeat(" ", printer.Indent)) + } + } + } + return res +} diff --git a/pkg/dib/generate_dag.go b/pkg/dib/generate_dag.go index 669a92258..064e30fe9 100644 --- a/pkg/dib/generate_dag.go +++ b/pkg/dib/generate_dag.go @@ -76,8 +76,8 @@ func GenerateDAG(buildPath, registryPrefix, customHashListPath string, buildArgs img.IgnorePatterns = ignorePatterns if n, ok := cache[img.Name]; ok { - return fmt.Errorf("duplicate image name %q found while reading file %q: previous file was %q", - img.Name, filePath, path.Join(n.Image.Dockerfile.ContextPath, n.Image.Dockerfile.Filename)) + return fmt.Errorf("duplicate image name %q: previous file was %q", + img.Name, path.Join(n.Image.Dockerfile.ContextPath, n.Image.Dockerfile.Filename)) } allParents[img.Name] = dckfile.From diff --git a/pkg/dib/generate_dag_test.go b/pkg/dib/generate_dag_test.go index c59da5e11..d5e5b51a3 100644 --- a/pkg/dib/generate_dag_test.go +++ b/pkg/dib/generate_dag_test.go @@ -7,8 +7,8 @@ import ( "path" "testing" - "github.com/radiofrance/dib/pkg/dag" "github.com/radiofrance/dib/pkg/dib" + "github.com/radiofrance/dib/pkg/dockerfile" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -19,160 +19,332 @@ const ( registryPrefix = "eu.gcr.io/my-test-repository" ) -//nolint:paralleltest -func TestGenerateDAG(t *testing.T) { - t.Run("basic tests", func(t *testing.T) { - graph, err := dib.GenerateDAG(buildPath1, registryPrefix, "", nil) - require.NoError(t, err) - - nodes := flattenNodes(graph) - rootNode := nodes["bullseye"] - subNode := nodes["sub-image"] - multistageNode := nodes["multistage"] - - rootImage := rootNode.Image - assert.Equal(t, path.Join(registryPrefix, "bullseye"), rootImage.Name) - assert.Equal(t, "bullseye", rootImage.ShortName) - assert.Empty(t, rootNode.Parents()) - assert.Len(t, rootNode.Children(), 3) - assert.Len(t, subNode.Parents(), 1) - assert.Len(t, multistageNode.Parents(), 1) - assert.Equal(t, []string{"latest"}, multistageNode.Image.ExtraTags) - }) +func TestGenerateDAG(t *testing.T) { //nolint:maintidx + t.Parallel() + + baseDir := path.Join(buildPath1, "bullseye") + bullseyeFiles := []string{ + path.Join(baseDir, "Dockerfile"), + path.Join(baseDir, "external-parent", "Dockerfile"), + path.Join(baseDir, "multistage", "Dockerfile"), + path.Join(baseDir, "multistage", "included.txt"), + path.Join(baseDir, "skipbuild", "Dockerfile"), + path.Join(baseDir, "sub-image", "Dockerfile"), + path.Join(baseDir, "sub-image", "ignored.txt"), + } + bullseyeHash, err := dib.HashFiles(baseDir, bullseyeFiles, nil, nil) + require.NoError(t, err) + + baseDir = path.Join(buildPath1, "bullseye", "external-parent") + extParentsFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + extParentHash, err := dib.HashFiles(baseDir, extParentsFiles, []string{bullseyeHash}, nil) + require.NoError(t, err) - t.Run("modifying the root node should change all hashes", func(t *testing.T) { - buildPath := copyFixtures(t, buildPath1) + baseDir = path.Join(buildPath1, "bullseye", "multistage") + multistageFiles := []string{ + path.Join(baseDir, "Dockerfile"), + path.Join(baseDir, "included.txt"), + } + multistageHash, err := dib.HashFiles(baseDir, multistageFiles, []string{bullseyeHash}, nil) + require.NoError(t, err) - graph0, err := dib.GenerateDAG(buildPath, registryPrefix, "", nil) + baseDir = path.Join(buildPath1, "bullseye", "sub-image") + subImageFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + subImageHash, err := dib.HashFiles(baseDir, subImageFiles, []string{bullseyeHash}, nil) + require.NoError(t, err) + + baseDir = path.Join(buildPath1, "root") + rootFiles := []string{ + path.Join(baseDir, "Dockerfile"), + path.Join(baseDir, "root-as-well", "Dockerfile"), + } + rootHash, err := dib.HashFiles(baseDir, rootFiles, nil, nil) + require.NoError(t, err) + + baseDir = path.Join(buildPath1, "root", "root-as-well") + rootAsWellFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + rootAsWellHash, err := dib.HashFiles(baseDir, rootAsWellFiles, nil, nil) + require.NoError(t, err) + + t.Run("nominal", func(t *testing.T) { + t.Parallel() + + buildPath := copyFixtures(t) + + graph, err := dib.GenerateDAG(buildPath, registryPrefix, "", nil) require.NoError(t, err) - nodes0 := flattenNodes(graph0) - rootNode0 := nodes0["bullseye"] - subNode0 := nodes0["sub-image"] - multistageNode0 := nodes0["multistage"] + assert.Equal(t, fmt.Sprintf( + `docker +├──┬bullseye [%s] +│ ├───external-parent [%s] +│ ├───multistage [%s] +│ └───sub-image [%s] +├───root [%s] +└───root-as-well [%s] +`, bullseyeHash, extParentHash, multistageHash, subImageHash, rootHash, rootAsWellHash), + graph.Sprint(path.Base(buildPath))) + }) - // When I add a new file in bullseye/ (root node) - require.NoError(t, os.WriteFile( - path.Join(buildPath, "bullseye/newfile"), - []byte("any content"), - os.ModePerm)) + t.Run("adding a file to bullseye directory", func(t *testing.T) { + t.Parallel() + + buildPath := copyFixtures(t) + + // When I add a new file in bullseye + baseDir := path.Join(buildPath, "bullseye") + newFilePath := path.Join(baseDir, "newfile") + require.NoError(t, os.WriteFile(newFilePath, []byte("any content"), os.ModePerm)) + + // Recompute hashes of bullseye and all its children because the context of bullseye has changed + bullseyeFiles := []string{ + path.Join(baseDir, "Dockerfile"), + path.Join(baseDir, "external-parent", "Dockerfile"), + path.Join(baseDir, "multistage", "Dockerfile"), + path.Join(baseDir, "multistage", "included.txt"), + path.Join(baseDir, "skipbuild", "Dockerfile"), + path.Join(baseDir, "sub-image", "Dockerfile"), + path.Join(baseDir, "sub-image", "ignored.txt"), + newFilePath, + } + bullseyeHash, err := dib.HashFiles(baseDir, bullseyeFiles, nil, nil) + require.NoError(t, err) - // Then ONLY the hash of the child node bullseye/multistage should have changed - graph1, err := dib.GenerateDAG(buildPath, registryPrefix, "", nil) + baseDir = path.Join(buildPath, "bullseye", "external-parent") + extParentsFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + extParentHash, err := dib.HashFiles(baseDir, extParentsFiles, []string{bullseyeHash}, nil) require.NoError(t, err) - nodes1 := flattenNodes(graph1) - rootNode1 := nodes1["bullseye"] - subNode1 := nodes1["sub-image"] - multistageNode1 := nodes1["multistage"] + baseDir = path.Join(buildPath, "bullseye", "multistage") + multistageFiles := []string{ + path.Join(baseDir, "Dockerfile"), + path.Join(baseDir, "included.txt"), + } + multistageHash, err := dib.HashFiles(baseDir, multistageFiles, []string{bullseyeHash}, nil) + require.NoError(t, err) - assert.NotEqual(t, rootNode0.Image.Hash, rootNode1.Image.Hash) - assert.NotEqual(t, subNode0.Image.Hash, subNode1.Image.Hash) - assert.NotEqual(t, multistageNode0.Image.Hash, multistageNode1.Image.Hash) - }) + baseDir = path.Join(buildPath, "bullseye", "sub-image") + subImageFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + subImageHash, err := dib.HashFiles(baseDir, subImageFiles, []string{bullseyeHash}, nil) + require.NoError(t, err) - t.Run("modifying a child node should change only its hash", func(t *testing.T) { - buildPath := copyFixtures(t, buildPath1) + // Then all hashes of children of bullseye node should change + graph, err := dib.GenerateDAG(buildPath, registryPrefix, "", nil) + require.NoError(t, err) - graph0, err := dib.GenerateDAG(buildPath, registryPrefix, "", nil) + assert.Equal(t, fmt.Sprintf( + `docker +├──┬bullseye [%s] +│ ├───external-parent [%s] +│ ├───multistage [%s] +│ └───sub-image [%s] +├───root [%s] +└───root-as-well [%s] +`, bullseyeHash, extParentHash, multistageHash, subImageHash, rootHash, rootAsWellHash), + graph.Sprint(path.Base(buildPath))) + }) + + t.Run("adding a file to multistage directory", func(t *testing.T) { + t.Parallel() + + buildPath := copyFixtures(t) + + // When I add a new file in bullseye/multistage + newFilePath := path.Join(buildPath, "bullseye", "multistage", "newfile") + require.NoError(t, os.WriteFile(newFilePath, []byte("any content"), os.ModePerm)) + + // Recompute hashes of bullseye and its children because the context of bullseye has changed + baseDir := path.Join(buildPath, "bullseye") + bullseyeFiles := []string{ + path.Join(baseDir, "Dockerfile"), + path.Join(baseDir, "external-parent", "Dockerfile"), + path.Join(baseDir, "multistage", "Dockerfile"), + path.Join(baseDir, "multistage", "included.txt"), + path.Join(baseDir, "skipbuild", "Dockerfile"), + path.Join(baseDir, "sub-image", "Dockerfile"), + path.Join(baseDir, "sub-image", "ignored.txt"), + newFilePath, + } + bullseyeHash, err := dib.HashFiles(baseDir, bullseyeFiles, nil, nil) require.NoError(t, err) - nodes0 := flattenNodes(graph0) - rootNode0 := nodes0["bullseye"] - subNode0 := nodes0["sub-image"] - multistageNode0 := nodes0["multistage"] + baseDir = path.Join(buildPath, "bullseye", "external-parent") + extParentsFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + extParentHash, err := dib.HashFiles(baseDir, extParentsFiles, []string{bullseyeHash}, nil) + require.NoError(t, err) - // When I add a new file in bullseye/multistage/ (child node) - require.NoError(t, os.WriteFile( - path.Join(buildPath, "bullseye/multistage/newfile"), - []byte("file contents"), - os.ModePerm)) + baseDir = path.Join(buildPath, "bullseye", "multistage") + multistageFiles := []string{ + path.Join(baseDir, "Dockerfile"), + path.Join(baseDir, "included.txt"), + newFilePath, + } + multistageHash, err := dib.HashFiles(baseDir, multistageFiles, []string{bullseyeHash}, nil) + require.NoError(t, err) - // Then ONLY the hash of the child node bullseye/multistage should have changed - graph1, err := dib.GenerateDAG(buildPath, registryPrefix, "", nil) + baseDir = path.Join(buildPath, "bullseye", "sub-image") + subImageFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + subImageHash, err := dib.HashFiles(baseDir, subImageFiles, []string{bullseyeHash}, nil) require.NoError(t, err) - nodes1 := flattenNodes(graph1) - rootNode1 := nodes1["bullseye"] - subNode1 := nodes1["sub-image"] - multistageNode1 := nodes1["multistage"] + // Then ONLY the hash of the leaf node bullseye/multistage should have changed + graph, err := dib.GenerateDAG(buildPath, registryPrefix, "", nil) + require.NoError(t, err) - assert.Equal(t, rootNode0.Image.Hash, rootNode1.Image.Hash) - assert.Equal(t, subNode0.Image.Hash, subNode1.Image.Hash) - assert.NotEqual(t, multistageNode0.Image.Hash, multistageNode1.Image.Hash) + assert.Equal(t, fmt.Sprintf( + `docker +├──┬bullseye [%s] +│ ├───external-parent [%s] +│ ├───multistage [%s] +│ └───sub-image [%s] +├───root [%s] +└───root-as-well [%s] +`, bullseyeHash, extParentHash, multistageHash, subImageHash, rootHash, rootAsWellHash), + graph.Sprint(path.Base(buildPath))) }) - t.Run("using custom hash list should change only hashes of nodes with custom label", func(t *testing.T) { - graph0, err := dib.GenerateDAG(buildPath1, registryPrefix, "", nil) - require.NoError(t, err) + t.Run("using custom hash list", func(t *testing.T) { + t.Parallel() + + buildPath := copyFixtures(t) - graph1, err := dib.GenerateDAG(buildPath1, registryPrefix, - "../../test/fixtures/dib/valid_wordlist.txt", nil) + customHashListPath := "../../test/fixtures/dib/valid_wordlist.txt" + + // Recompute hash of sub-image which is the only node that has the label 'dib.use-custom-hash-list' + baseDir = path.Join(buildPath, "bullseye", "sub-image") + subImageFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + list, err := dib.LoadCustomHashList(customHashListPath) + require.NoError(t, err) + subImageHash, err := dib.HashFiles(baseDir, subImageFiles, []string{bullseyeHash}, list) require.NoError(t, err) - nodes0 := flattenNodes(graph0) - rootNode0 := nodes0["bullseye"] - subNode0 := nodes0["sub-image"] - nodes1 := flattenNodes(graph1) - rootNode1 := nodes1["bullseye"] - subNode1 := nodes1["sub-image"] + graph, err := dib.GenerateDAG(buildPath, registryPrefix, customHashListPath, nil) + require.NoError(t, err) - assert.Equal(t, rootNode1.Image.Hash, rootNode0.Image.Hash) - assert.Equal(t, "violet-minnesota-alabama-alpha", subNode0.Image.Hash) - assert.Equal(t, "golduck-dialga-abra-aegislash", subNode1.Image.Hash) + // Only the sub-image node which has the label 'dib.use-custom-hash-list' should change + assert.Equal(t, fmt.Sprintf( + `docker +├──┬bullseye [%s] +│ ├───external-parent [%s] +│ ├───multistage [%s] +│ └───sub-image [%s] +├───root [%s] +└───root-as-well [%s] +`, bullseyeHash, extParentHash, multistageHash, subImageHash, rootHash, rootAsWellHash), + graph.Sprint(path.Base(buildPath))) }) - t.Run("using arg used in root node should change all hashes", func(t *testing.T) { - graph0, err := dib.GenerateDAG(buildPath1, registryPrefix, "", nil) + t.Run("using build args", func(t *testing.T) { + t.Parallel() + + buildPath := copyFixtures(t) + + baseDir := path.Join(buildPath, "bullseye") + dckfile, err := dockerfile.ParseDockerfile(path.Join(baseDir, "Dockerfile")) + require.NoError(t, err) + + buildArgs := map[string]string{ + "HELLO": "world", + } + argInstructionsToReplace := make(map[string]string) + for key, newArg := range buildArgs { + prevArgInstruction, ok := dckfile.Args[key] + if ok { + argInstructionsToReplace[prevArgInstruction] = fmt.Sprintf("ARG %s=%s", key, newArg) + } + } + require.NoError(t, dockerfile.ReplaceInFile(path.Join(baseDir, "Dockerfile"), argInstructionsToReplace)) + + // Recompute hashes of bullseye and all its children because the Dockerfile of bullseye has changed + bullseyeFiles := []string{ + path.Join(baseDir, "Dockerfile"), + path.Join(baseDir, "external-parent", "Dockerfile"), + path.Join(baseDir, "multistage", "Dockerfile"), + path.Join(baseDir, "multistage", "included.txt"), + path.Join(baseDir, "skipbuild", "Dockerfile"), + path.Join(baseDir, "sub-image", "Dockerfile"), + path.Join(baseDir, "sub-image", "ignored.txt"), + } + bullseyeHash, err := dib.HashFiles(baseDir, bullseyeFiles, nil, nil) + require.NoError(t, err) + + baseDir = path.Join(buildPath, "bullseye", "external-parent") + extParentsFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + extParentHash, err := dib.HashFiles(baseDir, extParentsFiles, []string{bullseyeHash}, nil) require.NoError(t, err) - graph1, err := dib.GenerateDAG(buildPath1, registryPrefix, "", - map[string]string{ - "HELLO": "world", - }) + baseDir = path.Join(buildPath, "bullseye", "multistage") + multistageFiles := []string{ + path.Join(baseDir, "Dockerfile"), + path.Join(baseDir, "included.txt"), + } + multistageHash, err := dib.HashFiles(baseDir, multistageFiles, []string{bullseyeHash}, nil) require.NoError(t, err) - nodes0 := flattenNodes(graph0) - rootNode0 := nodes0["bullseye"] - nodes1 := flattenNodes(graph1) - rootNode1 := nodes1["bullseye"] + baseDir = path.Join(buildPath, "bullseye", "sub-image") + subImageFiles := []string{ + path.Join(baseDir, "Dockerfile"), + } + subImageHash, err := dib.HashFiles(baseDir, subImageFiles, []string{bullseyeHash}, nil) + require.NoError(t, err) + + graph, err := dib.GenerateDAG(buildPath, registryPrefix, "", buildArgs) + require.NoError(t, err) - assert.NotEqual(t, rootNode1.Image.Hash, rootNode0.Image.Hash) + // Only bullseye node has the 'HELLO' argument, so its hash and all of its children should change + assert.Equal(t, fmt.Sprintf( + `docker +├──┬bullseye [%s] +│ ├───external-parent [%s] +│ ├───multistage [%s] +│ └───sub-image [%s] +├───root [%s] +└───root-as-well [%s] +`, bullseyeHash, extParentHash, multistageHash, subImageHash, rootHash, rootAsWellHash), + graph.Sprint(path.Base(buildPath))) }) - t.Run("duplicates", func(t *testing.T) { - graph, err := dib.GenerateDAG(buildPath2, registryPrefix, "", nil) - require.Error(t, err) - require.Nil(t, graph) + t.Run("duplicates image names", func(t *testing.T) { + t.Parallel() + + _, err := dib.GenerateDAG(buildPath2, registryPrefix, "", nil) require.EqualError(t, err, fmt.Sprintf( - "duplicate image name \"%s/duplicate\" found while reading file \"%s/bullseye/duplicate2/Dockerfile\": previous file was \"%s/bullseye/duplicate1/Dockerfile\"", //nolint:lll - registryPrefix, buildPath2, buildPath2)) + "could not process Dockerfile \"%s/bullseye/duplicate2/Dockerfile\": duplicate image name \"%s/duplicate\" found: previous file was \"%s/bullseye/duplicate1/Dockerfile\"", //nolint:lll + buildPath2, registryPrefix, buildPath2)) }) } -// copyFixtures copies the buildPath directory into a temporary one to be free to edit files. -func copyFixtures(t *testing.T, buildPath string) string { +// copyFixtures copies the buildPath1 directory into a temporary one to be free to edit files. +func copyFixtures(t *testing.T) string { t.Helper() cwd, err := os.Getwd() require.NoError(t, err) - src := path.Join(cwd, buildPath) + src := path.Join(cwd, buildPath1) dest := t.TempDir() cmd := exec.Command("cp", "-r", src, dest) require.NoError(t, cmd.Run()) return dest + "/docker" } -func flattenNodes(graph *dag.DAG) map[string]*dag.Node { - flatNodes := map[string]*dag.Node{} - - graph.Walk(func(node *dag.Node) { - flatNodes[node.Image.ShortName] = node - }) - - return flatNodes -} - func TestLoadCustomHashList(t *testing.T) { t.Parallel() diff --git a/pkg/graphviz/graphviz_test.go b/pkg/graphviz/graphviz_test.go index 28037ddae..374b0a0e8 100644 --- a/pkg/graphviz/graphviz_test.go +++ b/pkg/graphviz/graphviz_test.go @@ -34,19 +34,23 @@ func Test_GenerateDotviz(t *testing.T) { content, err := os.ReadFile(dotFile) require.NoError(t, err) - assert.Len(t, content, 647) + assert.Len(t, content, 809) assert.Contains(t, string(content), "\"eu.gcr.io/my-test-repository/bullseye\" [fillcolor=white style=filled];") assert.Contains(t, string(content), - "\"eu.gcr.io/my-test-repository/bullseye\" -> \"eu.gcr.io/my-test-repository/kaniko\";") + "\"eu.gcr.io/my-test-repository/bullseye\" -> \"eu.gcr.io/my-test-repository/external-parent\";") assert.Contains(t, string(content), "\"eu.gcr.io/my-test-repository/bullseye\" -> \"eu.gcr.io/my-test-repository/multistage\";") assert.Contains(t, string(content), "\"eu.gcr.io/my-test-repository/bullseye\" -> \"eu.gcr.io/my-test-repository/sub-image\";") assert.Contains(t, string(content), - "\"eu.gcr.io/my-test-repository/kaniko\" [fillcolor=white style=filled];") + "\"eu.gcr.io/my-test-repository/external-parent\" [fillcolor=white style=filled];") assert.Contains(t, string(content), "\"eu.gcr.io/my-test-repository/multistage\" [fillcolor=white style=filled];") assert.Contains(t, string(content), "\"eu.gcr.io/my-test-repository/sub-image\" [fillcolor=white style=filled];") + assert.Contains(t, string(content), + "\"eu.gcr.io/my-test-repository/root\" [fillcolor=white style=filled];") + assert.Contains(t, string(content), + "\"eu.gcr.io/my-test-repository/root-as-well\" [fillcolor=white style=filled];") } diff --git a/test/fixtures/docker/bullseye/external-parent/Dockerfile b/test/fixtures/docker/bullseye/external-parent/Dockerfile index 023e5e5d8..6598a039a 100644 --- a/test/fixtures/docker/bullseye/external-parent/Dockerfile +++ b/test/fixtures/docker/bullseye/external-parent/Dockerfile @@ -4,6 +4,5 @@ ARG KANIKO_VERSION=v1.6.0 FROM gcr.io/kaniko-project/executor:${KANIKO_VERSION} as kaniko_artifacts FROM eu.gcr.io/my-test-repository/bullseye:v1 -LABEL name="kaniko" +LABEL name="external-parent" LABEL version="16" - diff --git a/test/fixtures/docker/bullseye/multistage/included.txt b/test/fixtures/docker/bullseye/multistage/included.txt new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/docker/bullseye/sub-image/.dockerignore b/test/fixtures/docker/bullseye/sub-image/.dockerignore new file mode 100644 index 000000000..f89d64dab --- /dev/null +++ b/test/fixtures/docker/bullseye/sub-image/.dockerignore @@ -0,0 +1 @@ +ignored.txt diff --git a/test/fixtures/docker/bullseye/sub-image/ignored.txt b/test/fixtures/docker/bullseye/sub-image/ignored.txt new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/docker/root/Dockerfile b/test/fixtures/docker/root/Dockerfile new file mode 100644 index 000000000..b098ff95b --- /dev/null +++ b/test/fixtures/docker/root/Dockerfile @@ -0,0 +1,2 @@ +FROM apachesuperset.docker.scarf.sh/apache/superset:4.0.0 +LABEL name="root" diff --git a/test/fixtures/docker/root/root-as-well/Dockerfile b/test/fixtures/docker/root/root-as-well/Dockerfile new file mode 100644 index 000000000..68d9d158a --- /dev/null +++ b/test/fixtures/docker/root/root-as-well/Dockerfile @@ -0,0 +1,2 @@ +FROM apache/superset:dockerize +LABEL name="root-as-well"