chore: Windows build split

This commit is contained in:
jamesread 2026-07-21 15:55:56 +01:00
parent 38700aed95
commit 33f489dfb0
4 changed files with 57 additions and 29 deletions

View File

@ -207,7 +207,7 @@ jobs:
fi fi
done done
if [[ "${missing}" -ne 0 ]]; then if [[ "${missing}" -ne 0 ]]; then
echo "Windows signing is required before a draft release can be published. Configure SignPath secrets/vars (see docs/modules/dev/pages/signing.adoc)." >&2 echo "SignPath secrets/vars are required to upload signed Windows assets. Configure them (see docs/modules/dev/pages/signing.adoc)." >&2
exit 1 exit 1
fi fi
@ -238,7 +238,7 @@ jobs:
skip-decompress: true skip-decompress: true
output-artifact-directory: signed-windows-msi output-artifact-directory: signed-windows-msi
- name: Publish signed Windows assets and undraft release - name: Upload signed Windows assets
env: env:
GH_TOKEN: ${{ secrets.CONTAINER_TOKEN }} GH_TOKEN: ${{ secrets.CONTAINER_TOKEN }}
GITHUB_TOKEN: ${{ secrets.CONTAINER_TOKEN }} GITHUB_TOKEN: ${{ secrets.CONTAINER_TOKEN }}

View File

@ -6,6 +6,7 @@ before:
- make windows-resources VERSION={{ .Version }} - make windows-resources VERSION={{ .Version }}
builds: builds:
# id defaults to project_name (OliveTin) — required for notarize.macos defaults.
- skip: '{{ isEnvSet "GORELEASER_SKIP_BUILD" }}' - skip: '{{ isEnvSet "GORELEASER_SKIP_BUILD" }}'
env: env:
- CGO_ENABLED=0 - CGO_ENABLED=0
@ -14,7 +15,6 @@ builds:
dir: service dir: service
goos: goos:
- linux - linux
- windows
- darwin - darwin
- freebsd - freebsd
@ -33,19 +33,31 @@ builds:
- goos: darwin - goos: darwin
goarch: arm # Mac does not work on [32bit] arm goarch: arm # Mac does not work on [32bit] arm
- goos: windows ldflags:
goarch: arm - -s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{ .CommitDate }}
- goos: windows # Does anyone use Windows on arm64?
goarch: arm64
# Built and archived for SignPath, but excluded from the GitHub release upload.
- id: windows
skip: '{{ isEnvSet "GORELEASER_SKIP_BUILD" }}'
env:
- CGO_ENABLED=0
binary: OliveTin
main: .
dir: service
goos:
- windows
goarch:
- amd64
ldflags: ldflags:
- -s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{ .CommitDate }} - -s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{ .CommitDate }}
checksum: checksum:
name_template: 'checksums.txt' name_template: 'checksums.txt'
extra_files: # Exclude the windows archive; signed zip/MSI checksums are added after SignPath.
- glob: ./dist/OliveTin-windows-amd64.msi ids:
- default
- openrc
snapshot: snapshot:
version_template: "{{ .Branch }}-{{ .ShortCommit }}" version_template: "{{ .Branch }}-{{ .ShortCommit }}"
changelog: changelog:
@ -73,7 +85,10 @@ changelog:
- '^Merge branch' - '^Merge branch'
archives: archives:
- formats: tar.gz - id: default
ids:
- OliveTin
formats: tar.gz
files: files:
- config.yaml - config.yaml
- LICENSE - LICENSE
@ -85,9 +100,22 @@ archives:
- var - var
name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ .Arm }}" name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ .Arm }}"
wrap_in_directory: true wrap_in_directory: true
format_overrides:
- goos: windows - id: windows
ids:
- windows
formats: zip formats: zip
files:
- config.yaml
- LICENSE
- README.md
- src: Dockerfile.singlearch
dst: Dockerfile
- examples/backupScript.sh
- webui
- var
name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ .Arm }}"
wrap_in_directory: true
# dockers_v2: single multi-platform build with buildx; keeps default provenance + SBOM. # dockers_v2: single multi-platform build with buildx; keeps default provenance + SBOM.
# Replaces legacy dockers + docker_manifests (avoids "is a manifest list" when attestations are on). # Replaces legacy dockers + docker_manifests (avoids "is a manifest list" when attestations are on).
@ -199,10 +227,11 @@ notarize:
timeout: 30m timeout: 30m
release: release:
# Stay draft until the sign-windows job replaces unsigned Windows assets and undrafts. # Publish immediately without Windows assets; sign-windows uploads signed zip/MSI later.
draft: true draft: false
extra_files: ids:
- glob: ./dist/OliveTin-windows-amd64.msi - default
- openrc
footer: | footer: |
## Container images (from GitHub) ## Container images (from GitHub)

View File

