From 1416f01204d67dbff1c1ae07cc0e8fa10175ce14 Mon Sep 17 00:00:00 2001 From: Felipe Martin Date: Wed, 1 Oct 2025 20:44:21 +0200 Subject: [PATCH 1/4] feat: Add embedded frontend support with Go embed Implements a new Make target 'build-server-embedded' that creates a single binary containing both the server and React frontend using Go's standard embed library. Key Features: - New 'static' package with embed.go for asset embedding - Smart routing: serves static files, handles SPA routing, preserves API - Automatic detection of embedded assets vs API-only mode - Single deployable binary (~97MB with embedded frontend) - Proper MIME type detection for all asset types Changes: - Makefile: Added build-webapp and build-server-embedded targets - cmd/mcnb/server.go: Added embedded file serving with SPA routing support - static/embed.go: New package using //go:embed directive for asset embedding Usage: make build-server-embedded # Build server with embedded frontend ./build/mcnb-server server # Run server serving frontend at localhost:8070 The server automatically detects embedded assets and serves the React app while maintaining full API functionality at /api/v1/* endpoints. --- Makefile | 18 +++++++++++++++++- cmd/mcnb/server.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ static/embed.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 static/embed.go diff --git a/Makefile b/Makefile index 4cc055a..904dd12 100644 --- a/Makefile +++ b/Makefile @@ -47,4 +47,20 @@ lint-webapp: node_modules cd webapp; npm run lint .PHONY: check-style -check-style: lint-server govet lint-webapp \ No newline at end of file +check-style: lint-server govet lint-webapp + +.PHONY: build-webapp +build-webapp: node_modules + @echo Building webapp for production + cd webapp; npm run build + +.PHONY: build-server-embedded +build-server-embedded: build-webapp + @echo Building server with embedded frontend + @echo Copying webapp build files to static/build + rm -rf static/build + mkdir -p static + cp -r webapp/build static/ + go build -o build/mcnb-server ./cmd/mcnb + @echo Cleaning up copied files + rm -rf static/build \ No newline at end of file diff --git a/cmd/mcnb/server.go b/cmd/mcnb/server.go index 5e68760..fee43ee 100644 --- a/cmd/mcnb/server.go +++ b/cmd/mcnb/server.go @@ -2,16 +2,19 @@ package main import ( "context" + "io" "log" "net/http" "os" "os/signal" + "strings" "syscall" "time" "github.com/gorilla/mux" "github.com/mattermost/mattermost-cloudnative-bootstrapper/api" "github.com/mattermost/mattermost-cloudnative-bootstrapper/internal/logger" + "github.com/mattermost/mattermost-cloudnative-bootstrapper/static" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -39,6 +42,47 @@ var serverCmd = &cobra.Command{ api.Register(r, apiContext) + // Serve embedded static files if available (server mode) + if static.IsEmbedded() { + logger.FromContext(ctx).Info("Serving embedded frontend files") + staticFileSystem, err := static.GetEmbeddedFileSystem() + if err != nil { + logger.FromContext(ctx).WithError(err).Error("Failed to get embedded file system") + } else { + // Create a custom handler for SPA routing + spaHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + // Skip API routes - let them return 404 naturally + if strings.HasPrefix(req.URL.Path, "/api/v1") { + http.NotFound(w, req) + return + } + + // Try to serve the requested file first + if file, err := staticFileSystem.Open(req.URL.Path[1:]); err == nil { + defer file.Close() + http.ServeContent(w, req, req.URL.Path, time.Time{}, file.(io.ReadSeeker)) + return + } + + // If file not found and it's not an API route, serve index.html for SPA routing + indexFile, err := staticFileSystem.Open("index.html") + if err != nil { + http.NotFound(w, req) + return + } + defer indexFile.Close() + + w.Header().Set("Content-Type", "text/html; charset=utf-8") + http.ServeContent(w, req, "index.html", time.Time{}, indexFile.(io.ReadSeeker)) + }) + + // Serve everything through our custom handler + r.PathPrefix("/").Handler(spaHandler) + } + } else { + logger.FromContext(ctx).Info("No embedded frontend files found - running in API-only mode") + } + srv := &http.Server{ Addr: ":8070", Handler: r, diff --git a/static/embed.go b/static/embed.go new file mode 100644 index 0000000..bc422a1 --- /dev/null +++ b/static/embed.go @@ -0,0 +1,28 @@ +package static + +import ( + "embed" + "io/fs" + "net/http" +) + +//go:embed all:build +var embeddedFiles embed.FS + +// GetEmbeddedFileSystem returns the embedded file system containing the webapp build files +// It returns the build subdirectory as the root to serve files from +func GetEmbeddedFileSystem() (http.FileSystem, error) { + buildDir, err := fs.Sub(embeddedFiles, "build") + if err != nil { + return nil, err + } + return http.FS(buildDir), nil +} + +// IsEmbedded returns true if the embedded files are available +// This can be used to check if the server was built with embedded assets +func IsEmbedded() bool { + // Try to read a common file that should exist in the build + _, err := embeddedFiles.Open("build/index.html") + return err == nil +} From cd1aabcf59589512a3865525edfd182066bf4fe1 Mon Sep 17 00:00:00 2001 From: Felipe Martin Date: Wed, 1 Oct 2025 21:02:19 +0200 Subject: [PATCH 2/4] refactor: Upgrade dependencies and improve linting - Update Go version from 1.22.0 to 1.24 to match current toolchain - Replace deprecated golint with modern staticcheck linter - Update dependencies with 'go mod tidy' - Remove unused defaultLocalServerAPI constant - Add placeholder .gitkeep file to enable embed pattern during development This resolves linting compatibility issues and ensures our new embedded frontend code passes all style checks with modern tooling. --- Makefile | 6 +++--- cmd/mcnb/server.go | 2 -- go.mod | 11 ++++------- go.sum | 26 +------------------------- static/build/.gitkeep | 1 + 5 files changed, 9 insertions(+), 37 deletions(-) create mode 100644 static/build/.gitkeep diff --git a/Makefile b/Makefile index 904dd12..abe9365 100644 --- a/Makefile +++ b/Makefile @@ -22,10 +22,10 @@ build_desktop_desktop: build_desktop_macos .PHONY: lint-server lint-server: - @echo Running lint + @echo Running staticcheck @echo $(GOBIN) - GOBIN=$(GOBIN) $(GO) install golang.org/x/lint/golint - $(GOBIN)/golint -set_exit_status $(./...) + GOBIN=$(GOBIN) $(GO) install honnef.co/go/tools/cmd/staticcheck@latest + $(GOBIN)/staticcheck ./... @echo lint success .PHONY: govet diff --git a/cmd/mcnb/server.go b/cmd/mcnb/server.go index fee43ee..22833b0 100644 --- a/cmd/mcnb/server.go +++ b/cmd/mcnb/server.go @@ -19,8 +19,6 @@ import ( "github.com/spf13/cobra" ) -const defaultLocalServerAPI = "http://localhost:8070" - var serverCmd = &cobra.Command{ Use: "server", Short: "Run the Mattermost CloudNative Bootstrapper server", diff --git a/go.mod b/go.mod index 0ad659f..5725e47 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/mattermost/mattermost-cloudnative-bootstrapper -go 1.22.0 +go 1.24 -toolchain go1.22.3 +toolchain go1.24.3 require ( github.com/aws/aws-sdk-go v1.50.26 @@ -13,6 +13,8 @@ require ( github.com/mattermost/mattermost-cloud v0.81.2 github.com/mattermost/mattermost-operator v1.21.0-rc.2 github.com/mittwald/go-helm-client v0.12.8 + github.com/pborman/uuid v1.2.1 + github.com/rudderlabs/analytics-go/v4 v4.2.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.9.0 @@ -110,7 +112,6 @@ require ( github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect - github.com/pborman/uuid v1.2.1 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -122,8 +123,6 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/robfig/cron v1.2.0 // indirect github.com/rubenv/sql-migrate v1.6.1 // indirect - github.com/rudderlabs/analytics-go v3.3.3+incompatible // indirect - github.com/rudderlabs/analytics-go/v4 v4.2.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/segmentio/backo-go v1.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect @@ -136,7 +135,6 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect - github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect @@ -146,7 +144,6 @@ require ( go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.26.0 // indirect golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect - golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect golang.org/x/sync v0.8.0 // indirect diff --git a/go.sum b/go.sum index 54f3d00..ce0933b 100644 --- a/go.sum +++ b/go.sum @@ -410,8 +410,6 @@ github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rubenv/sql-migrate v1.6.1 h1:bo6/sjsan9HaXAsNxYP/jCEDUGibHp8JmOBw7NTGRos= github.com/rubenv/sql-migrate v1.6.1/go.mod h1:tPzespupJS0jacLfhbwto/UjSX+8h2FdWB7ar+QlHa0= -github.com/rudderlabs/analytics-go v3.3.3+incompatible h1:OG0XlKoXfr539e2t1dXtTB+Gr89uFW+OUNQBVhHIIBY= -github.com/rudderlabs/analytics-go v3.3.3+incompatible/go.mod h1:LF8/ty9kUX4PTY3l5c97K3nZZaX5Hwsvt+NBaRL/f30= github.com/rudderlabs/analytics-go/v4 v4.2.1 h1:J1fnTDXC8jNwytgOgnTgW5/IYafuvaCODE4UsNC8siU= github.com/rudderlabs/analytics-go/v4 v4.2.1/go.mod h1:/kXZkGO7S0of698Z62p8Y6KPH1nFaok32di9WPZMiE4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -448,7 +446,6 @@ github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= @@ -471,8 +468,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= -github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -506,23 +501,17 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.3.0 h1:HTDXbdK9bjfSWkPzDJIw89W8CAtfFGduujWs33NLLsg= golang.org/x/image v0.3.0/go.mod h1:fXd9211C/0VTlYuAcOhW8dY/RtEJqODXOWBDpmYBf+A= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -532,8 +521,6 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= @@ -544,8 +531,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -563,15 +548,11 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -579,20 +560,15 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/static/build/.gitkeep b/static/build/.gitkeep new file mode 100644 index 0000000..48cdce8 --- /dev/null +++ b/static/build/.gitkeep @@ -0,0 +1 @@ +placeholder From 6e3aff40619cdb2a5996270462dac43ac4afbda7 Mon Sep 17 00:00:00 2001 From: Felipe Martin Date: Wed, 1 Oct 2025 21:05:35 +0200 Subject: [PATCH 3/4] ci: Auto-detect Go version from go.mod file Replace hardcoded GO_VERSION environment variable with go-version-file parameter in actions/setup-go. This ensures CI automatically uses the exact Go version specified in go.mod without manual updates. Benefits: - Eliminates version drift between go.mod and CI - Automatic updates when go.mod version changes - Reduces maintenance overhead --- .github/workflows/ci.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0a09759..ffb2f25 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,7 +11,6 @@ defaults: env: TERM: xterm - GO_VERSION: 1.22.0 concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -29,7 +28,7 @@ jobs: uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 with: cache: true - go-version: ${{ env.GO_VERSION }} + go-version-file: 'go.mod' - name: ci/setup-node uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: From 2a2e0cfce1d1e7ca9018c4da0fd06a62e1949064 Mon Sep 17 00:00:00 2001 From: Felipe Martin Date: Wed, 1 Oct 2025 21:10:19 +0200 Subject: [PATCH 4/4] style: Fix all staticcheck linting issues - Fix error string capitalization (ST1005) - Simplify boolean returns (S1008) - Replace manual loop with append operation (S1011) - Remove unused struct field (U1000) Fixed issues in: - api/response_writer_wrapper.go: Lowercase error message - model/mattermost.go: Simplify IsValid() methods - providers/aws.go: Optimize role collection loop, fix error message - providers/custom.go: Remove unused kubeClient field, fix error messages All staticcheck and go vet checks now pass successfully. --- api/response_writer_wrapper.go | 2 +- model/mattermost.go | 12 ++---------- providers/aws.go | 9 +++------ providers/custom.go | 5 ++--- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/api/response_writer_wrapper.go b/api/response_writer_wrapper.go index 368b80b..08dcea3 100644 --- a/api/response_writer_wrapper.go +++ b/api/response_writer_wrapper.go @@ -52,7 +52,7 @@ func (rw *ResponseWriterWrapper) Write(data []byte) (int, error) { // Hijack calls the underlying writer's Hijack output. func (rw *ResponseWriterWrapper) Hijack() (net.Conn, *bufio.ReadWriter, error) { if rw.hijacker == nil { - return nil, nil, errors.New("Hijacker interface not supported by the wrapped ResponseWriter") + return nil, nil, errors.New("hijacker interface not supported by the wrapped ResponseWriter") } return rw.hijacker.Hijack() } diff --git a/model/mattermost.go b/model/mattermost.go index c217f30..36f5f83 100644 --- a/model/mattermost.go +++ b/model/mattermost.go @@ -122,19 +122,11 @@ func (is *InstallationSecrets) ToInstallationSecretsResponse() (*InstallationSec } func (le *LocalExternalFileStore) IsValid() bool { - if le.VolumeClaimName == "" { - return false - } - - return true + return le.VolumeClaimName != "" } func (l *LocalFileStore) IsValid() bool { - if l.StorageSize == "" { - return false - } - - return true + return l.StorageSize != "" } func (e *ExistingDBConnection) IsValid() bool { diff --git a/providers/aws.go b/providers/aws.go index eb33bea..779491c 100644 --- a/providers/aws.go +++ b/providers/aws.go @@ -181,11 +181,8 @@ func (a *AWSProvider) ListRoles(c context.Context) ([]*model.SupportedRolesRespo // List IAM roles input := &iam.ListRolesInput{} err = svc.ListRolesPages(input, func(page *iam.ListRolesOutput, lastPage bool) bool { - for _, role := range page.Roles { - // TODO Filter down to only those roles that have permission? - - eksSupportedRoles = append(eksSupportedRoles, role) - } + // TODO Filter down to only those roles that have permission? + eksSupportedRoles = append(eksSupportedRoles, page.Roles...) return !lastPage }) if err != nil { @@ -503,7 +500,7 @@ func (a *AWSProvider) HelmFileStorePre(c context.Context, clusterName string, na // Install a chart release. if _, err := helmClient.InstallOrUpgradeChart(context.Background(), &chartSpec, nil); err != nil { - return errors.New("Failed to install aws-ebs-csi-driver") + return errors.New("failed to install aws-ebs-csi-driver") } return nil diff --git a/providers/custom.go b/providers/custom.go index 163c39e..6c8c13a 100644 --- a/providers/custom.go +++ b/providers/custom.go @@ -25,7 +25,6 @@ import ( type CustomKubeProvider struct { Credentials *model.Credentials credentialsLock *sync.Mutex - kubeClient *model.KubeClient } var customProviderInstance *CustomKubeProvider @@ -101,12 +100,12 @@ func (p *CustomKubeProvider) ValidateCredentials(c context.Context, creds *model kubeClient, err := p.KubeClient(c, "") if err != nil { - return false, fmt.Errorf("Unable to instantiate KubeClient: %w", err) + return false, fmt.Errorf("unable to instantiate KubeClient: %w", err) } _, err = kubeClient.Clientset.Discovery().ServerVersion() if err != nil { - return false, fmt.Errorf("Unable to hit discovery endpoint for cluster: %w", err) + return false, fmt.Errorf("unable to hit discovery endpoint for cluster: %w", err) } return true, nil