diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..dc8d74f53 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,23 @@ +version: 1 +labels: + +- label: enhancement + title: ^feat\b + +- label: bug + title: ^fix\b + +- label: documentation + title: ^docs\b + +- label: chore + title: ^chore\b + +- label: chore + title: ^refactor\b + +- label: build + title: ^build\b + +- label: dependencies + title: ^build\(deps\)\b diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 000000000..1d3cc1bc6 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,17 @@ +changelog: + exclude: + labels: + - dependencies + + categories: + - title: Fixes + labels: + - bug + + - title: Features + labels: + - enhancement + + - title: Other + labels: + - '*' diff --git a/.github/workflows/pr-metadata.yaml b/.github/workflows/pr-metadata.yaml new file mode 100644 index 000000000..1e6445f96 --- /dev/null +++ b/.github/workflows/pr-metadata.yaml @@ -0,0 +1,30 @@ +name: PR metadata + +on: + pull_request_target: + types: + - opened + - reopened + - edited + - synchronize + schedule: + - cron: "42 7 * * *" + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + + # + # Set labels on PRs, which are then used to categorise release notes + # + + labels: + name: Set labels + runs-on: ubuntu-latest + steps: + - uses: srvaroa/labeler@v1 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/build.go b/build.go index b58f03bc4..e920845a0 100644 --- a/build.go +++ b/build.go @@ -329,7 +329,7 @@ func runCommand(cmd string, target target) { writeCompatJSON() case "deb": - buildDeb(target) + buildDeb(target, tags) case "vet": metalintShort() @@ -592,7 +592,7 @@ func buildZip(target target, tags []string) { fmt.Println(filename) } -func buildDeb(target target) { +func buildDeb(target target, tags []string) { os.RemoveAll("deb") // "goarch" here is set to whatever the Debian packages expect. We correct @@ -606,7 +606,7 @@ func buildDeb(target target) { goarch = "arm" } - build(target, []string{"noupgrade"}) + build(target, append(tags, "noupgrade")) for i := range target.installationFiles { target.installationFiles[i].src = strings.Replace(target.installationFiles[i].src, "{{binary}}", target.BinaryName(), 1) diff --git a/go.mod b/go.mod index 202fab11b..5af31ba21 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.0 require ( github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 - github.com/alecthomas/kong v1.10.0 + github.com/alecthomas/kong v1.11.0 github.com/aws/aws-sdk-go v1.55.7 github.com/calmh/incontainer v1.0.0 github.com/calmh/xdr v1.2.0 @@ -30,24 +30,24 @@ require ( github.com/pierrec/lz4/v4 v4.1.22 github.com/prometheus/client_golang v1.22.0 github.com/puzpuzpuz/xsync/v3 v3.5.1 - github.com/quic-go/quic-go v0.51.0 + github.com/quic-go/quic-go v0.52.0 github.com/rabbitmq/amqp091-go v1.10.0 github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 github.com/shirou/gopsutil/v4 v4.25.4 - github.com/syncthing/notify v0.0.0-20250207082249-f0fa8f99c2bc + github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465 github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d github.com/thejerf/suture/v4 v4.0.6 github.com/urfave/cli v1.22.16 github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0 github.com/willabides/kongplete v0.4.0 go.uber.org/automaxprocs v1.6.0 - golang.org/x/crypto v0.37.0 + golang.org/x/crypto v0.38.0 golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 - golang.org/x/net v0.39.0 - golang.org/x/sys v0.32.0 - golang.org/x/text v0.24.0 + golang.org/x/net v0.40.0 + golang.org/x/sys v0.33.0 + golang.org/x/text v0.25.0 golang.org/x/time v0.11.0 - golang.org/x/tools v0.32.0 + golang.org/x/tools v0.33.0 google.golang.org/protobuf v1.36.6 modernc.org/sqlite v1.37.0 sigs.k8s.io/yaml v1.4.0 @@ -99,7 +99,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.uber.org/mock v0.5.2 // indirect golang.org/x/mod v0.24.0 // indirect - golang.org/x/sync v0.13.0 // indirect + golang.org/x/sync v0.14.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.62.1 // indirect modernc.org/mathutil v1.7.1 // indirect diff --git a/go.sum b/go.sum index 7780caf46..a10124f68 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/kong v1.10.0 h1:8K4rGDpT7Iu+jEXCIJUeKqvpwZHbsFRoebLbnzlmrpw= -github.com/alecthomas/kong v1.10.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU= +github.com/alecthomas/kong v1.11.0 h1:y++1gI7jf8O7G7l4LZo5ASFhrhJvzc+WgF/arranEmM= +github.com/alecthomas/kong v1.11.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= @@ -223,8 +223,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= -github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc= -github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ= +github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA= +github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ= github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= @@ -255,8 +255,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/syncthing/notify v0.0.0-20250207082249-f0fa8f99c2bc h1:xc3UfSFlH/X5hRw3h21RF6WXnRUYKmGRx06FEaVxfkM= -github.com/syncthing/notify v0.0.0-20250207082249-f0fa8f99c2bc/go.mod h1:J0q59IWjLtpRIJulohwqEZvjzwOfTEPp8SVhDJl+y0Y= +github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465 h1:yhxdTGmFkAM2TFA65c3NgGwpnIkUM8oVqPX2e9S7IVg= +github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465/go.mod h1:J0q59IWjLtpRIJulohwqEZvjzwOfTEPp8SVhDJl+y0Y= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/thejerf/suture/v4 v4.0.6 h1:QsuCEsCqb03xF9tPAsWAj8QOAJBgQI1c0VqJNaingg8= @@ -284,8 +284,8 @@ go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -299,13 +299,13 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -328,23 +328,23 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/lib/model/model.go b/lib/model/model.go index 1d43bddd1..545558fc9 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -2357,8 +2357,14 @@ func (m *model) scheduleConnectionPromotion() { // be called after adding new connections, and after closing a primary // device connection. func (m *model) promoteConnections() { + // Slice of actions to take on connections after releasing the main + // mutex. We do this so that we do not perform blocking network actions + // inside the loop, and also to avoid a possible deadlock with calling + // Start() on connections that are already executing a Close() with a + // callback into the model... + var postLockActions []func() + m.mut.Lock() - defer m.mut.Unlock() for deviceID, connIDs := range m.deviceConnIDs { cm, passwords := m.generateClusterConfigRLocked(deviceID) @@ -2371,11 +2377,13 @@ func (m *model) promoteConnections() { // on where we get ClusterConfigs from the peer.) conn := m.connections[connIDs[0]] l.Debugf("Promoting connection to %s at %s", deviceID.Short(), conn) - if conn.Statistics().StartedAt.IsZero() { - conn.SetFolderPasswords(passwords) - conn.Start() - } - conn.ClusterConfig(cm) + postLockActions = append(postLockActions, func() { + if conn.Statistics().StartedAt.IsZero() { + conn.SetFolderPasswords(passwords) + conn.Start() + } + conn.ClusterConfig(cm) + }) m.promotedConnID[deviceID] = connIDs[0] } @@ -2384,12 +2392,20 @@ func (m *model) promoteConnections() { for _, connID := range connIDs[1:] { conn := m.connections[connID] if conn.Statistics().StartedAt.IsZero() { - conn.SetFolderPasswords(passwords) - conn.Start() - conn.ClusterConfig(&protocol.ClusterConfig{Secondary: true}) + postLockActions = append(postLockActions, func() { + conn.SetFolderPasswords(passwords) + conn.Start() + conn.ClusterConfig(&protocol.ClusterConfig{Secondary: true}) + }) } } } + + m.mut.Unlock() + + for _, action := range postLockActions { + action() + } } func (m *model) DownloadProgress(conn protocol.Connection, p *protocol.DownloadProgress) error { diff --git a/lib/protocol/protocol.go b/lib/protocol/protocol.go index 5a0390172..8b1ade2f5 100644 --- a/lib/protocol/protocol.go +++ b/lib/protocol/protocol.go @@ -269,6 +269,15 @@ func newRawConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, clo func (c *rawConnection) Start() { c.startStopMut.Lock() defer c.startStopMut.Unlock() + + select { + case <-c.closed: + // we have already closed the connection before starting processing + // on it. + return + default: + } + c.loopWG.Add(5) go func() { c.readerLoop() @@ -291,6 +300,7 @@ func (c *rawConnection) Start() { c.pingReceiver() c.loopWG.Done() }() + c.startTime = time.Now().Truncate(time.Second) close(c.started) } @@ -947,9 +957,9 @@ func (c *rawConnection) Close(err error) { // internalClose is called if there is an unexpected error during normal operation. func (c *rawConnection) internalClose(err error) { - c.startStopMut.Lock() - defer c.startStopMut.Unlock() c.closeOnce.Do(func() { + c.startStopMut.Lock() + l.Debugf("close connection to %s at %s due to %v", c.deviceID.Short(), c.ConnectionInfo, err) if cerr := c.closer.Close(); cerr != nil { l.Debugf("failed to close underlying conn %s at %s %v:", c.deviceID.Short(), c.ConnectionInfo, cerr) @@ -971,6 +981,10 @@ func (c *rawConnection) internalClose(err error) { <-c.dispatcherLoopStopped } + c.startStopMut.Unlock() + + // We don't want to call into the model while holding the + // startStopMut. c.model.Closed(err) }) } diff --git a/relnotes/v1.md b/relnotes/v1.md new file mode 100644 index 000000000..0345719a0 --- /dev/null +++ b/relnotes/v1.md @@ -0,0 +1,8 @@ +## Syncthing 2 is coming + +Syncthing version 1.x will soon be replaced by Syncthing version 2.x. +Version 2 brings a new database format and various cleanups, but remains +protocol compatible with Syncthing 1. + +More detailed information about Syncthing 2 can be found in the release +notes at https://github.com/syncthing/syncthing/releases. diff --git a/script/relnotes.go b/script/relnotes.go index b88c2f7fc..3296e6dab 100644 --- a/script/relnotes.go +++ b/script/relnotes.go @@ -20,6 +20,7 @@ import ( "log" "net/http" "os" + "regexp" "strings" ) @@ -114,5 +115,9 @@ func generatedNotes(newVer, targetCommit, prevVer string) (string, error) { if err := json.NewDecoder(res.Body).Decode(&resJSON); err != nil { return "", err } - return strings.TrimSpace(resJSON.Body), nil + return strings.TrimSpace(removeHTMLComments(resJSON.Body)), nil +} + +func removeHTMLComments(s string) string { + return regexp.MustCompile(``).ReplaceAllString(s, "") }