diff --git a/cmd/Desktop-Bridge/main.go b/cmd/Desktop-Bridge/main.go index 23d29f34..66b1c942 100644 --- a/cmd/Desktop-Bridge/main.go +++ b/cmd/Desktop-Bridge/main.go @@ -55,6 +55,7 @@ import ( "github.com/ProtonMail/proton-bridge/internal/smtp" "github.com/ProtonMail/proton-bridge/pkg/args" "github.com/ProtonMail/proton-bridge/pkg/config" + "github.com/ProtonMail/proton-bridge/pkg/constants" "github.com/ProtonMail/proton-bridge/pkg/listener" "github.com/ProtonMail/proton-bridge/pkg/pmapi" "github.com/ProtonMail/proton-bridge/pkg/updates" @@ -68,45 +69,29 @@ import ( // Different number will drop old files and create new ones. const cacheVersion = "c11" -// Following variables are set via ldflags during build. var ( - // Version of the build. - Version = "" //nolint[gochecknoglobals] - // Revision is current hash of the build. - Revision = "" //nolint[gochecknoglobals] - // BuildTime stamp of the build. - BuildTime = "" //nolint[gochecknoglobals] - // AppShortName to make setup - AppShortName = "bridge" //nolint[gochecknoglobals] - // DSNSentry client keys to be able to report crashes to Sentry - DSNSentry = "" //nolint[gochecknoglobals] -) - -var ( - longVersion = Version + " (" + Revision + ")" //nolint[gochecknoglobals] - buildVersion = longVersion + " " + BuildTime //nolint[gochecknoglobals] - log = logrus.WithField("pkg", "main") //nolint[gochecknoglobals] // How many crashes in a row. numberOfCrashes = 0 //nolint[gochecknoglobals] + // After how many crashes bridge gives up starting. maxAllowedCrashes = 10 //nolint[gochecknoglobals] ) func main() { - if err := raven.SetDSN(DSNSentry); err != nil { + if err := raven.SetDSN(constants.DSNSentry); err != nil { log.WithError(err).Errorln("Can not setup sentry DSN") } - raven.SetRelease(Revision) - bridge.UpdateCurrentUserAgent(Version, runtime.GOOS, "", "") + raven.SetRelease(constants.Revision) + bridge.UpdateCurrentUserAgent(constants.Version, runtime.GOOS, "", "") args.FilterProcessSerialNumberFromArgs() filterRestartNumberFromArgs() app := cli.NewApp() app.Name = "Protonmail Bridge" - app.Version = buildVersion + app.Version = constants.BuildVersion app.Flags = []cli.Flag{ cli.StringFlag{ Name: "log-level, l", @@ -135,13 +120,13 @@ func main() { // Always log the basic info about current bridge. logrus.SetLevel(logrus.InfoLevel) - log.WithField("version", Version). - WithField("revision", Revision). + log.WithField("version", constants.Version). + WithField("revision", constants.Revision). WithField("runtime", runtime.GOOS). - WithField("build", BuildTime). + WithField("build", constants.BuildTime). WithField("args", os.Args). WithField("appLong", app.Name). - WithField("appShort", AppShortName). + WithField("appShort", constants.AppShortName). Info("Run app") if err := app.Run(os.Args); err != nil { log.Error("Program exited with error: ", err) @@ -174,7 +159,7 @@ func (ph *panicHandler) HandlePanic() { // IMPORTANT: ***Read the comments before CHANGING the order *** func run(context *cli.Context) (contextError error) { // nolint[funlen] // We need to have config instance to setup a logs, panic handler, etc ... - cfg := config.New(AppShortName, Version, Revision, cacheVersion) + cfg := config.New(constants.AppShortName, constants.Version, constants.Revision, cacheVersion) // We want to know about any problem. Our PanicHandler calls sentry which is // not dependent on anything else. If that fails, it tries to create crash @@ -208,7 +193,16 @@ func run(context *cli.Context) (contextError error) { // nolint[funlen] // It's safe to get version JSON file even when other instance is running. // (thus we put it before check of presence of other Bridge instance). - updates := updates.New(AppShortName, Version, Revision, BuildTime, bridge.ReleaseNotes, bridge.ReleaseFixedBugs, cfg.GetUpdateDir()) + updates := updates.New( + constants.AppShortName, + constants.Version, + constants.Revision, + constants.BuildTime, + bridge.ReleaseNotes, + bridge.ReleaseFixedBugs, + cfg.GetUpdateDir(), + ) + if dir := context.GlobalString("version-json"); dir != "" { generateVersionFiles(updates, dir) return nil @@ -280,7 +274,7 @@ func run(context *cli.Context) (contextError error) { // nolint[funlen] // implementation depending on whether build flag pmapi_prod is used or not. cm.SetRoundTripper(cfg.GetRoundTripper(cm, eventListener)) - bridgeInstance := bridge.New(cfg, pref, panicHandler, eventListener, Version, cm, credentialsStore) + bridgeInstance := bridge.New(cfg, pref, panicHandler, eventListener, cm, credentialsStore) imapBackend := imap.NewIMAPBackend(panicHandler, eventListener, cfg, bridgeInstance) smtpBackend := smtp.NewSMTPBackend(panicHandler, eventListener, pref, bridgeInstance) @@ -326,7 +320,7 @@ func run(context *cli.Context) (contextError error) { // nolint[funlen] } showWindowOnStart := !context.GlobalBool("no-window") - frontend := frontend.New(Version, buildVersion, frontendMode, showWindowOnStart, panicHandler, cfg, pref, eventListener, updates, bridgeInstance, smtpBackend) + frontend := frontend.New(constants.Version, constants.BuildVersion, frontendMode, showWindowOnStart, panicHandler, cfg, pref, eventListener, updates, bridgeInstance, smtpBackend) // Last part is to start everything. log.Debug("Starting frontend...") @@ -346,7 +340,7 @@ func run(context *cli.Context) (contextError error) { // nolint[funlen] // It will happen only when c10/prefs.json exists and c11/prefs.json not. // No configuration changed between c10 and c11 versions. func migratePreferencesFromC10(cfg *config.Config) { - pref10Path := config.New(AppShortName, Version, Revision, "c10").GetPreferencesPath() + pref10Path := config.New(constants.AppShortName, constants.Version, constants.Revision, "c10").GetPreferencesPath() if _, err := os.Stat(pref10Path); os.IsNotExist(err) { log.WithField("path", pref10Path).Trace("Old preferences does not exist, migration skipped") return diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index 6b667b7e..ba6e8cdc 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -46,7 +46,6 @@ type Bridge struct { pref PreferenceProvider panicHandler PanicHandler events listener.Listener - version string clientManager ClientManager credStorer CredentialsStorer storeCache *store.Cache @@ -77,7 +76,6 @@ func New( pref PreferenceProvider, panicHandler PanicHandler, eventListener listener.Listener, - version string, clientManager ClientManager, credStorer CredentialsStorer, ) *Bridge { @@ -88,7 +86,6 @@ func New( pref: pref, panicHandler: panicHandler, events: eventListener, - version: version, clientManager: clientManager, credStorer: credStorer, storeCache: store.NewCache(config.GetIMAPCachePath()), @@ -122,7 +119,7 @@ func New( } if pref.GetBool(preferences.FirstStartKey) { - b.SendMetric(metrics.New(metrics.Setup, metrics.FirstStart, metrics.Label(version))) + b.SendMetric(metrics.New(metrics.Setup, metrics.FirstStart, metrics.Label(config.GetVersion()))) } return b @@ -572,7 +569,7 @@ func (b *Bridge) StopWatchers() { } func (b *Bridge) updateCurrentUserAgent() { - UpdateCurrentUserAgent(b.version, b.userAgentOS, b.userAgentClientName, b.userAgentClientVersion) + UpdateCurrentUserAgent(b.config.GetVersion(), b.userAgentOS, b.userAgentClientName, b.userAgentClientVersion) } // hasUser returns whether the bridge currently has a user with ID `id`. diff --git a/internal/bridge/bridge_test.go b/internal/bridge/bridge_test.go index 0006f522..b23700ae 100644 --- a/internal/bridge/bridge_test.go +++ b/internal/bridge/bridge_test.go @@ -244,10 +244,11 @@ func testNewBridge(t *testing.T, m mocks) *Bridge { m.prefProvider.EXPECT().GetBool(preferences.AllowProxyKey).Return(false).AnyTimes() m.config.EXPECT().GetDBDir().Return("/tmp").AnyTimes() m.config.EXPECT().GetIMAPCachePath().Return(cacheFile.Name()).AnyTimes() + m.config.EXPECT().GetVersion().Return("ver").AnyTimes() m.eventListener.EXPECT().Add(events.UpgradeApplicationEvent, gomock.Any()) m.clientManager.EXPECT().GetAuthUpdateChannel().Return(make(chan pmapi.ClientAuth)) - bridge := New(m.config, m.prefProvider, m.PanicHandler, m.eventListener, "ver", m.clientManager, m.credentialsStore) + bridge := New(m.config, m.prefProvider, m.PanicHandler, m.eventListener, m.clientManager, m.credentialsStore) waitForEvents() diff --git a/internal/bridge/mocks/mocks.go b/internal/bridge/mocks/mocks.go index 3fbf72f0..dad77b09 100644 --- a/internal/bridge/mocks/mocks.go +++ b/internal/bridge/mocks/mocks.go @@ -91,6 +91,20 @@ func (mr *MockConfigerMockRecorder) GetIMAPCachePath() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIMAPCachePath", reflect.TypeOf((*MockConfiger)(nil).GetIMAPCachePath)) } +// GetVersion mocks base method +func (m *MockConfiger) GetVersion() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetVersion") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetVersion indicates an expected call of GetVersion +func (mr *MockConfigerMockRecorder) GetVersion() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVersion", reflect.TypeOf((*MockConfiger)(nil).GetVersion)) +} + // MockPreferenceProvider is a mock of PreferenceProvider interface type MockPreferenceProvider struct { ctrl *gomock.Controller diff --git a/internal/bridge/types.go b/internal/bridge/types.go index d7da9a2b..3cbf3669 100644 --- a/internal/bridge/types.go +++ b/internal/bridge/types.go @@ -25,6 +25,7 @@ import ( type Configer interface { ClearData() error GetDBDir() string + GetVersion() string GetIMAPCachePath() string GetAPIConfig() *pmapi.ClientConfig } diff --git a/pkg/config/config.go b/pkg/config/config.go index 7b3b8613..546ffa2d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -172,6 +172,11 @@ func (c *Config) IsDevMode() bool { return os.Getenv("PROTONMAIL_ENV") == "dev" } +// GetVersion returns the version. +func (c *Config) GetVersion() string { + return c.version +} + // GetLogDir returns folder for log files. func (c *Config) GetLogDir() string { return c.appDirs.UserLogs() diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go new file mode 100644 index 00000000..38277477 --- /dev/null +++ b/pkg/constants/constants.go @@ -0,0 +1,26 @@ +// Package constants contains variables that are set via ldflags during build. +package constants + +// nolint[gochecknoglobals] +var ( + // Version of the build. + Version = "" + + // Revision is current hash of the build. + Revision = "" + + // BuildTime stamp of the build. + BuildTime = "" + + // AppShortName to make setup. + AppShortName = "bridge" + + // DSNSentry client keys to be able to report crashes to Sentry. + DSNSentry = "" + + // LongVersion is derived from Version and Revision. + LongVersion = Version + " (" + Revision + ")" + + // BuildVersion is derived from LongVersion and BuildTime. + BuildVersion = LongVersion + " " + BuildTime +) diff --git a/test/Makefile b/test/Makefile index 743e0d61..82d1e680 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,9 +1,9 @@ .PHONY: check-has-go install-godog test test-live test-debug test-live-debug export GO111MODULE=on -export VERSION:=1.2.5-integrationtest export VERBOSITY?=fatal export TEST_DATA=testdata +export VERSION:=dev-integrationtests check-has-go: @which go || (echo "Install Go-lang!" && exit 1) diff --git a/test/context/bridge.go b/test/context/bridge.go index 756eab10..fb04169e 100644 --- a/test/context/bridge.go +++ b/test/context/bridge.go @@ -18,11 +18,11 @@ package context import ( - "os" "runtime" "github.com/ProtonMail/proton-bridge/internal/bridge" "github.com/ProtonMail/proton-bridge/internal/preferences" + "github.com/ProtonMail/proton-bridge/pkg/constants" "github.com/ProtonMail/proton-bridge/pkg/listener" ) @@ -64,13 +64,12 @@ func newBridgeInstance( eventListener listener.Listener, clientManager bridge.ClientManager, ) *bridge.Bridge { - version := os.Getenv("VERSION") - bridge.UpdateCurrentUserAgent(version, runtime.GOOS, "", "") + bridge.UpdateCurrentUserAgent(constants.Version, runtime.GOOS, "", "") panicHandler := &panicHandler{t: t} pref := preferences.New(cfg) - return bridge.New(cfg, pref, panicHandler, eventListener, version, clientManager, credStore) + return bridge.New(cfg, pref, panicHandler, eventListener, clientManager, credStore) } // SetLastBridgeError sets the last error that occurred while executing a bridge action. diff --git a/test/context/config.go b/test/context/config.go index 37324b8b..77ba2c0e 100644 --- a/test/context/config.go +++ b/test/context/config.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" + "github.com/ProtonMail/gopenpgp/constants" "github.com/ProtonMail/proton-bridge/pkg/pmapi" ) @@ -48,13 +49,16 @@ func (c *fakeConfig) ClearData() error { } func (c *fakeConfig) GetAPIConfig() *pmapi.ClientConfig { return &pmapi.ClientConfig{ - AppVersion: "Bridge_" + os.Getenv("VERSION"), + AppVersion: "Bridge_" + constants.Version, ClientID: "bridge", } } func (c *fakeConfig) GetDBDir() string { return c.dir } +func (c *fakeConfig) GetVersion() string { + return constants.Version +} func (c *fakeConfig) GetLogDir() string { return c.dir } diff --git a/test/main_test.go b/test/main_test.go index d6b6545f..f91affb4 100644 --- a/test/main_test.go +++ b/test/main_test.go @@ -22,6 +22,7 @@ import ( "os" "testing" + "github.com/ProtonMail/proton-bridge/pkg/constants" "github.com/cucumber/godog" "github.com/cucumber/godog/colors" ) @@ -33,6 +34,9 @@ var opt = godog.Options{ //nolint[gochecknoglobals] func init() { //nolint[gochecknoinits] godog.BindFlags("godog.", flag.CommandLine, &opt) + + // This would normally be done using ldflags but `godog` command doesn't support that. + constants.Version = os.Getenv("VERSION") } func TestMain(m *testing.M) { @@ -46,5 +50,6 @@ func TestMain(m *testing.M) { if st := m.Run(); st > status { status = st } + os.Exit(status) }