cmd/syncthing: Implement "release candidate" logic

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3943
LGTM: AudriusButkevicius
This commit is contained in:
Jakob Borg 2017-01-30 21:33:07 +00:00
parent 35e87e23fd
commit 1c9361a818
3 changed files with 56 additions and 25 deletions

View File

@ -1038,7 +1038,7 @@ func (s *apiService) getEvents(w http.ResponseWriter, r *http.Request, eventSub
} }
func (s *apiService) getSystemUpgrade(w http.ResponseWriter, r *http.Request) { func (s *apiService) getSystemUpgrade(w http.ResponseWriter, r *http.Request) {
if noUpgrade { if noUpgradeFromEnv {
http.Error(w, upgrade.ErrUpgradeUnsupported.Error(), 500) http.Error(w, upgrade.ErrUpgradeUnsupported.Error(), 500)
return return
} }

View File

@ -60,6 +60,7 @@ var (
BuildHost = "unknown" BuildHost = "unknown"
BuildUser = "unknown" BuildUser = "unknown"
IsRelease bool IsRelease bool
IsCandidate bool
IsBeta bool IsBeta bool
LongVersion string LongVersion string
allowedVersionExp = regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z0-9]+)*(\.\d+)*(\+\d+-g[0-9a-f]+)?(-[^\s]+)?$`) allowedVersionExp = regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z0-9]+)*(\.\d+)*(\+\d+-g[0-9a-f]+)?(-[^\s]+)?$`)
@ -99,14 +100,23 @@ func init() {
} }
} }
// Check for a clean release build. A release is something like "v0.1.2", // Check for a clean release build. A release is something like
// with an optional suffix of letters and dot separated numbers like // "v0.1.2", with an optional suffix of letters and dot separated
// "-beta3.47". If there's more stuff, like a plus sign and a commit hash // numbers like "-beta3.47". If there's more stuff, like a plus sign and
// and so on, then it's not a release. If there's a dash anywhere in // a commit hash and so on, then it's not a release. If it has a dash in
// there, it's some kind of beta or prerelease version. // it, it's some sort of beta, release candidate or special build. If it
// has "-rc." in it, like "v0.14.35-rc.42", then it's a candidate build.
//
// So, every build that is not a stable release build has IsBeta = true.
// This is used to enable some extra debugging (the deadlock detector).
//
// Release candidate builds are also "betas" from this point of view and
// will have that debugging enabled. In addition, some features are
// forced for release candidates - auto upgrade, and usage reporting.
exp := regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z]+[\d\.]+)?$`) exp := regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z]+[\d\.]+)?$`)
IsRelease = exp.MatchString(Version) IsRelease = exp.MatchString(Version)
IsCandidate = strings.Contains(Version, "-rc.")
IsBeta = strings.Contains(Version, "-") IsBeta = strings.Contains(Version, "-")
stamp, _ := strconv.Atoi(BuildStamp) stamp, _ := strconv.Atoi(BuildStamp)
@ -207,7 +217,7 @@ The following are valid values for the STTRACE variable:
// Environment options // Environment options
var ( var (
noUpgrade = os.Getenv("STNOUPGRADE") != "" noUpgradeFromEnv = os.Getenv("STNOUPGRADE") != ""
innerProcess = os.Getenv("STNORESTART") != "" || os.Getenv("STMONITORED") != "" innerProcess = os.Getenv("STNORESTART") != "" || os.Getenv("STMONITORED") != ""
noDefaultFolder = os.Getenv("STNODEFAULTFOLDER") != "" noDefaultFolder = os.Getenv("STNODEFAULTFOLDER") != ""
) )
@ -812,21 +822,27 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
} }
} }
// Candidate builds always run with usage reporting.
if IsCandidate {
l.Infoln("Anonymous usage reporting is always enabled for candidate releases.")
opts.URAccepted = usageReportVersion
// Unique ID will be set and config saved below if necessary.
}
if opts.URAccepted > 0 && opts.URAccepted < usageReportVersion { if opts.URAccepted > 0 && opts.URAccepted < usageReportVersion {
l.Infoln("Anonymous usage report has changed; revoking acceptance") l.Infoln("Anonymous usage report has changed; revoking acceptance")
opts.URAccepted = 0 opts.URAccepted = 0
opts.URUniqueID = "" opts.URUniqueID = ""
cfg.SetOptions(opts) cfg.SetOptions(opts)
} }
if opts.URAccepted >= usageReportVersion {
if opts.URUniqueID == "" { if opts.URAccepted >= usageReportVersion && opts.URUniqueID == "" {
// Previously the ID was generated from the node ID. We now need // Generate and save a new unique ID if it is missing.
// to generate a new one.
opts.URUniqueID = rand.String(8) opts.URUniqueID = rand.String(8)
cfg.SetOptions(opts) cfg.SetOptions(opts)
cfg.Save() cfg.Save()
} }
}
// The usageReportingManager registers itself to listen to configuration // The usageReportingManager registers itself to listen to configuration
// changes, and there's nothing more we need to tell it from the outside. // changes, and there's nothing more we need to tell it from the outside.
@ -837,8 +853,21 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
go standbyMonitor() go standbyMonitor()
} }
// Candidate builds should auto upgrade. Make sure the option is set,
// unless we are in a build where it's disabled or the STNOUPGRADE
// environment variable is set.
if IsCandidate && !upgrade.DisabledByCompilation && !noUpgradeFromEnv {
l.Infoln("Automatic upgrade is always enabled for candidate releases.")
if opts.AutoUpgradeIntervalH == 0 || opts.AutoUpgradeIntervalH > 24 {
opts.AutoUpgradeIntervalH = 12
}
// We don't tweak the user's choice of upgrading to pre-releases or
// not, as otherwise they cannot step off the candidate channel.
}
if opts.AutoUpgradeIntervalH > 0 { if opts.AutoUpgradeIntervalH > 0 {
if noUpgrade { if noUpgradeFromEnv {
l.Infof("No automatic upgrades; STNOUPGRADE environment variable defined.") l.Infof("No automatic upgrades; STNOUPGRADE environment variable defined.")
} else { } else {
go autoUpgrade(cfg) go autoUpgrade(cfg)

View File

@ -81,9 +81,10 @@ func (m *usageReportingManager) String() string {
// reportData returns the data to be sent in a usage report. It's used in // reportData returns the data to be sent in a usage report. It's used in
// various places, so not part of the usageReportingManager object. // various places, so not part of the usageReportingManager object.
func reportData(cfg configIntf, m modelIntf) map[string]interface{} { func reportData(cfg configIntf, m modelIntf) map[string]interface{} {
opts := cfg.Options()
res := make(map[string]interface{}) res := make(map[string]interface{})
res["urVersion"] = usageReportVersion res["urVersion"] = usageReportVersion
res["uniqueID"] = cfg.Options().URUniqueID res["uniqueID"] = opts.URUniqueID
res["version"] = Version res["version"] = Version
res["longVersion"] = LongVersion res["longVersion"] = LongVersion
res["platform"] = runtime.GOOS + "-" + runtime.GOARCH res["platform"] = runtime.GOOS + "-" + runtime.GOARCH
@ -188,7 +189,7 @@ func reportData(cfg configIntf, m modelIntf) map[string]interface{} {
res["deviceUses"] = deviceUses res["deviceUses"] = deviceUses
defaultAnnounceServersDNS, defaultAnnounceServersIP, otherAnnounceServers := 0, 0, 0 defaultAnnounceServersDNS, defaultAnnounceServersIP, otherAnnounceServers := 0, 0, 0
for _, addr := range cfg.Options().GlobalAnnServers { for _, addr := range opts.GlobalAnnServers {
if addr == "default" || addr == "default-v4" || addr == "default-v6" { if addr == "default" || addr == "default-v4" || addr == "default-v6" {
defaultAnnounceServersDNS++ defaultAnnounceServersDNS++
} else { } else {
@ -196,8 +197,8 @@ func reportData(cfg configIntf, m modelIntf) map[string]interface{} {
} }
} }
res["announce"] = map[string]interface{}{ res["announce"] = map[string]interface{}{
"globalEnabled": cfg.Options().GlobalAnnEnabled, "globalEnabled": opts.GlobalAnnEnabled,
"localEnabled": cfg.Options().LocalAnnEnabled, "localEnabled": opts.LocalAnnEnabled,
"defaultServersDNS": defaultAnnounceServersDNS, "defaultServersDNS": defaultAnnounceServersDNS,
"defaultServersIP": defaultAnnounceServersIP, "defaultServersIP": defaultAnnounceServersIP,
"otherServers": otherAnnounceServers, "otherServers": otherAnnounceServers,
@ -218,10 +219,11 @@ func reportData(cfg configIntf, m modelIntf) map[string]interface{} {
"otherServers": otherRelayServers, "otherServers": otherRelayServers,
} }
res["usesRateLimit"] = cfg.Options().MaxRecvKbps > 0 || cfg.Options().MaxSendKbps > 0 res["usesRateLimit"] = opts.MaxRecvKbps > 0 || opts.MaxSendKbps > 0
res["upgradeAllowedManual"] = !(upgrade.DisabledByCompilation || noUpgrade) res["upgradeAllowedManual"] = !(upgrade.DisabledByCompilation || noUpgradeFromEnv)
res["upgradeAllowedAuto"] = !(upgrade.DisabledByCompilation || noUpgrade) && cfg.Options().AutoUpgradeIntervalH > 0 res["upgradeAllowedAuto"] = !(upgrade.DisabledByCompilation || noUpgradeFromEnv) && opts.AutoUpgradeIntervalH > 0
res["upgradeAllowedPre"] = !(upgrade.DisabledByCompilation || noUpgradeFromEnv) && opts.AutoUpgradeIntervalH > 0 && opts.UpgradeToPreReleases
return res return res
} }