diff --git a/Makefile b/Makefile index 2b224c5..88d12e1 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,6 @@ PROTECTED_BRANCH := master CURRENT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) # Use repository name as application name APP_NAME := $(shell basename -s .git `git config --get remote.origin.url`) -# Get current commit -APP_COMMIT := $(shell git log --pretty=format:'%h' -n 1) # Check if we are in protected branch, if yes use `protected_branch_name-sha` as app version. # Else check if we are in a release tag, if yes use the tag as app version, else use `dev-sha` as app version. APP_VERSION ?= $(shell if [ $(PROTECTED_BRANCH) = $(CURRENT_BRANCH) ]; then echo $(PROTECTED_BRANCH); else (git describe --abbrev=0 --exact-match --tags 2>/dev/null || echo dev-$(APP_COMMIT)) ; fi) @@ -23,6 +21,11 @@ endif # Get current date and format like: 2022-04-27 11:32 BUILD_DATE := $(shell date +%Y-%m-%d\ %H:%M) +# Get version information for plugins that depend on a semver version +BUILD_HASH = $(shell git rev-parse --short HEAD) +BUILD_TAG_LATEST = $(shell git describe --tags --match 'v*' --abbrev=0) +BUILD_TAG_CURRENT = $(shell git tag --points-at HEAD) + ## General Configuration Variables # We don't need make's built-in rules. MAKEFLAGS += --no-builtin-rules @@ -69,7 +72,9 @@ GO := $(shell which go) GO_VERSION ?= $(shell grep -E '^go' go.mod | awk {'print $$2'}) # LDFLAGS GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/internal/version.gitVersion=$(GIT_VERSION)" -GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/internal/version.gitCommit=$(APP_COMMIT)" +GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/internal/version.buildHash=$(BUILD_HASH)" +GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/internal/version.buildTagLatest=$(BUILD_TAG_LATEST)" +GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/internal/version.buildTagCurrent=$(BUILD_TAG_CURRENT)" GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/internal/version.gitTreeState=$(GIT_TREESTATE)" GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/internal/version.buildDate=$(BUILD_DATE)" diff --git a/internal/version/version.go b/internal/version/version.go index 5f5773d..e4b1c88 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -15,8 +15,12 @@ var ( // Output of "git describe". The prerequisite is that the branch should be // tagged using the correct versioning strategy. gitVersion string = "devel" - // SHA1 from git, output of $(git rev-parse HEAD) - gitCommit = "unknown" + // short SHA1 from git, output of $(git rev-parse --short HEAD) + buildHash = "unknown" + // the most recent v* tag in the current branch (or its ancestors) + buildTagLatest = "unknown" + // the current commit's v* tag + buildTagCurrent = "unknown" // State of git tree, either "clean" or "dirty" gitTreeState = "unknown" // Build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ') @@ -32,21 +36,39 @@ func GetVersion() error { } type Info struct { - GitVersion string - GitCommit string - GitTreeState string - BuildDate string - GoVersion string - Compiler string - Platform string + GitVersion string `json:"-"` + BuildHash string `json:"hash"` + BuildVersion string `json:"version"` + GitTreeState string `json:"-"` + BuildDate string `json:"-"` + GoVersion string `json:"-"` + Compiler string `json:"-"` + Platform string `json:"-"` } func VersionInfo() Info { // These variables typically come from -ldflags settings and in // their absence fallback to the global defaults set above. + + // Create the semver version based on the state of the current commit or its branch. + // Use the first version we find. + var version string + tags := strings.Fields(buildTagCurrent) + for _, t := range tags { + if strings.HasPrefix(t, "v") { + version = t + break + } + } + if version == "" { + version = buildTagLatest + "+" + buildHash + } + version = strings.TrimPrefix(version, "v") + return Info{ GitVersion: gitVersion, - GitCommit: gitCommit, + BuildHash: buildHash, + BuildVersion: version, GitTreeState: gitTreeState, BuildDate: buildDate, GoVersion: runtime.Version(), @@ -61,7 +83,8 @@ func (i *Info) String() string { w := tabwriter.NewWriter(&b, 0, 0, 2, ' ', 0) fmt.Fprintf(w, "GitVersion:\t%s\n", i.GitVersion) - fmt.Fprintf(w, "GitCommit:\t%s\n", i.GitCommit) + fmt.Fprintf(w, "BuildHash:\t%s\n", i.BuildHash) + fmt.Fprintf(w, "BuildVersion:\t%s\n", i.BuildVersion) fmt.Fprintf(w, "GitTreeState:\t%s\n", i.GitTreeState) fmt.Fprintf(w, "BuildDate:\t%s\n", i.BuildDate) fmt.Fprintf(w, "GoVersion:\t%s\n", i.GoVersion) diff --git a/server/android_notification_server.go b/server/android_notification_server.go index 66f7f7f..9bfc7c9 100644 --- a/server/android_notification_server.go +++ b/server/android_notification_server.go @@ -114,6 +114,7 @@ func (me *AndroidNotificationServer) SendNotification(msg *PushNotification) Pus data := map[string]string{ "ack_id": msg.AckID, "type": pushType, + "sub_type": msg.SubType, "version": msg.Version, "channel_id": msg.ChannelID, "is_crt_enabled": strconv.FormatBool(msg.IsCRTEnabled), diff --git a/server/apple_notification_server.go b/server/apple_notification_server.go index 80aa8e4..0721c24 100644 --- a/server/apple_notification_server.go +++ b/server/apple_notification_server.go @@ -168,6 +168,7 @@ func (me *AppleNotificationServer) SendNotification(msg *PushNotification) PushR me.metrics.incrementNotificationTotal(PushNotifyApple, pushType) } data.Custom("type", pushType) + data.Custom("sub_type", msg.SubType) data.Custom("server_id", msg.ServerID) if msg.AckID != "" { diff --git a/server/push_notification.go b/server/push_notification.go index 269e4b4..d2c44a5 100644 --- a/server/push_notification.go +++ b/server/push_notification.go @@ -39,6 +39,7 @@ type PushNotification struct { RootID string `json:"root_id"` ChannelName string `json:"channel_name"` Type string `json:"type"` + SubType string `json:"sub_type,omitempty"` SenderName string `json:"sender_name"` SenderID string `json:"sender_id"` OverrideUsername string `json:"override_username"` diff --git a/server/server.go b/server/server.go index 57c9f79..2e96839 100644 --- a/server/server.go +++ b/server/server.go @@ -102,6 +102,7 @@ func (s *Server) Start() { handler := th.Throttle(router) router.HandleFunc("/", root).Methods("GET") + router.HandleFunc("/version", s.version).Methods("GET") metricCompatibleSendNotificationHandler := s.handleSendNotification metricCompatibleAckNotificationHandler := s.handleAckNotification @@ -150,6 +151,18 @@ func root(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("Mattermost Push Proxy")) } +func (s *Server) version(w http.ResponseWriter, _ *http.Request) { + info := version.VersionInfo() + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(info); err != nil { + s.logger.Errorf("Failed to write response: %v", err) + if s.metrics != nil { + s.metrics.incrementBadRequest() + } + } +} + func (s *Server) responseTimeMiddleware(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { start := time.Now() diff --git a/server/server_test.go b/server/server_test.go index 7273ce7..37dd573 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -6,7 +6,10 @@ package server import ( "bytes" "encoding/json" + "github.com/mattermost/mattermost-push-proxy/internal/version" + "github.com/stretchr/testify/assert" "net/http" + "net/http/httptest" "testing" "time" @@ -111,3 +114,26 @@ func TestAndroidSend(t *testing.T) { srv.Stop() time.Sleep(time.Second * 2) } + +func TestServer_version(t *testing.T) { + fileName := FindConfigFile("mattermost-push-proxy.sample.json") + cfg, err := LoadConfig(fileName) + require.NoError(t, err) + logger := NewLogger(cfg) + srv := New(cfg, logger) + + req := httptest.NewRequest(http.MethodGet, "/version", nil) + res := httptest.NewRecorder() + srv.version(res, req) + assert.Equal(t, res.Code, http.StatusOK) + + info := version.VersionInfo() + ret := struct { + Version string + Hash string + }{} + err = json.NewDecoder(res.Body).Decode(&ret) + assert.NoError(t, err) + assert.Equal(t, info.BuildVersion, ret.Version) + assert.Equal(t, info.BuildHash, ret.Hash) +}