From a9da2e978e7a1f01bd8bd8a6569da384aa0ec6b3 Mon Sep 17 00:00:00 2001 From: Mateusz Szostok Date: Sat, 15 Apr 2023 20:20:40 +0200 Subject: [PATCH] Add tpl approach for plugin goreleaser config --- .goreleaser.plugin.tpl.yaml | 38 +++++++ .goreleaser.plugin.yaml | 168 +++++++++++++++++++++-------- Makefile | 2 + cmd/botkube/main.go | 6 +- cmd/source/cm-watcher/main.go | 14 +-- hack/gen-plugin-index.go | 16 +-- hack/target/gen-goreleaser/main.go | 56 ++++++++++ internal/loggerx/error.go | 24 +++++ test/helpers/plugin_server.go | 11 +- 9 files changed, 259 insertions(+), 76 deletions(-) create mode 100644 .goreleaser.plugin.tpl.yaml mode change 100644 => 100755 .goreleaser.plugin.yaml create mode 100644 hack/target/gen-goreleaser/main.go create mode 100644 internal/loggerx/error.go diff --git a/.goreleaser.plugin.tpl.yaml b/.goreleaser.plugin.tpl.yaml new file mode 100644 index 000000000..544d30ba7 --- /dev/null +++ b/.goreleaser.plugin.tpl.yaml @@ -0,0 +1,38 @@ +# GoReleaser already creates Botkube artifacts in the ./dist folder. +# To not override them during release, we use a different folder +dist: plugin-dist + +before: + hooks: + - go mod download + +builds: + + - id: <.Name> + main: cmd/<.Type>/<.Name>/main.go + binary: <.Type>_<.Name>_{{ .Os }}_{{ .Arch }} + + no_unique_dist_dir: true + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - amd64 + - arm64 + goarm: + - 7 + + +archives: + + - builds: [<.Name>] + id: <.Name> + files: + - none* + name_template: "{{ .Binary }}" + + +snapshot: + name_template: 'v{{ .Version }}' diff --git a/.goreleaser.plugin.yaml b/.goreleaser.plugin.yaml old mode 100644 new mode 100755 index 3a6bc8c39..9610837db --- a/.goreleaser.plugin.yaml +++ b/.goreleaser.plugin.yaml @@ -7,82 +7,164 @@ before: - go mod download builds: + - id: echo main: cmd/executor/echo/main.go binary: executor_echo_{{ .Os }}_{{ .Arch }} no_unique_dist_dir: true - env: &env + env: - CGO_ENABLED=0 - goos: &goos + goos: - linux - darwin - goarch: &goarch + goarch: - amd64 - arm64 - goarm: &goarm + goarm: - 7 - - - id: helm - main: cmd/executor/helm/main.go - binary: executor_helm_{{ .Os }}_{{ .Arch }} - - no_unique_dist_dir: true - env: *env - goos: *goos - goarch: *goarch - goarm: *goarm - + - id: gh main: cmd/executor/gh/main.go binary: executor_gh_{{ .Os }}_{{ .Arch }} no_unique_dist_dir: true - env: *env - goos: *goos - goarch: *goarch - goarm: *goarm - + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - amd64 + - arm64 + goarm: + - 7 + + - id: helm + main: cmd/executor/helm/main.go + binary: executor_helm_{{ .Os }}_{{ .Arch }} + no_unique_dist_dir: true + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - amd64 + - arm64 + goarm: + - 7 + - id: kubectl main: cmd/executor/kubectl/main.go binary: executor_kubectl_{{ .Os }}_{{ .Arch }} no_unique_dist_dir: true - env: *env - goos: *goos - goarch: *goarch - goarm: *goarm - + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - amd64 + - arm64 + goarm: + - 7 + - id: cm-watcher main: cmd/source/cm-watcher/main.go binary: source_cm-watcher_{{ .Os }}_{{ .Arch }} no_unique_dist_dir: true - env: *env - goos: *goos - goarch: *goarch - goarm: *goarm + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - amd64 + - arm64 + goarm: + - 7 + + - id: kubernetes + main: cmd/source/kubernetes/main.go + binary: source_kubernetes_{{ .Os }}_{{ .Arch }} + no_unique_dist_dir: true + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - amd64 + - arm64 + goarm: + - 7 + - id: prometheus main: cmd/source/prometheus/main.go binary: source_prometheus_{{ .Os }}_{{ .Arch }} no_unique_dist_dir: true - env: *env - goos: *goos - goarch: *goarch - goarm: *goarm - - - id: kubernetes - main: cmd/source/kubernetes/main.go - binary: source_kubernetes_{{ .Os }}_{{ .Arch }} - - no_unique_dist_dir: true - env: *env - goos: *goos - goarch: *goarch - goarm: *goarm + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - amd64 + - arm64 + goarm: + - 7 + + +archives: + + - builds: [echo] + id: echo + files: + - none* + name_template: "{{ .Binary }}" + + - builds: [gh] + id: gh + files: + - none* + name_template: "{{ .Binary }}" + + - builds: [helm] + id: helm + files: + - none* + name_template: "{{ .Binary }}" + + - builds: [kubectl] + id: kubectl + files: + - none* + name_template: "{{ .Binary }}" + + - builds: [cm-watcher] + id: cm-watcher + files: + - none* + name_template: "{{ .Binary }}" + + - builds: [kubernetes] + id: kubernetes + files: + - none* + name_template: "{{ .Binary }}" + + - builds: [prometheus] + id: prometheus + files: + - none* + name_template: "{{ .Binary }}" + snapshot: name_template: 'v{{ .Version }}' diff --git a/Makefile b/Makefile index 5a91d3870..10b9ccb23 100644 --- a/Makefile +++ b/Makefile @@ -31,12 +31,14 @@ build: pre-build # Build Botkube official plugins for all supported platforms. build-plugins: pre-build @echo "Building plugins binaries" + go run ./hack/target/gen-goreleaser/main.go @./hack/goreleaser.sh build_plugins @echo "Build completed successfully" # Build Botkube official plugins only for current GOOS and GOARCH. build-plugins-single: pre-build @echo "Building single target plugins binaries" + go run ./hack/target/gen-goreleaser/main.go @./hack/goreleaser.sh build_plugins_single @echo "Build completed successfully" diff --git a/cmd/botkube/main.go b/cmd/botkube/main.go index 2dc11e0ef..dcde3cc1d 100644 --- a/cmd/botkube/main.go +++ b/cmd/botkube/main.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "log" "net/http" "time" @@ -67,9 +66,8 @@ func main() { ctx, cancelCtxFn := context.WithCancel(ctx) defer cancelCtxFn() - if err := run(ctx); err != nil { - log.Fatal(err) - } + err := run(ctx) + loggerx.ExitOnError(err, "while running app") } // run wraps the main logic of the app to be able to properly clean up resources via deferred calls. diff --git a/cmd/source/cm-watcher/main.go b/cmd/source/cm-watcher/main.go index eb6c08302..36c16d9ab 100644 --- a/cmd/source/cm-watcher/main.go +++ b/cmd/source/cm-watcher/main.go @@ -3,7 +3,6 @@ package main import ( "context" "fmt" - "log" "github.com/MakeNowJust/heredoc" "github.com/hashicorp/go-plugin" @@ -17,6 +16,7 @@ import ( "k8s.io/client-go/tools/clientcmd" watchtools "k8s.io/client-go/tools/watch" + "github.com/kubeshop/botkube/internal/loggerx" "github.com/kubeshop/botkube/pkg/api" "github.com/kubeshop/botkube/pkg/api/source" "github.com/kubeshop/botkube/pkg/pluginx" @@ -82,9 +82,9 @@ func (CMWatcher) Stream(ctx context.Context, in source.StreamInput) (source.Stre func listenEvents(ctx context.Context, kubeConfig []byte, obj Object, sink chan<- []byte) { config, err := clientcmd.RESTConfigFromKubeConfig(kubeConfig) - exitOnError(err) + loggerx.ExitOnError(err, "while creating kubeconfig") clientset, err := kubernetes.NewForConfig(config) - exitOnError(err) + loggerx.ExitOnError(err, "while creating k8s client") fieldSelector := fields.OneTermEqualSelector("metadata.name", obj.Name).String() lw := &cache.ListWatch{ @@ -110,7 +110,7 @@ func listenEvents(ctx context.Context, kubeConfig []byte, obj Object, sink chan< } _, err = watchtools.UntilWithSync(ctx, lw, &corev1.ConfigMap{}, nil, infiniteWatch) - exitOnError(err) + loggerx.ExitOnError(err, "while watching for ConfigMaps") } func main() { @@ -121,12 +121,6 @@ func main() { }) } -func exitOnError(err error) { - if err != nil { - log.Fatal(err) - } -} - func jsonSchema() api.JSONSchema { return api.JSONSchema{ Value: heredoc.Docf(`{ diff --git a/hack/gen-plugin-index.go b/hack/gen-plugin-index.go index 6e33cd74f..7695b8d78 100644 --- a/hack/gen-plugin-index.go +++ b/hack/gen-plugin-index.go @@ -2,13 +2,13 @@ package main import ( "flag" - "log" "os" "path/filepath" "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" + "github.com/kubeshop/botkube/internal/loggerx" "github.com/kubeshop/botkube/internal/plugin" ) @@ -28,7 +28,7 @@ func main() { idxBuilder := plugin.NewIndexBuilder(logger) absBinsDir, err := filepath.Abs(*binsDir) - exitOnError("while resolving an absolute path of binaries folder", err) + loggerx.ExitOnError(err, "while resolving an absolute path of binaries folder") log := logger.WithFields(logrus.Fields{ "binDir": absBinsDir, @@ -38,18 +38,12 @@ func main() { log.Info("Building index..") idx, err := idxBuilder.Build(absBinsDir, *urlBasePath, *pluginNameFilter) - exitOnError("while building plugin index", err) + loggerx.ExitOnError(err, "while building plugin index") raw, err := yaml.Marshal(idx) - exitOnError("while marshaling index into YAML format", err) + loggerx.ExitOnError(err, "while marshaling index into YAML format") logger.WithField("output", *output).Info("Saving index file...") err = os.WriteFile(*output, raw, filePerm) - exitOnError("while saving index file", err) -} - -func exitOnError(context string, err error) { - if err != nil { - log.Fatalf("%s: %s", context, err) - } + loggerx.ExitOnError(err, "while saving index file") } diff --git a/hack/target/gen-goreleaser/main.go b/hack/target/gen-goreleaser/main.go new file mode 100644 index 000000000..e180500a0 --- /dev/null +++ b/hack/target/gen-goreleaser/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "os" + "text/template" + + "github.com/kubeshop/botkube/internal/loggerx" +) + +const ( + templateFile = "./.goreleaser.plugin.tpl.yaml" + outputFile = "./.goreleaser.plugin.yaml" + entrypoint = "./cmd" + filePerm = 0o755 +) + +type ( + Plugins []Plugin + Plugin struct { + Name string + Type string + } +) + +func main() { + executors, err := os.ReadDir(entrypoint + "/executor") + loggerx.ExitOnError(err, "collecting executors") + sources, err := os.ReadDir(entrypoint + "/source") + loggerx.ExitOnError(err, "collecting sources") + + var plugins Plugins + for _, d := range executors { + plugins = append(plugins, Plugin{ + Type: "executor", + Name: d.Name(), + }) + } + for _, d := range sources { + plugins = append(plugins, Plugin{ + Type: "source", + Name: d.Name(), + }) + } + + file, err := os.ReadFile(templateFile) + loggerx.ExitOnError(err, "reading tpl file") + + tpl, err := template.New("goreleaser").Delims("<", ">").Parse(string(file)) + loggerx.ExitOnError(err, "creating tpl processor") + + dst, err := os.OpenFile(outputFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, filePerm) + loggerx.ExitOnError(err, "open destination file file") + + err = tpl.Execute(dst, plugins) + loggerx.ExitOnError(err, "while running tpl processor") +} diff --git a/internal/loggerx/error.go b/internal/loggerx/error.go new file mode 100644 index 000000000..a6cb74a00 --- /dev/null +++ b/internal/loggerx/error.go @@ -0,0 +1,24 @@ +package loggerx + +import ( + "os" + + "github.com/sirupsen/logrus" +) + +// ExitOnError exits an app with a given error. +func ExitOnError(err error, context string) { + if err == nil { + return + } + log := &logrus.Logger{ + Out: os.Stdout, + Formatter: &logrus.TextFormatter{FullTimestamp: true}, + Hooks: make(logrus.LevelHooks), + Level: logrus.InfoLevel, + ExitFunc: os.Exit, + ReportCaller: false, + } + + log.Fatalf("%s: %s", context, err) +} diff --git a/test/helpers/plugin_server.go b/test/helpers/plugin_server.go index 99b1fffc5..ad34aa825 100644 --- a/test/helpers/plugin_server.go +++ b/test/helpers/plugin_server.go @@ -5,12 +5,13 @@ import ( "os" "path/filepath" + "github.com/kubeshop/botkube/internal/loggerx" "github.com/kubeshop/botkube/test/fake" ) func main() { dir, err := os.Getwd() - exitOnErr(err) + loggerx.ExitOnError(err, "while getting current directory") host := os.Getenv("PLUGIN_SERVER_HOST") if host == "" { @@ -29,11 +30,5 @@ func main() { log.Printf("Service plugin binaries from %s\n", binDir) log.Printf("Botkube repository index URL: %s", indexEndpoint) err = startServerFn() - exitOnErr(err) -} - -func exitOnErr(err error) { - if err != nil { - log.Fatal(err) - } + loggerx.ExitOnError(err, "while starting server") }