From f4dcffd8d33753f34b286510dffbae2a4b1d4b58 Mon Sep 17 00:00:00 2001 From: Doug Lauder Date: Thu, 23 Jun 2022 07:55:50 -0400 Subject: [PATCH] Additional Product APIs for Focalboard multi-product architecture (#20527) * bump focalboard version; add services to product API * add API to fetch logger * import boards in same fashion as enterprise --- .gitignore | 3 ++- Makefile | 56 +++++++++++++++++++++++++++++++++++++--- app/channels.go | 17 +++--------- app/product.go | 17 ------------ app/server.go | 4 +-- model/version.go | 2 ++ product/api.go | 28 ++++++++++++++++---- scripts/setup_go_work.sh | 21 ++++++++++----- shared/mlog/mlog.go | 1 + 9 files changed, 99 insertions(+), 50 deletions(-) diff --git a/.gitignore b/.gitignore index e7cdecf92de..6d6121d78c5 100644 --- a/.gitignore +++ b/.gitignore @@ -22,8 +22,9 @@ config/config.json config/logging.json /plugins -# Enterprise imports file +# Enterprise & products imports files imports/imports.go +imports/boards_imports.go # go.work file go.work diff --git a/Makefile b/Makefile index 55feb2ada30..04736c8df62 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,8 @@ ifeq ($(BUILD_NUMBER),) BUILD_DATE := n/a BUILD_NUMBER := dev endif + +# Enterprise BUILD_ENTERPRISE_DIR ?= ../enterprise BUILD_ENTERPRISE ?= true BUILD_ENTERPRISE_READY = false @@ -56,6 +58,8 @@ else BUILD_ENTERPRISE_READY = false BUILD_TYPE_NAME = team endif + +# Webapp BUILD_WEBAPP_DIR ?= ../mattermost-webapp BUILD_CLIENT = false BUILD_HASH_CLIENT = independent @@ -70,6 +74,21 @@ else BUILD_CLIENT = false endif +# Boards +BUILD_BOARDS_DIR ?= ../focalboard +BUILD_BOARDS ?= true +BUILD_HASH_BOARDS = none +ifneq ($(wildcard $(BUILD_BOARDS_DIR)/.),) + ifeq ($(BUILD_BOARDS),true) + BUILD_BOARDS = true + BUILD_HASH_BOARDS = $(shell cd $(BUILD_BOARDS_DIR) && git rev-parse HEAD) + else + BUILD_BOARDS = false + endif +else + BUILD_BOARDS = false +endif + # We need current user's UID for `run-haserver` so docker compose does not run server # as root and mess up file permissions for devs. When running like this HOME will be blank # and docker will add '/', so we need to set the go-build cache location or we'll get @@ -91,6 +110,8 @@ LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildDate=$(BUIL LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHash=$(BUILD_HASH)" LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)" LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)" +LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHashBoards=$(BUILD_HASH_BOARDS)" +LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildBoards=$(BUILD_BOARDS)" GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1) GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2) @@ -156,6 +177,17 @@ else ALL_PACKAGES=$(TE_PACKAGES) endif +# Prepare optional Boards build. +BOARDS_PACKAGES=$(shell $(GO) list $(BUILD_BOARDS_DIR)/server/...) +ifeq ($(BUILD_BOARDS),true) + ALL_PACKAGES += $(BOARDS_PACKAGES) + IGNORE:=$(shell echo Boards build selected, preparing) + IGNORE:=$(shell rm -f imports/boards_imports.go) + IGNORE:=$(shell cp $(BUILD_BOARDS_DIR)/mattermost-plugin/product/imports/boards_imports.go imports/) +else + IGNORE:=$(shell rm -f imports/boards_imports.go) +endif + all: run ## Alias for 'run'. -include config.override.mk @@ -276,7 +308,12 @@ golangci-lint: ## Run golangci-lint on codebase $(GOBIN)/golangci-lint run ./... ifeq ($(BUILD_ENTERPRISE_READY),true) ifneq ($(MM_NO_ENTERPRISE_LINT),true) - $(GOBIN)/golangci-lint run ../enterprise/... + $(GOBIN)/golangci-lint run ../enterprise/... + endif +endif +ifeq ($(BUILD_BOARDS),true) + ifneq ($(MM_NO_BOARDS_LINT),true) + $(GOBIN)/golangci-lint run $(BUILD_BOARDS_DIR)/server/... endif endif @@ -361,10 +398,10 @@ ifeq ($(BUILD_ENTERPRISE_READY),true) ./scripts/prereq-check-enterprise.sh endif +setup-go-work: export BUILD_ENTERPRISE_READY := $(BUILD_ENTERPRISE_READY) +setup-go-work: export BUILD_BOARDS := $(BUILD_BOARDS) setup-go-work: ## Sets up your go.work file -ifeq ($(BUILD_ENTERPRISE_READY),true) ./scripts/setup_go_work.sh -endif check-style: golangci-lint plugin-checker vet ## Runs style/lint checks @@ -396,6 +433,9 @@ gomodtidy: @if [ -f "imports/imports.go" ]; then \ mv imports/imports.go imports/imports.go.orig; \ fi; + @if [ -f "imports/boards_imports.go" ]; then \ + mv imports/boards_imports.go imports/boards_imports.go.orig; \ + fi; $(GO) mod tidy @if [ "$$(diff go.mod go.mod.orig)" != "" -o "$$(diff go.sum go.sum.orig)" != "" ]; then \ echo "go.mod/go.sum was modified. \ndiff- $$(diff go.mod go.mod.orig) \n$$(diff go.sum go.sum.orig) \nRun \"go mod tidy\"."; \ @@ -405,17 +445,25 @@ gomodtidy: @if [ -f "imports/imports.go.orig" ]; then \ mv imports/imports.go.orig imports/imports.go; \ fi; + @if [ -f "imports/boards_imports.go.orig" ]; then \ + mv imports/boards_imports.go.orig imports/boards_imports.go; \ + fi; @rm go.*.orig; modules-tidy: @if [ -f "imports/imports.go" ]; then \ mv imports/imports.go imports/imports.go.orig; \ fi; + @if [ -f "imports/boards_imports.go" ]; then \ + mv imports/boards_imports.go imports/boards_imports.go.orig; \ + fi; -$(GO) mod tidy @if [ -f "imports/imports.go.orig" ]; then \ mv imports/imports.go.orig imports/imports.go; \ fi; - + @if [ -f "imports/boards_imports.go.orig" ]; then \ + mv imports/boards_imports.go.orig imports/boards_imports.go; \ + fi; test-server-pre: check-prereqs-enterprise start-docker go-junit-report do-cover-file ## Runs tests. ifeq ($(BUILD_ENTERPRISE_READY),true) diff --git a/app/channels.go b/app/channels.go index 4ecbbe2c233..91145335027 100644 --- a/app/channels.go +++ b/app/channels.go @@ -10,6 +10,8 @@ import ( "sync" "sync/atomic" + "github.com/pkg/errors" + "github.com/mattermost/mattermost-server/v6/app/imaging" "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/config" @@ -20,19 +22,8 @@ import ( "github.com/mattermost/mattermost-server/v6/services/imageproxy" "github.com/mattermost/mattermost-server/v6/shared/filestore" "github.com/mattermost/mattermost-server/v6/shared/mlog" - "github.com/pkg/errors" ) -// configSvc is a consumer interface to work -// with any config related task with the server. -type configSvc interface { - Config() *model.Config - AddConfigListener(listener func(*model.Config, *model.Config)) string - RemoveConfigListener(id string) - UpdateConfig(f func(*model.Config)) - SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError) -} - // licenseSvc is added to act as a starting point for future integrated products. // It has the same signature and functionality with the license related APIs of the plugin-api. type licenseSvc interface { @@ -49,7 +40,7 @@ type namer interface { // Channels contains all channels related state. type Channels struct { srv *Server - cfgSvc configSvc + cfgSvc product.ConfigService filestore filestore.FileBackend licenseSvc licenseSvc routerSvc *routerService @@ -135,7 +126,7 @@ func NewChannels(s *Server, services map[ServiceKey]interface{}) (*Channels, err switch svcKey { // Keep adding more services here case ConfigKey: - cfgSvc, ok := svc.(configSvc) + cfgSvc, ok := svc.(product.ConfigService) if !ok { return nil, errors.New("Config service did not satisfy ConfigSvc interface") } diff --git a/app/product.go b/app/product.go index 0412ca2e8e1..2e09f137c89 100644 --- a/app/product.go +++ b/app/product.go @@ -6,8 +6,6 @@ package app import ( "fmt" "strings" - - "github.com/mattermost/mattermost-server/v6/shared/mlog" ) type Product interface { @@ -80,18 +78,3 @@ func (s *Server) initializeProducts( return nil } - -type logWrapper struct { - srv *Server -} - -func (s *logWrapper) LogError(productID, msg string, keyValuePairs ...interface{}) { - s.srv.Log.Error(msg, mlog.String("product_id", productID), mlog.Map("key-value pairs", keyValuePairs)) -} - -func (s *logWrapper) LogWarn(productID, msg string, keyValuePairs ...interface{}) { - s.srv.Log.Warn(msg, mlog.String("product_id", productID), mlog.Map("key-value pairs", keyValuePairs)) -} -func (s *logWrapper) LogDebug(productID, msg string, keyValuePairs ...interface{}) { - s.srv.Log.Debug(msg, mlog.String("product_id", productID), mlog.Map("key-value pairs", keyValuePairs)) -} diff --git a/app/server.go b/app/server.go index 087bba50a38..f3f07ff98c1 100644 --- a/app/server.go +++ b/app/server.go @@ -399,9 +399,7 @@ func NewServer(options ...Option) (*Server, error) { FilestoreKey: s.filestore, ClusterKey: s.clusterWrapper, UserKey: New(ServerConnector(s.Channels())), - LogKey: &logWrapper{ - srv: s, - }, + LogKey: s.GetLogger(), } // Step 8: Initialize products. diff --git a/model/version.go b/model/version.go index 5d615a7ebeb..c4e1bfd8461 100644 --- a/model/version.go +++ b/model/version.go @@ -109,6 +109,8 @@ var BuildDate string var BuildHash string var BuildHashEnterprise string var BuildEnterpriseReady string +var BuildHashBoards string +var BuildBoards string var versionsWithoutHotFixes []string func init() { diff --git a/product/api.go b/product/api.go index a59af13abe0..e7df857b94f 100644 --- a/product/api.go +++ b/product/api.go @@ -4,10 +4,14 @@ package product import ( + "io" + "github.com/gorilla/mux" + "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" + "github.com/mattermost/mattermost-server/v6/shared/filestore" ) // RouterService enables registering the product router to the server. After registering the @@ -95,11 +99,13 @@ type BotService interface { EnsureBot(ctx *request.Context, productID string, bot *model.Bot) (string, error) } -// LogService shall be registered via app.LogKey service key. -type LogService interface { - LogError(productID, msg string, keyValuePairs ...interface{}) - LogWarn(productID, msg string, keyValuePairs ...interface{}) - LogDebug(productID, msg string, keyValuePairs ...interface{}) +// ConfigService shall be registered via app.ConfigKey service key. +type ConfigService interface { + Config() *model.Config + AddConfigListener(listener func(*model.Config, *model.Config)) string + RemoveConfigListener(id string) + UpdateConfig(f func(*model.Config)) + SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError) } // Hooks is an interim solution for enabling plugin hooks on the multi-product architecture. After the @@ -116,3 +122,15 @@ type Hooks interface { type HooksService interface { RegisterHooks(productID string, hooks Hooks) error } + +// FilestoreService is the API for accessing the file store. +// +// The service shall be registered via app.FilestoreKey service key. +type FilestoreService interface { + Reader(path string) (filestore.ReadCloseSeeker, error) + FileExists(path string) (bool, error) + CopyFile(oldPath, newPath string) error + MoveFile(oldPath, newPath string) error + WriteFile(fr io.Reader, path string) (int64, error) + RemoveFile(path string) error +} diff --git a/scripts/setup_go_work.sh b/scripts/setup_go_work.sh index b7f0533cfee..681121838b1 100755 --- a/scripts/setup_go_work.sh +++ b/scripts/setup_go_work.sh @@ -3,11 +3,18 @@ if [[ ! -f "go.work" ]] ; then echo "Creating a go.work file" - cat >go.work < "go.work" +fi \ No newline at end of file diff --git a/shared/mlog/mlog.go b/shared/mlog/mlog.go index 9b4bb820bf8..368df6f53ee 100644 --- a/shared/mlog/mlog.go +++ b/shared/mlog/mlog.go @@ -37,6 +37,7 @@ type LoggerIFace interface { Critical(string, ...Field) Log(Level, string, ...Field) LogM([]Level, string, ...Field) + With(fields ...Field) *Logger } // Type and function aliases from Logr to limit the spread of dependencies.