# Build Flags BUILD_NUMBER ?= $(BUILD_NUMBER:) BUILD_DATE = $(shell date -u) BUILD_HASH = $(shell git rev-parse HEAD) # If we don't set the build number it defaults to dev ifeq ($(BUILD_NUMBER),) BUILD_NUMBER := dev BUILD_DATE := n/a endif MM_SERVER_PATH ?= $(MM_SERVER_PATH:) ifeq ($(MM_SERVER_PATH),) MM_SERVER_PATH := ../../mattermost endif LDFLAGS += -X "github.com/mattermost/focalboard/server/model.BuildNumber=$(BUILD_NUMBER)" LDFLAGS += -X "github.com/mattermost/focalboard/server/model.BuildDate=$(BUILD_DATE)" LDFLAGS += -X "github.com/mattermost/focalboard/server/model.BuildHash=$(BUILD_HASH)" LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=plugin" GO ?= $(shell command -v go 2> /dev/null) NPM ?= $(shell command -v npm 2> /dev/null) CURL ?= $(shell command -v curl 2> /dev/null) MM_DEBUG ?= MANIFEST_FILE ?= plugin.json GOPATH ?= $(shell go env GOPATH) GO_TEST_FLAGS ?= -race GO_BUILD_FLAGS ?= -ldflags '$(LDFLAGS)' MM_UTILITIES_DIR ?= ../mattermost-utilities DLV_DEBUG_PORT := 2346 MATTERMOST_PLUGINS_PATH=$(MM_SERVER_PATH)/plugins FOCALBOARD_PLUGIN_PATH=$(MATTERMOST_PLUGINS_PATH)/focalboard export GO111MODULE=on # You can include assets this directory into the bundle. This can be e.g. used to include profile pictures. ASSETS_DIR ?= assets ## Define the default target (make all) .PHONY: default default: all # Verify environment, and define PLUGIN_ID, PLUGIN_VERSION, HAS_SERVER and HAS_WEBAPP as needed. include build/setup.mk BUNDLE_NAME ?= $(PLUGIN_ID)-$(PLUGIN_VERSION).tar.gz # Include custom makefile, if present ifneq ($(wildcard build/custom.mk),) include build/custom.mk endif ## Checks the code style, tests, builds and bundles the plugin. .PHONY: all all: check-style test dist ## Propagates plugin manifest information into the server/ and webapp/ folders. .PHONY: apply apply: ./build/bin/manifest apply setup-go-work: ## Sets up a go.work file cd ..; go run ./build/gowork/main.go ## Runs eslint and golangci-lint .PHONY: check-style check-style: webapp/node_modules @echo Checking for style guide compliance ifneq ($(HAS_WEBAPP),) cd webapp && npm run lint cd webapp && npm run check-types endif ifneq ($(HAS_SERVER),) @if ! [ -x "$$(command -v golangci-lint)" ]; then \ echo "golangci-lint is not installed. Please see https://github.com/golangci/golangci-lint#install-golangci-lint for installation instructions."; \ exit 1; \ fi; \ @echo Running golangci-lint golangci-lint run ./... endif templates-archive: setup-go-work ## Build templates archive file cd ../server/assets/build-template-archive; go run -tags '$(BUILD_TAGS)' main.go --dir="../templates-boardarchive" --out="../templates.boardarchive" ## Builds the server, if it exists, for all supported architectures. .PHONY: server server: templates-archive ifneq ($(HAS_SERVER),) mkdir -p server/dist; ifeq ($(MM_DEBUG),) cd server && env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -trimpath -o dist/plugin-linux-amd64; cd server && env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GO) build $(GO_BUILD_FLAGS) -trimpath -o dist/plugin-linux-arm64; cd server && env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -trimpath -o dist/plugin-darwin-amd64; cd server && env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 $(GO) build $(GO_BUILD_FLAGS) -trimpath -o dist/plugin-darwin-arm64; cd server && env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -trimpath -o dist/plugin-windows-amd64.exe; else $(info DEBUG mode is on; to disable, unset MM_DEBUG) cd server && env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -gcflags "all=-N -l" -trimpath -o dist/plugin-darwin-amd64; cd server && env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 $(GO) build $(GO_BUILD_FLAGS) -gcflags "all=-N -l" -trimpath -o dist/plugin-darwin-arm64; cd server && env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -gcflags "all=-N -l" -trimpath -o dist/plugin-linux-amd64; cd server && env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GO) build $(GO_BUILD_FLAGS) -gcflags "all=-N -l" -trimpath -o dist/plugin-linux-arm64; cd server && env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -gcflags "all=-N -l" -trimpath -o dist/plugin-windows-amd64.exe; endif endif ## Ensures NPM dependencies are installed without having to run this all the time. webapp/node_modules: $(wildcard webapp/package.json) ifneq ($(HAS_WEBAPP),) cd webapp && $(NPM) install touch $@ endif ## Builds the webapp, if it exists. .PHONY: webapp webapp: webapp/node_modules ifneq ($(HAS_WEBAPP),) ifeq ($(MM_DEBUG),) cd webapp && $(NPM) run build; else cd webapp && $(NPM) run debug; endif endif ## Generates a tar bundle of the plugin for install. .PHONY: bundle bundle: rm -rf dist/ mkdir -p dist/$(PLUGIN_ID) cp $(MANIFEST_FILE) dist/$(PLUGIN_ID)/ cp -r ../webapp/pack dist/$(PLUGIN_ID)/ ifneq ($(wildcard $(ASSETS_DIR)/.),) cp -r $(ASSETS_DIR) dist/$(PLUGIN_ID)/ endif ifneq ($(HAS_PUBLIC),) cp -r public dist/$(PLUGIN_ID)/public/ endif ifneq ($(HAS_SERVER),) mkdir -p dist/$(PLUGIN_ID)/server cp -r server/dist dist/$(PLUGIN_ID)/server/ endif ifneq ($(HAS_WEBAPP),) mkdir -p dist/$(PLUGIN_ID)/webapp cp -r webapp/dist dist/$(PLUGIN_ID)/webapp/ endif cd dist && tar -cvzf $(BUNDLE_NAME) $(PLUGIN_ID) @echo plugin built at: dist/$(BUNDLE_NAME) ## Builds and bundles the plugin. .PHONY: dist dist: apply server webapp bundle ## Builds and installs the plugin to a server. .PHONY: deploy deploy: dist ./build/bin/pluginctl deploy $(PLUGIN_ID) dist/$(BUNDLE_NAME) ## Builds and installs the plugin to a server, updating the webapp automatically when changed. .PHONY: watch watch: apply server bundle ifeq ($(MM_DEBUG),) cd webapp && $(NPM) run build:watch else cd webapp && $(NPM) run debug:watch endif ## Installs a previous built plugin with updated webpack assets to a server. .PHONY: deploy-from-watch deploy-from-watch: bundle ./build/bin/pluginctl deploy $(PLUGIN_ID) dist/$(BUNDLE_NAME) .PHONY: build-product build-product: apply cd webapp && npm run build:product .PHONY: watch-product watch-product: apply cd webapp && npm run start:product ## Setup dlv for attaching, identifying the plugin PID for other targets. .PHONY: setup-attach setup-attach: $(eval PLUGIN_PID := $(shell ps aux | grep "plugins/${PLUGIN_ID}" | grep -v "grep" | awk -F " " '{print $$2}')) $(eval NUM_PID := $(shell echo -n ${PLUGIN_PID} | wc -w)) @if [ ${NUM_PID} -gt 2 ]; then \ echo "** There is more than 1 plugin process running. Run 'make kill reset' to restart just one."; \ exit 1; \ fi ## Check if setup-attach succeeded. .PHONY: check-attach check-attach: @if [ -z ${PLUGIN_PID} ]; then \ echo "Could not find plugin PID; the plugin is not running. Exiting."; \ exit 1; \ else \ echo "Located Plugin running with PID: ${PLUGIN_PID}"; \ fi ## Attach dlv to an existing plugin instance. .PHONY: attach attach: setup-attach check-attach dlv attach ${PLUGIN_PID} ## Attach dlv to an existing plugin instance, exposing a headless instance on $DLV_DEBUG_PORT. .PHONY: attach-headless attach-headless: setup-attach check-attach dlv attach ${PLUGIN_PID} --listen :$(DLV_DEBUG_PORT) --headless=true --api-version=2 --accept-multiclient ## Detach dlv from an existing plugin instance, if previously attached. .PHONY: detach detach: setup-attach @DELVE_PID=$(shell ps aux | grep "dlv attach ${PLUGIN_PID}" | grep -v "grep" | awk -F " " '{print $$2}') && \ if [ "$$DELVE_PID" -gt 0 ] > /dev/null 2>&1 ; then \ echo "Located existing delve process running with PID: $$DELVE_PID. Killing." ; \ kill -9 $$DELVE_PID ; \ fi ## Runs any lints and unit tests defined for the server and webapp, if they exist. .PHONY: test test: export FOCALBOARD_UNIT_TESTING=1 test: webapp/node_modules ifneq ($(HAS_SERVER),) $(GO) test -v $(GO_TEST_FLAGS) ./server/... endif ifneq ($(HAS_WEBAPP),) cd webapp && $(NPM) run test; endif ifneq ($(wildcard ./build/sync/plan/.),) cd ./build/sync && $(GO) test -v $(GO_TEST_FLAGS) ./... endif ## Creates a coverage report for the server code. .PHONY: coverage coverage: webapp/node_modules ifneq ($(HAS_SERVER),) $(GO) test $(GO_TEST_FLAGS) -coverprofile=server/coverage.txt ./server/... $(GO) tool cover -html=server/coverage.txt endif ## Extract strings for translation from the source code. .PHONY: i18n-extract i18n-extract: ifneq ($(HAS_WEBAPP),) ifeq ($(HAS_MM_UTILITIES),) @echo "You must clone github.com/mattermost/mattermost-utilities repo in .. to use this command" else cd $(MM_UTILITIES_DIR) && npm install && npm run babel && node mmjstool/build/index.js i18n extract-webapp --webapp-dir $(PWD)/webapp endif endif ## Disable the plugin. .PHONY: disable disable: detach ./build/bin/pluginctl disable $(PLUGIN_ID) ## Enable the plugin. .PHONY: enable enable: ./build/bin/pluginctl enable $(PLUGIN_ID) ## Reset the plugin, effectively disabling and re-enabling it on the server. .PHONY: reset reset: detach ./build/bin/pluginctl reset $(PLUGIN_ID) ## Kill all instances of the plugin, detaching any existing dlv instance. .PHONY: kill kill: detach $(eval PLUGIN_PID := $(shell ps aux | grep "plugins/${PLUGIN_ID}" | grep -v "grep" | awk -F " " '{print $$2}')) @for PID in ${PLUGIN_PID}; do \ echo "Killing plugin pid $$PID"; \ kill -9 $$PID; \ done; \ ## Clean removes all build artifacts. .PHONY: clean clean: rm -fr dist/ ifneq ($(HAS_SERVER),) rm -fr server/coverage.txt rm -fr server/dist endif ifneq ($(HAS_WEBAPP),) rm -fr webapp/junit.xml rm -fr webapp/dist rm -fr webapp/node_modules endif rm -fr build/bin/ ## Sync directory with a starter template sync: ifndef STARTERTEMPLATE_PATH @echo STARTERTEMPLATE_PATH is not set. @echo Set STARTERTEMPLATE_PATH to a local clone of https://github.com/mattermost/mattermost-plugin-starter-template and retry. @exit 1 endif cd ${STARTERTEMPLATE_PATH} && go run ./build/sync/main.go ./build/sync/plan.yml $(PWD) ## Watch webapp and server changes and redeploy locally using local filesystem (MM_SERVER_PATH) .PHONY: live-watch live-watch: make -j2 live-watch-server live-watch-webapp ## Watch server changes and redeploy locally using local filesystem (MM_SERVER_PATH) .PHONY: live-watch-server live-watch-server: apply cd ../ && modd -f mattermost-plugin/modd.conf ## Watch webapp changes and redeploy locally using local filesystem (MM_SERVER_PATH) .PHONY: live-watch-webapp live-watch-webapp: apply cd webapp && $(NPM) run live-watch .PHONY: deploy-to-mattermost-directory deploy-to-mattermost-directory: ./build/bin/pluginctl disable $(PLUGIN_ID) mkdir -p $(FOCALBOARD_PLUGIN_PATH) cp $(MANIFEST_FILE) $(FOCALBOARD_PLUGIN_PATH)/ cp -r ../webapp/pack $(FOCALBOARD_PLUGIN_PATH)/ cp -r $(ASSETS_DIR) $(FOCALBOARD_PLUGIN_PATH)/ cp -r public $(FOCALBOARD_PLUGIN_PATH)/ mkdir -p $(FOCALBOARD_PLUGIN_PATH)/server cp -r server/dist $(FOCALBOARD_PLUGIN_PATH)/server/ mkdir -p $(FOCALBOARD_PLUGIN_PATH)/webapp cp -r webapp/dist $(FOCALBOARD_PLUGIN_PATH)/webapp/ ./build/bin/pluginctl enable $(PLUGIN_ID) @echo plugin built at: $(FOCALBOARD_PLUGIN_PATH) # Help documentation à la https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html help: @cat Makefile build/*.mk | grep -v '\.PHONY' | grep -v '\help:' | grep -B1 -E '^[a-zA-Z0-9_.-]+:.*' | sed -e "s/:.*//" | sed -e "s/^## //" | grep -v '\-\-' | sed '1!G;h;$$!d' | awk 'NR%2{printf "\033[36m%-30s\033[0m",$$0;next;}1' | sort