@ -3,7 +3,7 @@
OliveTin signs release binaries on two platforms: OliveTin signs release binaries on two platforms:
* **macOS** — Developer ID + notarization via [quill](https://github.com/anchore/quill) inside GoReleaser (optional only when `MACOS_SIGN_P12` is unset). * **macOS** — Developer ID + notarization via [quill](https://github.com/anchore/quill) inside GoReleaser (optional only when `MACOS_SIGN_P12` is unset).
* **Windows** — Authenticode via [SignPath Foundation](https://signpath.org/) in a separate GitHub Actions job (required before a draft release is published). * **Windows** — Authenticode via [SignPath Foundation](https://signpath.org/) in a separate GitHub Actions job (signed zip/MSI are uploaded after the release is published).
## macOS release signing ## macOS release signing
@ -117,14 +117,14 @@ A signed and notarized binary should report `accepted` with `source=Notarized De
Windows Authenticode signing uses [SignPath Foundation](https://signpath.org/) (free for qualifying open-source projects). It does **not** use GoReleaser Pro. Windows Authenticode signing uses [SignPath Foundation](https://signpath.org/) (free for qualifying open-source projects). It does **not** use GoReleaser Pro.
GoReleaser creates a **draft** GitHub release with unsigned Windows assets. A separate `sign-windows` job submits those assets to SignPath, replaces them on the draft (including updated `checksums.txt`), then publishes the release. GoReleaser publishes a GitHub release **without** Windows zip/MSI assets. A separate `sign-windows` job submits the unsigned Windows files (as workflow artifacts) to SignPath, then uploads the signed zip/MSI and updates `checksums.txt` on the already-published release.
Signed artifacts: Signed artifacts:
* `OliveTin.exe` inside `OliveTin-windows-amd64.zip` * `OliveTin.exe` inside `OliveTin-windows-amd64.zip`
* nested `OliveTin.exe` and the `OliveTin-windows-amd64.msi` installer (deep signing) * nested `OliveTin.exe` and the `OliveTin-windows-amd64.msi` installer (deep signing)
Signing is **required** to publish. If SignPath secrets/vars are missing, `sign-windows` fails and the draft stays unpublished. If SignPath secrets/vars are missing or signing fails, the release still publishes; Windows assets are simply missing until a successful `sign-windows` run. Install URLs for the Windows zip may 404 until signing finishes.
### Prerequisites ### Prerequisites
@ -168,9 +168,9 @@ In **Settings → Secrets and variables → Actions**:
On a new semantic-release from `main`: On a new semantic-release from `main`:
1. GoReleaser publishes container images and creates a **draft** GitHub release (including unsigned Windows zip/MSI). 1. GoReleaser publishes container images and a GitHub release **without** Windows zip/MSI assets (those are built locally for SignPath only).
2. The build job uploads those Windows files as GitHub Actions artifacts. 2. The build job uploads the unsigned Windows files as GitHub Actions artifacts.
3. The `sign-windows` job submits each artifact to SignPath, waits for completion, then runs `var/windows/signpath-publish-signed.sh` to clobber-upload signed files, refresh `checksums.txt`, and undraft the release. 3. The `sign-windows` job submits each artifact to SignPath, waits for completion, then runs `var/windows/signpath-publish-signed.sh` to upload the signed files and refresh `checksums.txt`.
All jobs in this chain use GitHub-hosted runners (required by SignPath for OSS projects). All jobs in this chain use GitHub-hosted runners (required by SignPath for OSS projects).
@ -188,7 +188,7 @@ signtool verify /pa OliveTin-windows-amd64.msi
### Configuration reference ### Configuration reference
- Draft release: `release.draft: true` in link:https://github.com/OliveTin/OliveTin/blob/main/.goreleaser.yml[`.goreleaser.yml`] - Release publish (no Windows assets initially): `release.draft: false` and `release.ids` in link:https://github.com/OliveTin/OliveTin/blob/main/.goreleaser.yml[`.goreleaser.yml`]
- CI job: `sign-windows` in link:https://github.com/OliveTin/OliveTin/blob/main/.github/workflows/build-and-release.yml[`.github/workflows/build-and-release.yml`] - CI job: `sign-windows` in link:https://github.com/OliveTin/OliveTin/blob/main/.github/workflows/build-and-release.yml[`.github/workflows/build-and-release.yml`]
- Publish helper: link:https://github.com/OliveTin/OliveTin/blob/main/var/windows/signpath-publish-signed.sh[`var/windows/signpath-publish-signed.sh`] - Publish helper: link:https://github.com/OliveTin/OliveTin/blob/main/var/windows/signpath-publish-signed.sh[`var/windows/signpath-publish-signed.sh`]
- SignPath artifact configs (reference only): link:https://github.com/OliveTin/OliveTin/blob/main/docs/modules/dev/signpath/windows-zip.xml[`signpath/windows-zip.xml`], link:https://github.com/OliveTin/OliveTin/blob/main/docs/modules/dev/signpath/windows-msi.xml[`signpath/windows-msi.xml`] - SignPath artifact configs (reference only): link:https://github.com/OliveTin/OliveTin/blob/main/docs/modules/dev/signpath/windows-zip.xml[`signpath/windows-zip.xml`], link:https://github.com/OliveTin/OliveTin/blob/main/docs/modules/dev/signpath/windows-msi.xml[`signpath/windows-msi.xml`]

View File

@ -72,7 +72,8 @@ update_checksum() {
update_checksum "${ZIP_NAME}" update_checksum "${ZIP_NAME}"
update_checksum "${MSI_NAME}" update_checksum "${MSI_NAME}"
# Replace binaries first so a failed checksums upload leaves the draft recoverable. # Upload binaries first so a failed checksums upload can restore the previous file.
# --clobber overwrites same-named assets (needed if the sign job is re-run).
gh release upload "${TAG}" \ gh release upload "${TAG}" \
"${DIST_DIR}/${ZIP_NAME}" \ "${DIST_DIR}/${ZIP_NAME}" \
"${DIST_DIR}/${MSI_NAME}" \ "${DIST_DIR}/${MSI_NAME}" \
@ -87,6 +88,4 @@ if ! gh release upload "${TAG}" "${checksums_path}" --clobber; then
exit 1 exit 1
fi fi
gh release edit "${TAG}" --draft=false echo "Uploaded signed ${ZIP_NAME} and ${MSI_NAME} to release ${TAG}"
echo "Published signed ${ZIP_NAME} and ${MSI_NAME} on release ${TAG}"