Repository: syncthing/syncthing (language: go)

Issue:
Inconsistent version requirements in lib/build and lib/upgrade
### Does your log mention database corruption?

No

### Include required information

- `syncthing v1.27.0@6069cf3`

### Preamble

[semver](https://semver.org/) lists following versions as correct:
```
<valid semver> ::= <version core>
                 | <version core> "-" <pre-release>
                 | <version core> "+" <build>
                 | <version core> "-" <pre-release> "+" <build>
```

So, `v1.27.0`, `v1.27.0-abc.1`, `v1.27.0-abc.1+xyz`, `v1.27.0+xyz` **all** are valid semver strings.

### lib/build

`lib/build` contains `allowedVersionExp`:
```go
allowedVersionExp = regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z0-9]+)*(\.\d+)*(\+\d+-g[0-9a-f]+)?(-[^\s]+)?$`)
```

It allows `v1.27.0-abc.1+xyz` but not `v1.27.0+xyz`, thus if you built an app with that version (which is permitted by `build.go`) it won't start

### lib/upgrade

`lib/upgrade` uses `CompareVersions` to check for upgrade and `TestCompareVersions` uses `1.0.0+45` as test case

`versionParts` (that is used inside) correctly parses both  `v1.27.0-abc.1+xyz` and `v1.27.0+xyz` yielding `[1, 27, 0] [abc, 1]` and `[1, 27, 0]` respectively.

### Solution

1. I suggest making versions in form of `<version core> "+" <build>` valid in `lib/build` because the both valid semver and already accepted by `lib/upgrade` and `build.go`
2. Check `version` argument in `build.go` to avoid building binaries that can't be launched anyway
Inconsistent version requirements in lib/build and lib/upgrade
### Does your log mention database corruption?

No

### Include required information

- `syncthing v1.27.0@6069cf3`

### Preamble

[semver](https://semver.org/) lists following versions as correct:
```
<valid semver> ::= <version core>
                 | <version core> "-" <pre-release>
                 | <version core> "+" <build>
                 | <version core> "-" <pre-release> "+" <build>
```

So, `v1.27.0`, `v1.27.0-abc.1`, `v1.27.0-abc.1+xyz`, `v1.27.0+xyz` **all** are valid semver strings.

### lib/build

`lib/build` contains `allowedVersionExp`:
```go
allowedVersionExp = regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z0-9]+)*(\.\d+)*(\+\d+-g[0-9a-f]+)?(-[^\s]+)?$`)
```

It allows `v1.27.0-abc.1+xyz` but not `v1.27.0+xyz`, thus if you built an app with that version (which is permitted by `build.go`) it won't start

### lib/upgrade

`lib/upgrade` uses `CompareVersions` to check for upgrade and `TestCompareVersions` uses `1.0.0+45` as test case

`versionParts` (that is used inside) correctly parses both  `v1.27.0-abc.1+xyz` and `v1.27.0+xyz` yielding `[1, 27, 0] [abc, 1]` and `[1, 27, 0]` respectively.

### Solution

1. I suggest making versions in form of `<version core> "+" <build>` valid in `lib/build` because the both valid semver and already accepted by `lib/upgrade` and `build.go`
2. Check `version` argument in `build.go` to avoid building binaries that can't be launched anyway


Discussion / hints:
Wo don't generate version numbers with pluses in them as far as I know?
I generate syncthing builds with specific configurations.  
To differentiate them from vanilla builds right now I use e.g. `vX.Y.Z-noupgrade` which is technically incorrect semver because `noupgrade` is not a part of the version but rather "build meta information".

Difference is that meta is not included in version checks and pre-release part is.
Wo don't generate version numbers with pluses in them as far as I know?
I generate syncthing builds with specific configurations.  
To differentiate them from vanilla builds right now I use e.g. `vX.Y.Z-noupgrade` which is technically incorrect semver because `noupgrade` is not a part of the version but rather "build meta information".

Difference is that meta is not included in version checks and pre-release part is.

Fix patch:
diff --git a/lib/build/build.go b/lib/build/build.go
index 549b49da652..4a02356ce6a 100644
--- a/lib/build/build.go
+++ b/lib/build/build.go
@@ -36,7 +36,7 @@ var (
 	LongVersion string
 	Extra       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]+|\+[0-9a-z]+)?(-[^\s]+)?$`)
 
 	envTags = []string{
 		"STGUIASSETS",


Test patch:
diff --git a/lib/build/build_test.go b/lib/build/build_test.go
index e2918c018cc..1bdc478ff89 100644
--- a/lib/build/build_test.go
+++ b/lib/build/build_test.go
@@ -27,6 +27,11 @@ func TestAllowedVersions(t *testing.T) {
 		{"v0.13.0-some-weird-but-allowed-tag", true},
 		{"v0.13.0-allowed.to.do.this", true},
 		{"v0.13.0+not.allowed.to.do.this", false},
+		{"v1.27.0+xyz", true},
+		{"v1.27.0-abc.1+xyz", true},
+		{"v1.0.0+45", true},
+		{"v1.0.0-noupgrade", true},
+		{"v1.0.0+noupgrade", true},
 	}
 
 	for i, c := range testcases {