From 872ff70abe35e77645394ee7b23940da77deab2c Mon Sep 17 00:00:00 2001 From: Herman Schaaf Date: Tue, 12 Sep 2023 17:01:40 +0100 Subject: [PATCH 1/7] Update package command --- plugin/options.go | 16 +---- plugin/plugin.go | 30 +-------- plugin/plugin_publish.go | 17 +++-- serve/{publish.go => package.go} | 111 ++++++++++++++----------------- serve/package_test.go | 96 ++++++++++++++++++++++++++ serve/plugin.go | 2 +- serve/publish_test.go | 29 -------- 7 files changed, 160 insertions(+), 141 deletions(-) rename serve/{publish.go => package.go} (57%) create mode 100644 serve/package_test.go delete mode 100644 serve/publish_test.go diff --git a/plugin/options.go b/plugin/options.go index 7db78df8f9..12e1500558 100644 --- a/plugin/options.go +++ b/plugin/options.go @@ -17,21 +17,9 @@ func (m MigrateMode) String() string { type Option func(*Plugin) -func WithTitle(title string) Option { +func WithBuildTargets(targets []BuildTarget) Option { return func(p *Plugin) { - p.title = title - } -} - -func WithDescription(description string) Option { - return func(p *Plugin) { - p.description = description - } -} - -func WithShortDescription(shortDescription string) Option { - return func(p *Plugin) { - p.shortDescription = shortDescription + p.targets = targets } } diff --git a/plugin/plugin.go b/plugin/plugin.go index 5d2a805711..6f3374dad3 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -47,18 +47,10 @@ func (UnimplementedSource) Tables(context.Context, TableOptions) (schema.Tables, // Plugin is the base structure required to pass to sdk.serve // We take a declarative approach to API here similar to Cobra type Plugin struct { - // Name of plugin i.e aws,gcp, azure etc' + // Name of plugin i.e aws, gcp, azure etc name string // Version of the plugin version string - // Title of the plugin as appears in CloudQuery registry - title string - // Short description of the plugin as appears in CloudQuery registry - shortDescription string - // Long description of the plugin as appears in CloudQuery registry - description string - // categories of the plugin as appears in CloudQuery registry - categories []string // targets to build plugin for targets []BuildTarget // Called upon init call to validate and init configuration @@ -84,9 +76,7 @@ func NewPlugin(name string, version string, newClient NewClientFunc, options ... version: version, internalColumns: true, newClient: newClient, - title: name, - categories: []string{}, - targets: buildTargets, + targets: DefaultBuildTargets, } for _, opt := range options { opt(&p) @@ -104,22 +94,6 @@ func (p *Plugin) Version() string { return p.version } -func (p *Plugin) Title() string { - return p.title -} - -func (p *Plugin) Description() string { - return p.description -} - -func (p *Plugin) ShortDescription() string { - return p.shortDescription -} - -func (p *Plugin) Categories() []string { - return p.categories -} - func (p *Plugin) Targets() []BuildTarget { return p.targets } diff --git a/plugin/plugin_publish.go b/plugin/plugin_publish.go index 17886c2395..d4f43f4b07 100644 --- a/plugin/plugin_publish.go +++ b/plugin/plugin_publish.go @@ -1,9 +1,9 @@ package plugin const ( - GoOslinux = "linux" - GoOswindows = "windows" - GoOsDarwin = "darwin" + GoOSLinux = "linux" + GoOSWindows = "windows" + GoOSDarwin = "darwin" GoArchAmd64 = "amd64" GoArchArm64 = "arm64" @@ -13,7 +13,6 @@ type PackageType string const ( PackageTypeNative PackageType = "native" - PackageTypeDocker PackageType = "docker" ) type BuildTarget struct { @@ -21,9 +20,9 @@ type BuildTarget struct { Arch string `json:"arch"` } -var buildTargets = []BuildTarget{ - {GoOslinux, GoArchAmd64}, - {GoOswindows, GoArchAmd64}, - {GoOsDarwin, GoArchAmd64}, - {GoOsDarwin, GoArchArm64}, +var DefaultBuildTargets = []BuildTarget{ + {GoOSLinux, GoArchAmd64}, + {GoOSWindows, GoArchAmd64}, + {GoOSDarwin, GoArchAmd64}, + {GoOSDarwin, GoArchArm64}, } diff --git a/serve/publish.go b/serve/package.go similarity index 57% rename from serve/publish.go rename to serve/package.go index 52e9a17334..b580a10787 100644 --- a/serve/publish.go +++ b/serve/package.go @@ -9,49 +9,30 @@ import ( "io" "os" "os/exec" + "path" "path/filepath" + "regexp" "github.com/cloudquery/plugin-sdk/v4/plugin" "github.com/spf13/cobra" ) const ( - pluginPublishShort = "Publish plugin to CloudQuery registry" - pluginPublishLong = `Publish plugin to CloudQuery registry + pluginPublishShort = "Package plugin for publishing to CloudQuery registry." + pluginPublishLong = `Package plugin for publishing to CloudQuery registry. -To just build the plugin without publishing, use the --dry-run flag. -Example: -go run main.go publish --dry-run +This creates a directory with the plugin binaries, package.json and documentation. ` ) -type PackageType string - -const ( - PackageTypeNative PackageType = "native" - PackageTypeDocker PackageType = "docker" -) - -// manifest is the plugin.json file inside the dist directory. It is used by CloudQuery registry -// to be able to publish the plugin with all the needed metadata. -type Manifest struct { +// PackageJSON is the package.json file inside the dist directory. It is used by the CloudQuery package command +// to be able to package the plugin with all the needed metadata. +type PackageJSON struct { Name string `json:"name"` Version string `json:"version"` - Title string `json:"title"` - ShortDescription string `json:"short_description"` - Description string `json:"description"` - Categories []string `json:"categories"` Protocols []int `json:"protocols"` SupportedTargets []plugin.BuildTarget `json:"supported_targets"` - PackageType PackageType `json:"package_type"` -} - -func isDirEmpty(name string) (bool, error) { - entries, err := os.ReadDir(name) - if err != nil { - return false, err - } - return len(entries) == 0, nil + PackageType plugin.PackageType `json:"package_type"` } func (s *PluginServe) writeTablesJSON(ctx context.Context, dir string) error { @@ -73,12 +54,16 @@ func (s *PluginServe) writeTablesJSON(ctx context.Context, dir string) error { return os.WriteFile(outputPath, buffer.Bytes(), 0644) } -func (*PluginServe) build(pluginDirectory string, goos string, goarch string) error { - pluginName := "plugin" + "_" + goos + "_" + goarch - distPath := pluginDirectory + "/dist" - - pluginPath := distPath + "/" + pluginName +func (s *PluginServe) build(pluginDirectory, goos, goarch, distPath, pluginVersion string) error { + pluginName := fmt.Sprintf("plugin-%s-%s-%s-%s", s.plugin.Name(), pluginVersion, goos, goarch) + pluginPath := path.Join(distPath, pluginName) args := []string{"build", "-o", pluginPath} + importPath, err := s.getModuleName(pluginDirectory) + if err != nil { + return err + } + args = append(args, "-buildmode=exe") + args = append(args, "-ldflags", fmt.Sprintf("-s -w -X %s/plugin.Version=%s", importPath, pluginVersion)) cmd := exec.Command("go", args...) cmd.Dir = pluginDirectory cmd.Stdout = os.Stdout @@ -121,49 +106,55 @@ func (*PluginServe) build(pluginDirectory string, goos string, goarch string) er return nil } -func (s *PluginServe) writeManifest(dir string) error { - manifest := Manifest{ +func (*PluginServe) getModuleName(pluginDirectory string) (string, error) { + goMod, err := os.ReadFile(path.Join(pluginDirectory, "go.mod")) + if err != nil { + return "", fmt.Errorf("failed to open go.mod: %w", err) + } + reMod := regexp.MustCompile(`module\s+(.+)\n`) + importPathMatches := reMod.FindStringSubmatch(string(goMod)) + if len(importPathMatches) != 2 { + return "", fmt.Errorf("failed to parse import path from go.mod") + } + importPath := importPathMatches[1] + if err != nil { + return "", fmt.Errorf("failed to get import path: %w", err) + } + return importPath, nil +} + +func (s *PluginServe) writePackageJSON(dir, pluginVersion string) error { + packageJSON := PackageJSON{ Name: s.plugin.Name(), - Version: s.plugin.Version(), - Title: s.plugin.Title(), - ShortDescription: s.plugin.ShortDescription(), - Description: s.plugin.Description(), - Categories: s.plugin.Categories(), + Version: pluginVersion, Protocols: s.versions, SupportedTargets: s.plugin.Targets(), - PackageType: PackageTypeNative, + PackageType: plugin.PackageTypeNative, } buffer := &bytes.Buffer{} m := json.NewEncoder(buffer) m.SetIndent("", " ") m.SetEscapeHTML(false) - err := m.Encode(manifest) + err := m.Encode(packageJSON) if err != nil { return err } - outputPath := filepath.Join(dir, "plugin.json") + outputPath := filepath.Join(dir, "package.json") return os.WriteFile(outputPath, buffer.Bytes(), 0644) } -func (s *PluginServe) newCmdPluginPublish() *cobra.Command { - var distDirectory string +func (s *PluginServe) newCmdPluginPackage() *cobra.Command { cmd := &cobra.Command{ - Use: "publish ", + Use: "package ", Short: pluginPublishShort, Long: pluginPublishLong, - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { pluginDirectory := args[0] - distPath := pluginDirectory + "/dist" - if distDirectory != "" { - distPath = distDirectory - } - empty, err := isDirEmpty(distPath) - if err != nil { - return err - } - if !empty { - return fmt.Errorf("dist directory is not empty: %s", distPath) + pluginVersion := args[1] + distPath := path.Join(pluginDirectory, "dist") + if cmd.Flag("dist-dir").Changed { + distPath = cmd.Flag("dist-dir").Value.String() } if err := os.MkdirAll(distPath, 0755); err != nil { return err @@ -178,16 +169,16 @@ func (s *PluginServe) newCmdPluginPublish() *cobra.Command { } for _, target := range s.plugin.Targets() { fmt.Println("Building for OS: " + target.OS + ", ARCH: " + target.Arch) - if err := s.build(pluginDirectory, target.OS, target.Arch); err != nil { + if err := s.build(pluginDirectory, target.OS, target.Arch, distPath, pluginVersion); err != nil { return fmt.Errorf("failed to build plugin for %s/%s: %w", target.OS, target.Arch, err) } } - if err := s.writeManifest(distPath); err != nil { + if err := s.writePackageJSON(distPath, pluginVersion); err != nil { return fmt.Errorf("failed to write manifest: %w", err) } return nil }, } - cmd.Flags().StringVar(&distDirectory, "dist-dir", "", "dist directory to output the built plugin. (default: )") + cmd.Flags().String("dist-dir", "", "dist directory to output the built plugin. (default: /dist)") return cmd } diff --git a/serve/package_test.go b/serve/package_test.go new file mode 100644 index 0000000000..983c19da46 --- /dev/null +++ b/serve/package_test.go @@ -0,0 +1,96 @@ +package serve + +import ( + "encoding/json" + "io" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/cloudquery/plugin-sdk/v4/internal/memdb" + "github.com/cloudquery/plugin-sdk/v4/plugin" + "github.com/google/go-cmp/cmp" +) + +func TestPluginPackage(t *testing.T) { + _, filename, _, ok := runtime.Caller(0) + if !ok { + t.Fatal("failed to get current file path") + } + dir := filepath.Dir(filepath.Dir(filename)) + simplePluginPath := filepath.Join(dir, "examples/simple_plugin") + packageVersion := "v1.2.3" + p := plugin.NewPlugin( + "testPlugin", + "development", + memdb.NewMemDBClient, + plugin.WithBuildTargets([]plugin.BuildTarget{ + {plugin.GoOSLinux, plugin.GoArchAmd64}, + {plugin.GoOSWindows, plugin.GoArchAmd64}, + {plugin.GoOSDarwin, plugin.GoArchAmd64}, + }), + ) + srv := Plugin(p) + cmd := srv.newCmdPluginRoot() + distDir := t.TempDir() + cmd.SetArgs([]string{"package", "--dist-dir", distDir, simplePluginPath, packageVersion}) + if err := cmd.Execute(); err != nil { + t.Fatal(err) + } + files, err := os.ReadDir(distDir) + if err != nil { + t.Fatal(err) + } + expect := []string{ + "package.json", + "plugin-testPlugin-v1.2.3-darwin-amd64.zip", + "plugin-testPlugin-v1.2.3-linux-amd64.zip", + "plugin-testPlugin-v1.2.3-windows-amd64.zip", + "tables.json", + } + if diff := cmp.Diff(expect, fileNames(files)); diff != "" { + t.Fatalf("unexpected files in dist directory (-want +got):\n%s", diff) + } + + expectPackage := PackageJSON{ + Name: "testPlugin", + Version: "v1.2.3", + Protocols: []int{3}, + SupportedTargets: []plugin.BuildTarget{ + {plugin.GoOSLinux, plugin.GoArchAmd64}, + {plugin.GoOSWindows, plugin.GoArchAmd64}, + {plugin.GoOSDarwin, plugin.GoArchAmd64}, + }, + PackageType: plugin.PackageTypeNative, + } + checkPackageJSONContents(t, filepath.Join(distDir, "package.json"), expectPackage) +} + +func checkPackageJSONContents(t *testing.T, filename string, expect PackageJSON) { + f, err := os.Open(filename) + if err != nil { + t.Fatalf("failed to open package.json: %v", err) + } + defer f.Close() + b, err := io.ReadAll(f) + if err != nil { + t.Fatalf("failed to read package.json: %v", err) + } + j := PackageJSON{} + err = json.Unmarshal(b, &j) + if err != nil { + t.Fatalf("failed to unmarshal package.json: %v", err) + } + if diff := cmp.Diff(expect, j); diff != "" { + t.Fatalf("package.json contents mismatch (-want +got):\n%s", diff) + } +} + +func fileNames(files []os.DirEntry) []string { + var names []string + for _, file := range files { + names = append(names, file.Name()) + } + return names +} diff --git a/serve/plugin.go b/serve/plugin.go index a2d06945c8..fa60005e97 100644 --- a/serve/plugin.go +++ b/serve/plugin.go @@ -291,7 +291,7 @@ func (s *PluginServe) newCmdPluginRoot() *cobra.Command { } cmd.AddCommand(s.newCmdPluginServe()) cmd.AddCommand(s.newCmdPluginDoc()) - cmd.AddCommand(s.newCmdPluginPublish()) + cmd.AddCommand(s.newCmdPluginPackage()) cmd.CompletionOptions.DisableDefaultCmd = true cmd.Version = s.plugin.Version() return cmd diff --git a/serve/publish_test.go b/serve/publish_test.go deleted file mode 100644 index f0ef4a2ff1..0000000000 --- a/serve/publish_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package serve - -import ( - "path/filepath" - "runtime" - "testing" - - "github.com/cloudquery/plugin-sdk/v4/internal/memdb" - "github.com/cloudquery/plugin-sdk/v4/plugin" -) - -func TestPluginPublish(t *testing.T) { - _, filename, _, ok := runtime.Caller(0) - if !ok { - t.Fatal("failed to get current file path") - } - dir := filepath.Dir(filepath.Dir(filename)) - simplePluginPath := filepath.Join(dir, "examples/simple_plugin") - p := plugin.NewPlugin( - "testPlugin", - "v1.0.0", - memdb.NewMemDBClient) - srv := Plugin(p) - cmd := srv.newCmdPluginRoot() - cmd.SetArgs([]string{"publish", simplePluginPath, "--dist-dir", t.TempDir()}) - if err := cmd.Execute(); err != nil { - t.Fatal(err) - } -} From 93b67a7fc86210d795fdca8bcb911dfffa9c9382 Mon Sep 17 00:00:00 2001 From: Herman Schaaf Date: Tue, 12 Sep 2023 17:08:25 +0100 Subject: [PATCH 2/7] Include paths in package.json --- .../{plugin_publish.go => plugin_package.go} | 0 serve/package.go | 27 ++++++++++++++----- serve/package_test.go | 8 +++--- 3 files changed, 25 insertions(+), 10 deletions(-) rename plugin/{plugin_publish.go => plugin_package.go} (100%) diff --git a/plugin/plugin_publish.go b/plugin/plugin_package.go similarity index 100% rename from plugin/plugin_publish.go rename to plugin/plugin_package.go diff --git a/serve/package.go b/serve/package.go index b580a10787..100a701a03 100644 --- a/serve/package.go +++ b/serve/package.go @@ -28,11 +28,17 @@ This creates a directory with the plugin binaries, package.json and documentatio // PackageJSON is the package.json file inside the dist directory. It is used by the CloudQuery package command // to be able to package the plugin with all the needed metadata. type PackageJSON struct { - Name string `json:"name"` - Version string `json:"version"` - Protocols []int `json:"protocols"` - SupportedTargets []plugin.BuildTarget `json:"supported_targets"` - PackageType plugin.PackageType `json:"package_type"` + Name string `json:"name"` + Version string `json:"version"` + Protocols []int `json:"protocols"` + SupportedTargets []TargetBuild `json:"supported_targets"` + PackageType plugin.PackageType `json:"package_type"` +} + +type TargetBuild struct { + OS string `json:"os"` + Arch string `json:"arch"` + Path string `json:"path"` } func (s *PluginServe) writeTablesJSON(ctx context.Context, dir string) error { @@ -124,11 +130,20 @@ func (*PluginServe) getModuleName(pluginDirectory string) (string, error) { } func (s *PluginServe) writePackageJSON(dir, pluginVersion string) error { + targets := []TargetBuild{} + for _, target := range s.plugin.Targets() { + pluginName := fmt.Sprintf("plugin-%s-%s-%s-%s", s.plugin.Name(), pluginVersion, target.OS, target.Arch) + targets = append(targets, TargetBuild{ + OS: target.OS, + Arch: target.Arch, + Path: pluginName + ".zip", + }) + } packageJSON := PackageJSON{ Name: s.plugin.Name(), Version: pluginVersion, Protocols: s.versions, - SupportedTargets: s.plugin.Targets(), + SupportedTargets: targets, PackageType: plugin.PackageTypeNative, } buffer := &bytes.Buffer{} diff --git a/serve/package_test.go b/serve/package_test.go index 983c19da46..44918b18b0 100644 --- a/serve/package_test.go +++ b/serve/package_test.go @@ -57,10 +57,10 @@ func TestPluginPackage(t *testing.T) { Name: "testPlugin", Version: "v1.2.3", Protocols: []int{3}, - SupportedTargets: []plugin.BuildTarget{ - {plugin.GoOSLinux, plugin.GoArchAmd64}, - {plugin.GoOSWindows, plugin.GoArchAmd64}, - {plugin.GoOSDarwin, plugin.GoArchAmd64}, + SupportedTargets: []TargetBuild{ + {OS: plugin.GoOSLinux, Arch: plugin.GoArchAmd64, Path: "plugin-testPlugin-v1.2.3-linux-amd64.zip"}, + {OS: plugin.GoOSWindows, Arch: plugin.GoArchAmd64, Path: "plugin-testPlugin-v1.2.3-windows-amd64.zip"}, + {OS: plugin.GoOSDarwin, Arch: plugin.GoArchAmd64, Path: "plugin-testPlugin-v1.2.3-darwin-amd64.zip"}, }, PackageType: plugin.PackageTypeNative, } From 307f0110614121f820dea71b4e8424c6cb138621 Mon Sep 17 00:00:00 2001 From: Herman Schaaf Date: Tue, 12 Sep 2023 17:09:52 +0100 Subject: [PATCH 3/7] Lint --- serve/package_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/serve/package_test.go b/serve/package_test.go index 44918b18b0..9cada3554f 100644 --- a/serve/package_test.go +++ b/serve/package_test.go @@ -26,9 +26,9 @@ func TestPluginPackage(t *testing.T) { "development", memdb.NewMemDBClient, plugin.WithBuildTargets([]plugin.BuildTarget{ - {plugin.GoOSLinux, plugin.GoArchAmd64}, - {plugin.GoOSWindows, plugin.GoArchAmd64}, - {plugin.GoOSDarwin, plugin.GoArchAmd64}, + {OS: plugin.GoOSLinux, Arch: plugin.GoArchAmd64}, + {OS: plugin.GoOSWindows, Arch: plugin.GoArchAmd64}, + {OS: plugin.GoOSDarwin, Arch: plugin.GoArchAmd64}, }), ) srv := Plugin(p) @@ -88,7 +88,7 @@ func checkPackageJSONContents(t *testing.T, filename string, expect PackageJSON) } func fileNames(files []os.DirEntry) []string { - var names []string + names := make([]string, 0, len(files)) for _, file := range files { names = append(names, file.Name()) } From 880b732e180e721ed053ca40a0aa4247b4bae950 Mon Sep 17 00:00:00 2001 From: Herman Schaaf Date: Tue, 12 Sep 2023 17:15:10 +0100 Subject: [PATCH 4/7] Update naming --- serve/package.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/serve/package.go b/serve/package.go index 100a701a03..90ac822549 100644 --- a/serve/package.go +++ b/serve/package.go @@ -18,8 +18,8 @@ import ( ) const ( - pluginPublishShort = "Package plugin for publishing to CloudQuery registry." - pluginPublishLong = `Package plugin for publishing to CloudQuery registry. + pluginPackageShort = "Package plugin for publishing to CloudQuery registry." + pluginPackageLong = `Package plugin for publishing to CloudQuery registry. This creates a directory with the plugin binaries, package.json and documentation. ` @@ -161,8 +161,8 @@ func (s *PluginServe) writePackageJSON(dir, pluginVersion string) error { func (s *PluginServe) newCmdPluginPackage() *cobra.Command { cmd := &cobra.Command{ Use: "package ", - Short: pluginPublishShort, - Long: pluginPublishLong, + Short: pluginPackageShort, + Long: pluginPackageLong, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { pluginDirectory := args[0] From 6a7b08606d88431143909a543a0e512dc57cc27c Mon Sep 17 00:00:00 2001 From: Herman Schaaf Date: Wed, 13 Sep 2023 10:38:58 +0100 Subject: [PATCH 5/7] Add docs to dist --- examples/simple_plugin/docs/configuration.md | 9 +++ examples/simple_plugin/docs/overview.md | 9 +++ serve/package.go | 60 ++++++++++++++++++-- serve/package_test.go | 19 ++++++- 4 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 examples/simple_plugin/docs/configuration.md create mode 100644 examples/simple_plugin/docs/overview.md diff --git a/examples/simple_plugin/docs/configuration.md b/examples/simple_plugin/docs/configuration.md new file mode 100644 index 0000000000..95a0a9698f --- /dev/null +++ b/examples/simple_plugin/docs/configuration.md @@ -0,0 +1,9 @@ +--- +title: Configuration +slug: configuration +description: How to configure the simple_plugin example. +--- + +# Configuration + +This plugin requires no configuration. \ No newline at end of file diff --git a/examples/simple_plugin/docs/overview.md b/examples/simple_plugin/docs/overview.md new file mode 100644 index 0000000000..d5ffcbb3cf --- /dev/null +++ b/examples/simple_plugin/docs/overview.md @@ -0,0 +1,9 @@ +--- +title: Overview +slug: overview +description: Overview of the simple_plugin example. +--- + +# Overview + +This is a simple example of a plugin that is used to test the SDK. diff --git a/serve/package.go b/serve/package.go index 90ac822549..f308702aff 100644 --- a/serve/package.go +++ b/serve/package.go @@ -12,6 +12,7 @@ import ( "path" "path/filepath" "regexp" + "strings" "github.com/cloudquery/plugin-sdk/v4/plugin" "github.com/spf13/cobra" @@ -158,6 +159,49 @@ func (s *PluginServe) writePackageJSON(dir, pluginVersion string) error { return os.WriteFile(outputPath, buffer.Bytes(), 0644) } +func (s *PluginServe) copyDocs(distPath, docsPath string) error { + err := os.MkdirAll(filepath.Join(distPath, "docs"), 0755) + if err != nil { + return err + } + dirEntry, err := os.ReadDir(docsPath) + if err != nil { + return err + } + for _, entry := range dirEntry { + if entry.IsDir() { + continue + } + if strings.HasSuffix(entry.Name(), ".md") { + src := filepath.Join(docsPath, entry.Name()) + dst := filepath.Join(distPath, "docs", entry.Name()) + err := copyFile(src, dst) + if err != nil { + return err + } + } + } + return nil +} + +func copyFile(src, dst string) error { + srcFile, err := os.Open(src) + if err != nil { + return err + } + defer srcFile.Close() + dstFile, err := os.Create(dst) + if err != nil { + return err + } + defer dstFile.Close() + _, err = io.Copy(dstFile, srcFile) + if err != nil { + return err + } + return nil +} + func (s *PluginServe) newCmdPluginPackage() *cobra.Command { cmd := &cobra.Command{ Use: "package ", @@ -166,10 +210,14 @@ func (s *PluginServe) newCmdPluginPackage() *cobra.Command { Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { pluginDirectory := args[0] - pluginVersion := args[1] + pluginVersion := strings.TrimSpace(args[1]) distPath := path.Join(pluginDirectory, "dist") - if cmd.Flag("dist-dir").Changed { - distPath = cmd.Flag("dist-dir").Value.String() + if cmd.Flag("dist").Changed { + distPath = cmd.Flag("dist").Value.String() + } + docsPath := path.Join(pluginDirectory, "docs") + if cmd.Flag("docs").Changed { + docsPath = cmd.Flag("docs").Value.String() } if err := os.MkdirAll(distPath, 0755); err != nil { return err @@ -191,9 +239,13 @@ func (s *PluginServe) newCmdPluginPackage() *cobra.Command { if err := s.writePackageJSON(distPath, pluginVersion); err != nil { return fmt.Errorf("failed to write manifest: %w", err) } + if err := s.copyDocs(distPath, docsPath); err != nil { + return fmt.Errorf("failed to copy docs: %w", err) + } return nil }, } - cmd.Flags().String("dist-dir", "", "dist directory to output the built plugin. (default: /dist)") + cmd.Flags().String("dist", "", "dist directory to output the built plugin. (default: /dist)") + cmd.Flags().String("docs", "", "docs directory to copy to the dist directory. (default: /docs)") return cmd } diff --git a/serve/package_test.go b/serve/package_test.go index 9cada3554f..dcebcd5cc2 100644 --- a/serve/package_test.go +++ b/serve/package_test.go @@ -34,7 +34,7 @@ func TestPluginPackage(t *testing.T) { srv := Plugin(p) cmd := srv.newCmdPluginRoot() distDir := t.TempDir() - cmd.SetArgs([]string{"package", "--dist-dir", distDir, simplePluginPath, packageVersion}) + cmd.SetArgs([]string{"package", "--dist", distDir, simplePluginPath, packageVersion}) if err := cmd.Execute(); err != nil { t.Fatal(err) } @@ -43,6 +43,7 @@ func TestPluginPackage(t *testing.T) { t.Fatal(err) } expect := []string{ + "docs", "package.json", "plugin-testPlugin-v1.2.3-darwin-amd64.zip", "plugin-testPlugin-v1.2.3-linux-amd64.zip", @@ -65,6 +66,22 @@ func TestPluginPackage(t *testing.T) { PackageType: plugin.PackageTypeNative, } checkPackageJSONContents(t, filepath.Join(distDir, "package.json"), expectPackage) + + expectDocs := []string{ + "configuration.md", + "overview.md", + } + checkDocs(t, filepath.Join(distDir, "docs"), expectDocs) +} + +func checkDocs(t *testing.T, dir string, expect []string) { + files, err := os.ReadDir(dir) + if err != nil { + t.Fatal(err) + } + if diff := cmp.Diff(expect, fileNames(files)); diff != "" { + t.Fatalf("unexpected files in docs directory (-want +got):\n%s", diff) + } } func checkPackageJSONContents(t *testing.T, filename string, expect PackageJSON) { From 56155bd1e47e2fd36d9501f7f8486d3b29151f35 Mon Sep 17 00:00:00 2001 From: Herman Schaaf Date: Wed, 13 Sep 2023 10:49:33 +0100 Subject: [PATCH 6/7] Trim spaces --- serve/package.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/serve/package.go b/serve/package.go index f308702aff..495b7a43f6 100644 --- a/serve/package.go +++ b/serve/package.go @@ -127,7 +127,7 @@ func (*PluginServe) getModuleName(pluginDirectory string) (string, error) { if err != nil { return "", fmt.Errorf("failed to get import path: %w", err) } - return importPath, nil + return strings.TrimSpace(importPath), nil } func (s *PluginServe) writePackageJSON(dir, pluginVersion string) error { @@ -159,7 +159,7 @@ func (s *PluginServe) writePackageJSON(dir, pluginVersion string) error { return os.WriteFile(outputPath, buffer.Bytes(), 0644) } -func (s *PluginServe) copyDocs(distPath, docsPath string) error { +func (*PluginServe) copyDocs(distPath, docsPath string) error { err := os.MkdirAll(filepath.Join(distPath, "docs"), 0755) if err != nil { return err @@ -210,7 +210,7 @@ func (s *PluginServe) newCmdPluginPackage() *cobra.Command { Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { pluginDirectory := args[0] - pluginVersion := strings.TrimSpace(args[1]) + pluginVersion := args[1] distPath := path.Join(pluginDirectory, "dist") if cmd.Flag("dist").Changed { distPath = cmd.Flag("dist").Value.String() From fa8c1a45276700df251312963c4af89d624ffd57 Mon Sep 17 00:00:00 2001 From: Herman Schaaf Date: Wed, 13 Sep 2023 10:57:22 +0100 Subject: [PATCH 7/7] Ignore markdown linting --- .github/workflows/lint_markdown.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint_markdown.yml b/.github/workflows/lint_markdown.yml index aabcd9530d..d4c2d29782 100644 --- a/.github/workflows/lint_markdown.yml +++ b/.github/workflows/lint_markdown.yml @@ -16,7 +16,7 @@ jobs: - name: Vale uses: errata-ai/vale-action@v2 with: - vale_flags: "--glob=!{docs/testdata/*,CHANGELOG.md,.github/styles/proselint/README.md}" + vale_flags: "--glob=!{docs/testdata/*,CHANGELOG.md,.github/styles/proselint/README.md,examples/simple_plugin/docs/*.md}" filter_mode: nofilter env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} @@ -31,4 +31,4 @@ jobs: with: files: . config_file: .markdownlint.yaml - ignore_files: "{docs/testdata/*,CHANGELOG.md}" + ignore_files: "{docs/testdata/*,CHANGELOG.md,examples/simple_plugin/docs/*.md}"