Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions pkg/plugins/external/external_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,61 @@ var _ = Describe("Run external plugin using Scaffold", func() {
checkMetadata()
})
})

Context("Helper functions for Sending request to external plugin and parsing response", func() {
It("getUniverseMap should return path to content mapping of all files in Filesystem", func() {
fs := machinery.Filesystem{
FS: afero.NewMemMapFs(),
}

files := []struct {
path string
name string
content string
}{
{
path: "./",
name: "file",
content: "level 0 file",
},
{
path: "dir/",
name: "file",
content: "level 1 file",
},
{
path: "dir/subdir",
name: "file",
content: "level 2 file",
},
}

// create files in Filesystem
for _, file := range files {
err := fs.FS.MkdirAll(file.path, 0o700)
Expect(err).ToNot(HaveOccurred())

f, err := fs.FS.Create(filepath.Join(file.path, file.name))
Expect(err).ToNot(HaveOccurred())

_, err = f.Write([]byte(file.content))
Expect(err).ToNot(HaveOccurred())

err = f.Close()
Expect(err).ToNot(HaveOccurred())
}

universe, err := getUniverseMap(fs)

Expect(err).ToNot(HaveOccurred())
Expect(len(universe)).To(Equal(len(files)))

for _, file := range files {
content := universe[filepath.Join(file.path, file.name)]
Expect(content).To(Equal(file.content))
}
})
})
})

func getFlags() []external.Flag {
Expand Down
54 changes: 53 additions & 1 deletion pkg/plugins/external/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
iofs "io/fs"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"

"github.com/spf13/afero"
"github.com/spf13/pflag"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
Expand Down Expand Up @@ -102,8 +105,57 @@ func makePluginRequest(req external.PluginRequest, path string) (*external.Plugi
return &res, nil
}

// getUniverseMap is a helper function that is used to read the current directory to build
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be possible to add a unit test for this implementation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes sure, I'll add a unit test for this, thank you for the feedback!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@camilamacedo86 I've added a unit test in fd9cfa, let me know if it needs to be adjusted or to add more test cases.
thank you!

// the universe map.
// It will return a map[string]string where the keys are relative paths to files in the directory
// and values are the contents, or an error if an issue occurred while reading one of the files.
func getUniverseMap(fs machinery.Filesystem) (map[string]string, error) {
Copy link
Member

@camilamacedo86 camilamacedo86 Feb 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@em-r :
Question: Why have the path for the files is helpful? I mean, how it will be used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@camilamacedo86 - the way I see this is that when passing the path of files, we preserve the universe's file system structure, this way, the external plugin will have access to all scaffolded files the same way it would if we were to scan the root directory of the project from the external plugin.
on other hand, if there were multiple scaffolded files in the universe with the same name but in different directories, using the path of the files as keys will prevent overriding the file content in the universe map since they will have different keys.

Example:
plugin chain = plugin-1/v1 -> plugin-2/v1
plugin-1 scaffolds dir-1/doc.go and dir-2/doc.go
by using the file path as map key, we make sure that both entries for dir-1/doc.go and dir-2/doc.go will be available in the universe map, because the keys are unique, as opposed to if we use something like file name as the key, we will end up overriding one of the entries.
so in plugin-2/v1, we can for example access and make changes to any of the scaffolds the same way we would access them from file system: i.e. pr.Universe["dir-1/doc.go"]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the explanation.

universe := map[string]string{}

err := afero.Walk(fs.FS, ".", func(path string, info iofs.FileInfo, err error) error {
if err != nil {
return err
}

if info.IsDir() {
return nil
}

file, err := fs.FS.Open(path)
if err != nil {
return err
}

defer func() {
if err := file.Close(); err != nil {
return
}
}()

content, err := io.ReadAll(file)
if err != nil {
return err
}

universe[path] = string(content)

return nil
})

if err != nil {
return nil, err
}

return universe, nil
}

func handlePluginResponse(fs machinery.Filesystem, req external.PluginRequest, path string) error {
req.Universe = map[string]string{}
var err error

req.Universe, err = getUniverseMap(fs)
if err != nil {
return err
}

res, err := makePluginRequest(req, path)
if err != nil {
Expand Down