build: Add GitHub actions build for Windows

This is sort of a proof of concept, but since our current Windows
builder is down this might solve the problem. It includes a change for
easier code signing (taking the certificate in a secret/env var rather
than existing already on disk), but otherwise mirrors precisely what we
already do in the build server.
This commit is contained in:
Jakob Borg 2022-10-28 12:18:28 +02:00
parent 8228020ff0
commit abb921acbc
2 changed files with 123 additions and 1 deletions

94
.github/workflows/build-syncthing.yaml vendored Normal file
View File

@ -0,0 +1,94 @@
name: Build Syncthing
on:
pull_request:
push:
env:
GO_VERSION: "1.19.3"
GO386: softfloat
GOARM: "5"
GOMIPS: softfloat
jobs:
build-windows:
runs-on: windows-latest
name: Build and test on Windows
steps:
- name: Set git to use LF
# Without this, the checkout will happen with CRLF line endings,
# which is fine for the source code but messes up tests that depend
# on data on disk being as expected. Ideally, those tests should be
# fixed, but not today.
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
# `cache: true` gives us automatic caching of modules and build
# cache, speeding up builds. The cache key is dependent on the Go
# version and our go.sum contents.
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Build and test
run: |
go run build.go
go run build.go test
package-windows:
runs-on: windows-latest
name: Create packages for Windows
environment: signing
needs:
- build-windows
steps:
- name: Set git to use LF
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v3
# `fetch-depth: 0` because we want to check out the entire repo
# including tags and branches, not just the latest commit which
# lacks version info.
with:
fetch-depth: 0
- uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- uses: actions/cache@v3
with:
path: |
~\AppData\Local\go-build
~\go\pkg\mod
key: ${{ runner.os }}-go-${{ env.GOVERSION }}-package-${{ hashFiles('**/go.sum') }}
- name: Install dependencies
run: |
go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.4.0
- name: Create packages
run: |
go run build.go -goarch amd64 zip
go run build.go -goarch arm zip
go run build.go -goarch arm64 zip
go run build.go -goarch 386 zip
env:
CODESIGN_SIGNTOOL: ${{ secrets.CODESIGN_SIGNTOOL }}
CODESIGN_CERTIFICATE_BASE64: ${{ secrets.CODESIGN_CERTIFICATE_BASE64 }}
CODESIGN_CERTIFICATE_PASSWORD: ${{ secrets.CODESIGN_CERTIFICATE_PASSWORD }}
CODESIGN_TIMESTAMP_SERVER: ${{ secrets.CODESIGN_TIMESTAMP_SERVER }}
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages
path: syncthing-windows-*.zip

View File

@ -15,6 +15,7 @@ import (
"bytes" "bytes"
"compress/flate" "compress/flate"
"compress/gzip" "compress/gzip"
"encoding/base64"
"encoding/json" "encoding/json"
"errors" "errors"
"flag" "flag"
@ -1383,6 +1384,33 @@ func windowsCodesign(file string) {
args := []string{"sign", "/fd", algo} args := []string{"sign", "/fd", algo}
if f := os.Getenv("CODESIGN_CERTIFICATE_FILE"); f != "" { if f := os.Getenv("CODESIGN_CERTIFICATE_FILE"); f != "" {
args = append(args, "/f", f) args = append(args, "/f", f)
} else if b := os.Getenv("CODESIGN_CERTIFICATE_BASE64"); b != "" {
// Decode the PFX certificate from base64.
bs, err := base64.RawStdEncoding.DecodeString(b)
if err != nil {
log.Println("Codesign: signing failed: decoding base64:", err)
return
}
// Write it to a temporary file
f, err := os.CreateTemp("", "codesign-*.pfx")
if err != nil {
log.Println("Codesign: signing failed: creating temp file:", err)
return
}
_ = f.Chmod(0600) // best effort remove other users' access
defer os.Remove(f.Name())
if _, err := f.Write(bs); err != nil {
log.Println("Codesign: signing failed: writing temp file:", err)
return
}
if err := f.Close(); err != nil {
log.Println("Codesign: signing failed: closing temp file:", err)
return
}
// Use that when signing
args = append(args, "/f", f.Name())
} }
if p := os.Getenv("CODESIGN_CERTIFICATE_PASSWORD"); p != "" { if p := os.Getenv("CODESIGN_CERTIFICATE_PASSWORD"); p != "" {
args = append(args, "/p", p) args = append(args, "/p", p)
@ -1402,7 +1430,7 @@ func windowsCodesign(file string) {
bs, err := runError(st, args...) bs, err := runError(st, args...)
if err != nil { if err != nil {
log.Println("Codesign: signing failed:", string(bs)) log.Printf("Codesign: signing failed: %v: %s", err, string(bs))
return return
} }
log.Println("Codesign: successfully signed", file, "using", algo) log.Println("Codesign: successfully signed", file, "using", algo)