build-syncthing.yaml 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124
  1. name: Build Syncthing
  2. on:
  3. pull_request:
  4. push:
  5. branches-ignore:
  6. - release
  7. - release-rc*
  8. workflow_call:
  9. workflow_dispatch:
  10. env:
  11. # The go version to use for builds. We set check-latest to true when
  12. # installing, so we get the latest patch version that matches the
  13. # expression.
  14. GO_VERSION: "~1.24.0"
  15. # Optimize compatibility on the slow archictures.
  16. GOMIPS: softfloat
  17. GOARM: "6"
  18. # Avoid hilarious amounts of obscuring log output when running tests.
  19. LOGGER_DISCARD: "1"
  20. # Our build metadata
  21. BUILD_USER: builder
  22. BUILD_HOST: github.syncthing.net
  23. TAGS: "netgo osusergo sqlite_omit_load_extension sqlite_dbstat"
  24. # A note on actions and third party code... The actions under actions/ (like
  25. # `uses: actions/checkout`) are maintained by GitHub, and we need to trust
  26. # GitHub to maintain their code and infrastructure or we're in deep shit in
  27. # general. The same doesn't necessarily apply to other actions authors, so
  28. # some care needs to be taken when adding steps, especially in the paths
  29. # that lead up to code being packaged and signed.
  30. jobs:
  31. #
  32. # Source
  33. #
  34. facts:
  35. name: Gather common facts
  36. runs-on: ubuntu-latest
  37. outputs:
  38. version: ${{ steps.get-version.outputs.version }}
  39. release-kind: ${{ steps.get-version.outputs.release-kind }}
  40. go-version: ${{ steps.get-go.outputs.go-version }}
  41. steps:
  42. - uses: actions/checkout@v4
  43. with:
  44. fetch-depth: 0
  45. ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
  46. - uses: actions/setup-go@v5
  47. with:
  48. go-version: ${{ env.GO_VERSION }}
  49. cache: false
  50. check-latest: true
  51. - name: Get Syncthing version
  52. id: get-version
  53. run: |
  54. version=$(go run build.go version)
  55. echo "version=$version" >> "$GITHUB_OUTPUT"
  56. echo "Version: $version"
  57. kind=stable
  58. if [[ $version == *-rc.[0-9] || $version == *-rc.[0-9][0-9] ]] ; then
  59. kind=candidate
  60. elif [[ $version == *-* ]] ; then
  61. kind=nightly
  62. fi
  63. echo "release-kind=$kind" >> "$GITHUB_OUTPUT"
  64. echo "Release kind: $kind"
  65. - name: Get Go version
  66. id: get-go
  67. run: |
  68. go version
  69. echo "go-version=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_OUTPUT
  70. #
  71. # Tests for all platforms. Runs a matrix build on Windows, Linux and Mac,
  72. # with the list of expected supported Go versions (current, previous).
  73. #
  74. build-test:
  75. name: Build and test
  76. strategy:
  77. fail-fast: false
  78. matrix:
  79. runner: ["windows-latest", "ubuntu-latest", "macos-latest"]
  80. # The oldest version in this list should match what we have in our go.mod.
  81. # Variables don't seem to be supported here, or we could have done something nice.
  82. go: ["~1.23.0", "~1.24.0"]
  83. runs-on: ${{ matrix.runner }}
  84. steps:
  85. - name: Set git to use LF
  86. if: matrix.runner == 'windows-latest'
  87. # Without this, the Windows checkout will happen with CRLF line
  88. # endings, which is fine for the source code but messes up tests
  89. # that depend on data on disk being as expected. Ideally, those
  90. # tests should be fixed, but not today.
  91. run: |
  92. git config --global core.autocrlf false
  93. git config --global core.eol lf
  94. - uses: actions/checkout@v4
  95. - uses: actions/setup-go@v5
  96. with:
  97. go-version: ${{ matrix.go }}
  98. cache: true
  99. check-latest: true
  100. - name: Build
  101. run: |
  102. go run build.go
  103. - name: Install go-test-json-to-loki
  104. run: |
  105. go install calmh.dev/go-test-json-to-loki@latest
  106. - name: Test
  107. run: |
  108. go version
  109. go run build.go test | go-test-json-to-loki
  110. env:
  111. GOFLAGS: "-json"
  112. LOKI_URL: ${{ secrets.LOKI_URL }}
  113. LOKI_USER: ${{ secrets.LOKI_USER }}
  114. LOKI_PASSWORD: ${{ secrets.LOKI_PASSWORD }}
  115. LOKI_LABELS: "go=${{ matrix.go }},runner=${{ matrix.runner }},repo=${{ github.repository }},ref=${{ github.ref }}"
  116. CGO_ENABLED: "1"
  117. #
  118. # The basic checks job is a virtual one that depends on the matrix tests,
  119. # the correctness checks, and various builds that we always do. This makes
  120. # it easy to have the PR process have a single test as a gatekeeper for
  121. # merging, instead of having to add all the matrix tests and update them
  122. # each time the version changes. (The top level test is not available for
  123. # choosing there, only the matrix "children".)
  124. #
  125. basics:
  126. name: Basic checks passed
  127. runs-on: ubuntu-latest
  128. needs:
  129. - build-test
  130. - package-linux
  131. - package-cross
  132. - package-source
  133. - package-debian
  134. - package-windows
  135. - govulncheck
  136. - golangci
  137. - meta
  138. steps:
  139. - uses: actions/checkout@v4
  140. #
  141. # Windows
  142. #
  143. package-windows:
  144. name: Package for Windows
  145. runs-on: ubuntu-latest
  146. needs:
  147. - facts
  148. env:
  149. VERSION: ${{ needs.facts.outputs.version }}
  150. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  151. steps:
  152. - uses: actions/checkout@v4
  153. - uses: actions/setup-go@v5
  154. with:
  155. go-version: ${{ needs.facts.outputs.go-version }}
  156. cache: false
  157. - uses: mlugg/setup-zig@v2
  158. - uses: actions/cache@v4
  159. with:
  160. path: |
  161. ~/.cache/go-build
  162. ~/go/pkg/mod
  163. key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-windows-${{ hashFiles('**/go.sum') }}
  164. - name: Install dependencies
  165. run: |
  166. go install github.com/josephspurrier/goversioninfo/cmd/[email protected]
  167. - name: Create packages
  168. run: |
  169. for tgt in syncthing stdiscosrv strelaysrv ; do
  170. go run build.go -tags "${{env.TAGS}}" -goos windows -goarch amd64 -cc "zig cc -target x86_64-windows" zip $tgt
  171. go run build.go -tags "${{env.TAGS}}" -goos windows -goarch 386 -cc "zig cc -target x86-windows" zip $tgt
  172. go run build.go -tags "${{env.TAGS}}" -goos windows -goarch arm64 -cc "zig cc -target aarch64-windows" zip $tgt
  173. # go run build.go -tags "${{env.TAGS}}" -goos windows -goarch arm -cc "zig cc -target thumb-windows" zip $tgt # failes with linker errors
  174. done
  175. env:
  176. CGO_ENABLED: "1"
  177. - name: Archive artifacts
  178. uses: actions/upload-artifact@v4
  179. with:
  180. name: unsigned-packages-windows
  181. path: "*.zip"
  182. #
  183. # Codesign binaries for Windows. This job runs only when called in the
  184. # Syncthing repo for release branches and tags, as it requires our
  185. # specific code signing keys etc.
  186. #
  187. codesign-windows:
  188. name: Codesign for Windows
  189. if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v'))
  190. environment: release
  191. runs-on: windows-latest
  192. needs:
  193. - package-windows
  194. steps:
  195. - name: Download artifacts
  196. uses: actions/download-artifact@v4
  197. with:
  198. name: unsigned-packages-windows
  199. path: packages
  200. - name: Extract packages
  201. working-directory: packages
  202. run: |
  203. $files = Get-ChildItem "." -Filter *.zip
  204. foreach ($file in $files) {
  205. 7z x $file.Name
  206. }
  207. - name: Sign files with Trusted Signing
  208. uses: azure/[email protected]
  209. with:
  210. azure-tenant-id: ${{ secrets.AZURE_TRUSTED_SIGNING_TENANT_ID }}
  211. azure-client-id: ${{ secrets.AZURE_TRUSTED_SIGNING_CLIENT_ID }}
  212. azure-client-secret: ${{ secrets.AZURE_TRUSTED_SIGNING_CLIENT_SECRET }}
  213. endpoint: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }}
  214. trusted-signing-account-name: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT }}
  215. certificate-profile-name: ${{ secrets.AZURE_TRUSTED_SIGNING_PROFILE }}
  216. files-folder: ${{ github.workspace }}\packages
  217. files-folder-filter: exe
  218. files-folder-recurse: true
  219. file-digest: SHA256
  220. timestamp-rfc3161: http://timestamp.acs.microsoft.com
  221. timestamp-digest: SHA256
  222. - name: Repackage packages
  223. working-directory: packages
  224. run: |
  225. $files = Get-ChildItem "." -Filter *.zip
  226. foreach ($file in $files) {
  227. Remove-Item $file.Name
  228. 7z a -tzip $file.Name $file.BaseName
  229. }
  230. - name: Archive artifacts
  231. uses: actions/upload-artifact@v4
  232. with:
  233. name: packages-windows
  234. path: "packages/*.zip"
  235. #
  236. # Linux
  237. #
  238. package-linux:
  239. name: Package for Linux
  240. runs-on: ubuntu-latest
  241. needs:
  242. - facts
  243. env:
  244. VERSION: ${{ needs.facts.outputs.version }}
  245. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  246. steps:
  247. - uses: actions/checkout@v4
  248. - uses: actions/setup-go@v5
  249. with:
  250. go-version: ${{ needs.facts.outputs.go-version }}
  251. cache: false
  252. - uses: mlugg/setup-zig@v2
  253. - uses: actions/cache@v4
  254. with:
  255. path: |
  256. ~/.cache/go-build
  257. ~/go/pkg/mod
  258. key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-${{ hashFiles('**/go.sum') }}
  259. - name: Create packages
  260. run: |
  261. sudo apt-get install -y gcc-mips64-linux-gnuabi64 gcc-mips64el-linux-gnuabi64
  262. for tgt in syncthing stdiscosrv strelaysrv ; do
  263. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch amd64 -cc "zig cc -target x86_64-linux-musl" tar "$tgt"
  264. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch 386 -cc "zig cc -target x86-linux-musl" tar "$tgt"
  265. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch arm -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" tar "$tgt"
  266. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch arm64 -cc "zig cc -target aarch64-linux-musl" tar "$tgt"
  267. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mips -cc "zig cc -target mips-linux-musleabi" tar "$tgt"
  268. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mipsle -cc "zig cc -target mipsel-linux-musleabi" tar "$tgt"
  269. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mips64 -cc mips64-linux-gnuabi64-gcc tar "$tgt"
  270. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mips64le -cc mips64el-linux-gnuabi64-gcc tar "$tgt"
  271. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch riscv64 -cc "zig cc -target riscv64-linux-musl" tar "$tgt"
  272. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch s390x -cc "zig cc -target s390x-linux-musl" tar "$tgt"
  273. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch loong64 -cc "zig cc -target loongarch64-linux-musl" tar "$tgt"
  274. # go run build.go -tags "${{env.TAGS}}" -goos linux -goarch ppc64 -cc "zig cc -target powerpc64-linux-musl" tar "$tgt" # fails with linkmode not supported
  275. go run build.go -tags "${{env.TAGS}}" -goos linux -goarch ppc64le -cc "zig cc -target powerpc64le-linux-musl" tar "$tgt"
  276. done
  277. env:
  278. CGO_ENABLED: "1"
  279. EXTRA_LDFLAGS: "-linkmode=external -extldflags=-static"
  280. - name: Archive artifacts
  281. uses: actions/upload-artifact@v4
  282. with:
  283. name: packages-linux
  284. path: |
  285. *.tar.gz
  286. compat.json
  287. #
  288. # macOS. The entire build runs in the release environment because code
  289. # signing is part of the build process, so it is limited to release
  290. # branches on the Syncthing repo.
  291. #
  292. package-macos:
  293. name: Package for macOS
  294. if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v'))
  295. environment: release
  296. runs-on: macos-latest
  297. needs:
  298. - facts
  299. env:
  300. CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }}
  301. VERSION: ${{ needs.facts.outputs.version }}
  302. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  303. steps:
  304. - uses: actions/checkout@v4
  305. - uses: actions/setup-go@v5
  306. with:
  307. go-version: ${{ needs.facts.outputs.go-version }}
  308. cache: false
  309. - uses: actions/cache@v4
  310. with:
  311. path: |
  312. ~/.cache/go-build
  313. ~/go/pkg/mod
  314. key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-${{ hashFiles('**/go.sum') }}
  315. - name: Import signing certificate
  316. if: env.CODESIGN_IDENTITY != ''
  317. run: |
  318. # Set up a run-specific keychain, making it available for the
  319. # `codesign` tool.
  320. umask 066
  321. KEYCHAIN_PATH=$RUNNER_TEMP/codesign.keychain
  322. KEYCHAIN_PASSWORD=$(uuidgen)
  323. security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
  324. security default-keychain -s "$KEYCHAIN_PATH"
  325. security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
  326. security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
  327. # Import the certificate
  328. CERTIFICATE_PATH=$RUNNER_TEMP/codesign.p12
  329. echo "$DEVELOPER_ID_CERTIFICATE_BASE64" | base64 -d -o "$CERTIFICATE_PATH"
  330. security import "$CERTIFICATE_PATH" -k "$KEYCHAIN_PATH" -P "$DEVELOPER_ID_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign
  331. security set-key-partition-list -S apple-tool:,apple: -s -k actions "$KEYCHAIN_PATH"
  332. # Set the codesign identity for following steps
  333. echo "CODESIGN_IDENTITY=$CODESIGN_IDENTITY" >> $GITHUB_ENV
  334. env:
  335. DEVELOPER_ID_CERTIFICATE_BASE64: ${{ secrets.DEVELOPER_ID_CERTIFICATE_BASE64 }}
  336. DEVELOPER_ID_CERTIFICATE_PASSWORD: ${{ secrets.DEVELOPER_ID_CERTIFICATE_PASSWORD }}
  337. CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }}
  338. - name: Create package (amd64)
  339. run: |
  340. for tgt in syncthing stdiscosrv strelaysrv ; do
  341. go run build.go -tags "${{env.TAGS}}" -goarch amd64 zip "$tgt"
  342. done
  343. env:
  344. CGO_ENABLED: "1"
  345. - name: Create package (arm64 cross)
  346. run: |
  347. cat <<EOT > xgo.sh
  348. #!/bin/bash
  349. CGO_ENABLED=1 \
  350. CGO_CFLAGS="-target arm64-apple-macos10.15" \
  351. CGO_LDFLAGS="-target arm64-apple-macos10.15" \
  352. go "\$@"
  353. EOT
  354. chmod 755 xgo.sh
  355. for tgt in syncthing stdiscosrv strelaysrv ; do
  356. go run build.go -tags "${{env.TAGS}}" -gocmd ./xgo.sh -goarch arm64 zip "$tgt"
  357. done
  358. env:
  359. CGO_ENABLED: "1"
  360. - name: Create package (universal)
  361. run: |
  362. rm -rf _tmp
  363. mkdir _tmp
  364. pushd _tmp
  365. unzip ../syncthing-macos-amd64-*.zip
  366. unzip ../syncthing-macos-arm64-*.zip
  367. lipo -create syncthing-macos-amd64-*/syncthing syncthing-macos-arm64-*/syncthing -o syncthing
  368. amd64=(syncthing-macos-amd64-*)
  369. universal="${amd64/amd64/universal}"
  370. mv "$amd64" "$universal"
  371. mv syncthing "$universal"
  372. zip -r "../$universal.zip" "$universal"
  373. - name: Archive artifacts
  374. uses: actions/upload-artifact@v4
  375. with:
  376. name: packages-macos
  377. path: "*.zip"
  378. notarize-macos:
  379. name: Notarize for macOS
  380. if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v'))
  381. environment: release
  382. needs:
  383. - package-macos
  384. runs-on: macos-latest
  385. steps:
  386. - name: Download artifacts
  387. uses: actions/download-artifact@v4
  388. with:
  389. name: packages-macos
  390. - name: Notarize binaries
  391. run: |
  392. APPSTORECONNECT_API_KEY_PATH="$RUNNER_TEMP/apikey.p8"
  393. echo "$APPSTORECONNECT_API_KEY" | base64 -d -o "$APPSTORECONNECT_API_KEY_PATH"
  394. for file in *-macos-*.zip ; do
  395. xcrun notarytool submit \
  396. -k "$APPSTORECONNECT_API_KEY_PATH" \
  397. -d "$APPSTORECONNECT_API_KEY_ID" \
  398. -i "$APPSTORECONNECT_API_KEY_ISSUER" \
  399. $file
  400. done
  401. env:
  402. APPSTORECONNECT_API_KEY: ${{ secrets.APPSTORECONNECT_API_KEY }}
  403. APPSTORECONNECT_API_KEY_ID: ${{ secrets.APPSTORECONNECT_API_KEY_ID }}
  404. APPSTORECONNECT_API_KEY_ISSUER: ${{ secrets.APPSTORECONNECT_API_KEY_ISSUER }}
  405. #
  406. # Cross compile other unixes
  407. #
  408. package-cross:
  409. name: Package cross compiled
  410. runs-on: ubuntu-latest
  411. needs:
  412. - facts
  413. env:
  414. VERSION: ${{ needs.facts.outputs.version }}
  415. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  416. steps:
  417. - uses: actions/checkout@v4
  418. - uses: actions/setup-go@v5
  419. with:
  420. go-version: ${{ needs.facts.outputs.go-version }}
  421. cache: false
  422. - uses: actions/cache@v4
  423. with:
  424. path: |
  425. ~/.cache/go-build
  426. ~/go/pkg/mod
  427. key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-cross-${{ hashFiles('**/go.sum') }}
  428. - name: Create packages
  429. run: |
  430. platforms=$(go tool dist list \
  431. | grep -v aix/ppc64 \
  432. | grep -v android/ \
  433. | grep -v darwin/ \
  434. | grep -v ios/ \
  435. | grep -v js/ \
  436. | grep -v linux/ \
  437. | grep -v nacl/ \
  438. | grep -v plan9/ \
  439. | grep -v windows/ \
  440. | grep -v /wasm \
  441. )
  442. # Build for each platform with errors silenced, because we expect
  443. # some oddball platforms to fail. This avoids a bunch of errors in
  444. # the GitHub Actions output, instead summarizing each build
  445. # failure as a warning.
  446. for plat in $platforms; do
  447. goos="${plat%/*}"
  448. goarch="${plat#*/}"
  449. echo "::group ::$plat"
  450. for tgt in syncthing stdiscosrv strelaysrv ; do
  451. if ! go run build.go -goos "$goos" -goarch "$goarch" tar "$tgt" ; then
  452. echo "::warning ::Failed to build $tgt for $plat"
  453. fi
  454. done
  455. echo "::endgroup::"
  456. done
  457. env:
  458. CGO_ENABLED: "0"
  459. - name: Archive artifacts
  460. uses: actions/upload-artifact@v4
  461. with:
  462. name: packages-other
  463. path: "*.tar.gz"
  464. #
  465. # Source
  466. #
  467. package-source:
  468. name: Package source code
  469. runs-on: ubuntu-latest
  470. needs:
  471. - facts
  472. env:
  473. VERSION: ${{ needs.facts.outputs.version }}
  474. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  475. steps:
  476. - uses: actions/checkout@v4
  477. - uses: actions/setup-go@v5
  478. with:
  479. go-version: ${{ needs.facts.outputs.go-version }}
  480. cache: false
  481. - name: Package source
  482. run: |
  483. echo "$VERSION" > RELEASE
  484. go mod vendor
  485. go run build.go assets
  486. cd ..
  487. tar c -z -f "syncthing-source-$VERSION.tar.gz" \
  488. --exclude .git \
  489. syncthing
  490. mv "syncthing-source-$VERSION.tar.gz" syncthing
  491. - name: Archive artifacts
  492. uses: actions/upload-artifact@v4
  493. with:
  494. name: packages-source
  495. path: syncthing-source-*.tar.gz
  496. #
  497. # Sign binaries for auto upgrade, generate ASC signature files
  498. #
  499. sign-for-upgrade:
  500. name: Sign for upgrade
  501. if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v'))
  502. environment: release
  503. needs:
  504. - codesign-windows
  505. - package-linux
  506. - package-macos
  507. - package-cross
  508. - package-source
  509. - facts
  510. env:
  511. VERSION: ${{ needs.facts.outputs.version }}
  512. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  513. runs-on: ubuntu-latest
  514. steps:
  515. - uses: actions/checkout@v4
  516. - uses: actions/checkout@v4
  517. with:
  518. repository: syncthing/release-tools
  519. path: tools
  520. - name: Download artifacts
  521. uses: actions/download-artifact@v4
  522. - uses: actions/setup-go@v5
  523. with:
  524. go-version: ${{ needs.facts.outputs.go-version }}
  525. cache: false
  526. - name: Install signing tool
  527. run: |
  528. go install ./cmd/dev/stsigtool
  529. - name: Sign archives
  530. run: |
  531. export PRIVATE_KEY="$RUNNER_TEMP/privkey.pem"
  532. export PATH="$PATH:$(go env GOPATH)/bin"
  533. echo "$STSIGTOOL_PRIVATE_KEY" | base64 -d > "$PRIVATE_KEY"
  534. mkdir packages
  535. mv packages-*/* packages
  536. pushd packages
  537. "$GITHUB_WORKSPACE/tools/sign-only"
  538. rm -f "$PRIVATE_KEY"
  539. env:
  540. STSIGTOOL_PRIVATE_KEY: ${{ secrets.STSIGTOOL_PRIVATE_KEY }}
  541. - name: Create shasum files
  542. run: |
  543. pushd packages
  544. files=(*.tar.gz *.zip)
  545. sha1sum "${files[@]}" > sha1sum.txt
  546. sha256sum "${files[@]}" > sha256sum.txt
  547. popd
  548. - name: Sign shasum files
  549. uses: docker://ghcr.io/kastelo/ezapt:latest
  550. with:
  551. args:
  552. sign
  553. packages/sha1sum.txt packages/sha256sum.txt
  554. env:
  555. EZAPT_KEYRING_BASE64: ${{ secrets.APT_GPG_KEYRING_BASE64 }}
  556. - name: Sign source
  557. uses: docker://ghcr.io/kastelo/ezapt:latest
  558. with:
  559. args:
  560. sign --detach --ascii
  561. packages/syncthing-source-${{ env.VERSION }}.tar.gz
  562. env:
  563. EZAPT_KEYRING_BASE64: ${{ secrets.APT_GPG_KEYRING_BASE64 }}
  564. - name: Archive artifacts
  565. uses: actions/upload-artifact@v4
  566. with:
  567. name: packages-signed
  568. path: |
  569. packages/*.tar.gz
  570. packages/*.zip
  571. packages/*.asc
  572. packages/*.json
  573. #
  574. # Debian
  575. #
  576. package-debian:
  577. name: Package for Debian
  578. runs-on: ubuntu-latest
  579. needs:
  580. - facts
  581. env:
  582. VERSION: ${{ needs.facts.outputs.version }}
  583. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  584. steps:
  585. - uses: actions/checkout@v4
  586. - uses: actions/setup-go@v5
  587. with:
  588. go-version: ${{ needs.facts.outputs.go-version }}
  589. cache: false
  590. - uses: ruby/setup-ruby@v1
  591. with:
  592. ruby-version: '3.0'
  593. - name: Install fpm
  594. run: |
  595. gem install fpm
  596. - uses: mlugg/setup-zig@v2
  597. - uses: actions/cache@v4
  598. with:
  599. path: |
  600. ~/.cache/go-build
  601. ~/go/pkg/mod
  602. key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-debian-${{ hashFiles('**/go.sum') }}
  603. - name: Package for Debian (CGO)
  604. run: |
  605. for tgt in syncthing stdiscosrv strelaysrv ; do
  606. go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch amd64 -cc "zig cc -target x86_64-linux-musl" deb "$tgt"
  607. go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch arm -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" deb "$tgt"
  608. go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch arm64 -cc "zig cc -target aarch64-linux-musl" deb "$tgt"
  609. done
  610. env:
  611. BUILD_USER: debian
  612. CGO_ENABLED: "1"
  613. EXTRA_LDFLAGS: "-linkmode=external -extldflags=-static"
  614. - name: Archive artifacts
  615. uses: actions/upload-artifact@v4
  616. with:
  617. name: debian-packages
  618. path: "*.deb"
  619. #
  620. # Nightlies
  621. #
  622. publish-nightly:
  623. name: Publish nightly build
  624. if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && startsWith(github.ref, 'refs/heads/release-nightly')
  625. environment: release
  626. needs:
  627. - sign-for-upgrade
  628. - facts
  629. runs-on: ubuntu-latest
  630. steps:
  631. - uses: actions/checkout@v4
  632. with:
  633. repository: syncthing/release-tools
  634. path: tools
  635. - name: Download artifacts
  636. uses: actions/download-artifact@v4
  637. with:
  638. name: packages-signed
  639. path: packages
  640. - uses: actions/setup-go@v5
  641. with:
  642. go-version: ${{ needs.facts.outputs.go-version }}
  643. cache: false
  644. - name: Create release json
  645. run: |
  646. cd packages
  647. "$GITHUB_WORKSPACE/tools/generate-release-json" "$BASE_URL" > nightly.json
  648. env:
  649. BASE_URL: ${{ secrets.NIGHTLY_BASE_URL }}
  650. - name: Push artifacts
  651. uses: docker://docker.io/rclone/rclone:latest
  652. env:
  653. RCLONE_CONFIG_OBJSTORE_TYPE: s3
  654. RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
  655. RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
  656. RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
  657. RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
  658. RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
  659. RCLONE_CONFIG_OBJSTORE_ACL: public-read
  660. with:
  661. args: sync -v --no-update-modtime packages objstore:nightly
  662. #
  663. # Push release artifacts to Spaces
  664. #
  665. publish-release-files:
  666. name: Publish release files
  667. if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/tags/v'))
  668. environment: release
  669. permissions:
  670. contents: write
  671. needs:
  672. - sign-for-upgrade
  673. - package-debian
  674. - facts
  675. env:
  676. VERSION: ${{ needs.facts.outputs.version }}
  677. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  678. runs-on: ubuntu-latest
  679. steps:
  680. - uses: actions/checkout@v4
  681. - name: Download signed packages
  682. uses: actions/download-artifact@v4
  683. with:
  684. name: packages-signed
  685. path: packages
  686. - name: Download debian packages
  687. uses: actions/download-artifact@v4
  688. with:
  689. name: debian-packages
  690. path: packages
  691. - uses: actions/setup-go@v5
  692. with:
  693. go-version: ${{ needs.facts.outputs.go-version }}
  694. cache: false
  695. - name: Push to object store (${{ env.VERSION }})
  696. uses: docker://docker.io/rclone/rclone:latest
  697. env:
  698. RCLONE_CONFIG_OBJSTORE_TYPE: s3
  699. RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
  700. RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
  701. RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
  702. RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
  703. RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
  704. RCLONE_CONFIG_OBJSTORE_ACL: public-read
  705. with:
  706. args: sync -v --no-update-modtime packages objstore:release/${{ env.VERSION }}
  707. - name: Push to object store (latest)
  708. uses: docker://docker.io/rclone/rclone:latest
  709. env:
  710. RCLONE_CONFIG_OBJSTORE_TYPE: s3
  711. RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
  712. RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
  713. RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
  714. RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
  715. RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
  716. RCLONE_CONFIG_OBJSTORE_ACL: public-read
  717. with:
  718. args: sync -v --no-update-modtime objstore:release/${{ env.VERSION }} objstore:release/latest
  719. - name: Create GitHub releases and push binaries
  720. run: |
  721. maybePrerelease=""
  722. if [[ $VERSION == *-* ]]; then
  723. maybePrerelease="--prerelease"
  724. fi
  725. export GH_PROMPT_DISABLED=1
  726. if ! gh release view --json name "$VERSION" >/dev/null 2>&1 ; then
  727. gh release create "$VERSION" \
  728. $maybePrerelease \
  729. --title "$VERSION" \
  730. --notes-from-tag
  731. fi
  732. gh release upload --clobber "$VERSION" \
  733. packages/*.asc packages/*.json \
  734. packages/syncthing-*.tar.gz \
  735. packages/syncthing-*.zip \
  736. packages/syncthing_*.deb
  737. PKGS=$(pwd)/packages
  738. cd /tmp # gh will not release for repo x while inside repo y
  739. for repo in relaysrv discosrv ; do
  740. export GH_REPO="syncthing/$repo"
  741. if ! gh release view --json name "$VERSION" >/dev/null 2>&1 ; then
  742. gh release create "$VERSION" \
  743. $maybePrerelease \
  744. --title "$VERSION" \
  745. --notes "https://github.com/syncthing/syncthing/releases/tag/$VERSION"
  746. fi
  747. gh release upload --clobber "$VERSION" \
  748. $PKGS/*.asc \
  749. $PKGS/*${repo}*
  750. done
  751. env:
  752. GH_TOKEN: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
  753. #
  754. # Push Debian/APT archive
  755. #
  756. publish-apt:
  757. name: Publish APT
  758. if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v'))
  759. environment: release
  760. needs:
  761. - package-debian
  762. - facts
  763. env:
  764. VERSION: ${{ needs.facts.outputs.version }}
  765. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  766. runs-on: ubuntu-latest
  767. steps:
  768. - uses: actions/checkout@v4
  769. - name: Download packages
  770. uses: actions/download-artifact@v4
  771. with:
  772. name: debian-packages
  773. path: packages
  774. # Decide whether packages should go to stable, candidate or nightly
  775. - name: Prepare packages
  776. run: |
  777. mkdir -p packages/syncthing/$RELEASE_KIND
  778. mv packages/*.deb packages/syncthing/$RELEASE_KIND
  779. - name: Pull archive
  780. uses: docker://docker.io/rclone/rclone:latest
  781. env:
  782. RCLONE_CONFIG_OBJSTORE_TYPE: s3
  783. RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
  784. RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
  785. RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
  786. RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
  787. RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
  788. RCLONE_CONFIG_OBJSTORE_ACL: public-read
  789. with:
  790. args: sync objstore:apt/dists dists
  791. - name: Update archive
  792. uses: docker://ghcr.io/kastelo/ezapt:latest
  793. with:
  794. args:
  795. publish
  796. --add packages
  797. --dists dists
  798. env:
  799. EZAPT_KEYRING_BASE64: ${{ secrets.APT_GPG_KEYRING_BASE64 }}
  800. - name: Push archive
  801. uses: docker://docker.io/rclone/rclone:latest
  802. env:
  803. RCLONE_CONFIG_OBJSTORE_TYPE: s3
  804. RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
  805. RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
  806. RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
  807. RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
  808. RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
  809. RCLONE_CONFIG_OBJSTORE_ACL: public-read
  810. with:
  811. args: sync -v --no-update-modtime dists objstore:apt/dists
  812. #
  813. # Build and push (except for PRs) to GHCR.
  814. #
  815. docker-ghcr:
  816. name: Build and push Docker images (GHCR)
  817. runs-on: ubuntu-latest
  818. permissions:
  819. contents: read
  820. packages: write
  821. needs:
  822. - facts
  823. env:
  824. VERSION: ${{ needs.facts.outputs.version }}
  825. RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
  826. strategy:
  827. matrix:
  828. pkg:
  829. - syncthing
  830. - strelaysrv
  831. - stdiscosrv
  832. include:
  833. - pkg: syncthing
  834. dockerfile: Dockerfile
  835. image: syncthing
  836. - pkg: strelaysrv
  837. dockerfile: Dockerfile.strelaysrv
  838. image: relaysrv
  839. - pkg: stdiscosrv
  840. dockerfile: Dockerfile.stdiscosrv
  841. image: discosrv
  842. steps:
  843. - uses: actions/checkout@v4
  844. - uses: actions/setup-go@v5
  845. with:
  846. go-version: ${{ needs.facts.outputs.go-version }}
  847. cache: false
  848. - uses: mlugg/setup-zig@v2
  849. - uses: actions/cache@v4
  850. with:
  851. path: |
  852. ~/.cache/go-build
  853. ~/go/pkg/mod
  854. key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-docker-${{ matrix.pkg }}-${{ hashFiles('**/go.sum') }}
  855. - name: Build binaries (CGO)
  856. run: |
  857. # amd64
  858. go run build.go -goos linux -goarch amd64 -tags "${{env.TAGS}}" -cc "zig cc -target x86_64-linux-musl" -no-upgrade build ${{ matrix.pkg }}
  859. mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-amd64
  860. # arm64
  861. go run build.go -goos linux -goarch arm64 -tags "${{env.TAGS}}" -cc "zig cc -target aarch64-linux-musl" -no-upgrade build ${{ matrix.pkg }}
  862. mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-arm64
  863. # arm
  864. go run build.go -goos linux -goarch arm -tags "${{env.TAGS}}" -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" -no-upgrade build ${{ matrix.pkg }}
  865. mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-arm
  866. env:
  867. CGO_ENABLED: "1"
  868. BUILD_USER: docker
  869. EXTRA_LDFLAGS: "-linkmode=external -extldflags=-static"
  870. - name: Login to GHCR
  871. uses: docker/login-action@v3
  872. with:
  873. registry: ghcr.io
  874. username: ${{ github.actor }}
  875. password: ${{ secrets.GITHUB_TOKEN }}
  876. - name: Set up Docker Buildx
  877. uses: docker/setup-buildx-action@v3
  878. - name: Set version tags
  879. run: |
  880. version=${VERSION#v}
  881. repo=ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}
  882. ref="${{github.ref_name}}"
  883. ref=${ref//\//-} # slashes to dashes
  884. # List of tags for ghcr.io
  885. if [[ $version == @([0-9]|[0-9][0-9]).@([0-9]|[0-9][0-9]).@([0-9]|[0-9][0-9]) ]] ; then
  886. major=${version%.*.*}
  887. minor=${version%.*}
  888. tags=$repo:$version,$repo:$major,$repo:$minor,$repo:latest
  889. elif [[ $version == *-rc.@([0-9]|[0-9][0-9]) ]] ; then
  890. tags=$repo:$version,$repo:rc
  891. elif [[ $ref == "main" ]] ; then
  892. tags=$repo:edge
  893. else
  894. tags=$repo:$ref
  895. fi
  896. echo Pushing to $tags
  897. echo "DOCKER_TAGS=$tags" >> $GITHUB_ENV
  898. - name: Build and push Docker image
  899. uses: docker/build-push-action@v5
  900. with:
  901. context: .
  902. file: ${{ matrix.dockerfile }}
  903. platforms: linux/amd64,linux/arm64,linux/arm/7
  904. tags: ${{ env.DOCKER_TAGS }}
  905. push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
  906. labels: |
  907. org.opencontainers.image.version=${{ env.VERSION }}
  908. org.opencontainers.image.revision=${{ github.sha }}
  909. #
  910. # Sync images to Docker hub. This takes the images already pushed to GHCR
  911. # and copies them to Docker hub. Runs for releases only.
  912. #
  913. docker-hub:
  914. name: Sync images to Docker hub
  915. if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/release-nightly' || github.ref == 'refs/heads/infrastructure' || startsWith(github.ref, 'refs/tags/v'))
  916. runs-on: ubuntu-latest
  917. needs:
  918. - docker-ghcr
  919. environment: docker
  920. env:
  921. DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
  922. DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
  923. steps:
  924. - uses: actions/checkout@v4
  925. - name: Sync images
  926. uses: docker://docker.io/regclient/regsync:latest
  927. with:
  928. args:
  929. -c ./.github/regsync.yml
  930. once
  931. #
  932. # Check for known vulnerabilities in Go dependencies
  933. #
  934. govulncheck:
  935. runs-on: ubuntu-latest
  936. name: Run govulncheck
  937. needs:
  938. - facts
  939. steps:
  940. - uses: actions/checkout@v4
  941. - uses: actions/setup-go@v5
  942. with:
  943. go-version: ${{ needs.facts.outputs.go-version }}
  944. cache: false
  945. - name: run govulncheck
  946. run: |
  947. go run build.go assets
  948. go install golang.org/x/vuln/cmd/govulncheck@latest
  949. govulncheck ./...
  950. #
  951. # golangci-lint runs a suite of static analysis checks on the code
  952. #
  953. golangci:
  954. runs-on: ubuntu-latest
  955. name: Run golangci-lint
  956. steps:
  957. - uses: actions/checkout@v4
  958. - uses: actions/setup-go@v5
  959. with:
  960. go-version: 'stable'
  961. - name: ensure asset generation
  962. run: go run build.go assets
  963. - name: golangci-lint
  964. uses: golangci/golangci-lint-action@v8
  965. with:
  966. only-new-issues: true
  967. #
  968. # Meta checks for formatting, copyright, etc
  969. #
  970. meta:
  971. name: Run meta checks
  972. runs-on: ubuntu-latest
  973. steps:
  974. - uses: actions/checkout@v4
  975. - uses: actions/setup-go@v5
  976. with:
  977. go-version: 'stable'
  978. - run: |
  979. go run build.go assets
  980. go test -v ./meta