From abf4fc2cf0074c124458baf07c4243198ab9e449 Mon Sep 17 00:00:00 2001 From: jamesread Date: Fri, 26 Jun 2026 21:19:19 +0100 Subject: [PATCH] feat: Windows icons and MSI support --- .github/workflows/build-and-release.yml | 6 ++ .gitignore | 1 + .goreleaser.yml | 1 + .releaserc.yaml | 2 + Makefile | 7 ++ service/Makefile | 7 +- var/windows/OliveTin.exe.manifest | 25 +++++++ var/windows/OliveTin.ico | Bin 0 -> 109595 bytes var/windows/OliveTin.wxs | 46 ++++++++++++ var/windows/build-msi.sh | 93 ++++++++++++++++++++++++ var/windows/generate-resources.sh | 92 +++++++++++++++++++++++ var/windows/upload-msi-release.sh | 40 ++++++++++ var/windows/versioninfo.json | 41 +++++++++++ 13 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 var/windows/OliveTin.exe.manifest create mode 100644 var/windows/OliveTin.ico create mode 100644 var/windows/OliveTin.wxs create mode 100755 var/windows/build-msi.sh create mode 100755 var/windows/generate-resources.sh create mode 100755 var/windows/upload-msi-release.sh create mode 100644 var/windows/versioninfo.json diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index b9ba5a0..5fc1d7c 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -13,6 +13,7 @@ on: - 'integration-tests/**' - 'proto/**' - 'service/**' + - 'var/windows/**' workflow_dispatch: push: tags: @@ -31,6 +32,7 @@ on: - 'integration-tests/**' - 'proto/**' - 'service/**' + - 'var/windows/**' jobs: build: @@ -112,6 +114,10 @@ jobs: integration-tests !integration-tests/node_modules + - name: Install msitools + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false + run: sudo apt-get update && sudo apt-get install -y msitools + - name: Install goreleaser if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false uses: goreleaser/goreleaser-action@v6 diff --git a/.gitignore b/.gitignore index 48e8d33..469fbd0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ service/OliveTin service/OliveTin.armhf service/OliveTin.exe +service/resource_windows_*.syso service/reports releases/ dist/ diff --git a/.goreleaser.yml b/.goreleaser.yml index a6ba475..32c6a76 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -3,6 +3,7 @@ version: 2 before: hooks: - make service-prep + - make windows-resources VERSION={{ .Version }} builds: - env: diff --git a/.releaserc.yaml b/.releaserc.yaml index c3ddbdc..fc571cf 100644 --- a/.releaserc.yaml +++ b/.releaserc.yaml @@ -10,5 +10,7 @@ plugins: - - "@semantic-release/exec" - publishCmd: | goreleaser release --clean --timeout 60m + VERSION=${nextRelease.version} ./var/windows/build-msi.sh + ./var/windows/upload-msi-release.sh ${nextRelease.gitTag} tagFormat: '${version}' diff --git a/Makefile b/Makefile index 23062c2..7ce7955 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,12 @@ service: service-prep: $(MAKE) -wC service prep +windows-resources: + VERSION="$(VERSION)" ./var/windows/generate-resources.sh + +windows-msi: + VERSION="$(VERSION)" ./var/windows/build-msi.sh + service-unittests: $(MAKE) -wC service unittests @@ -59,6 +65,7 @@ clean: $(call delete-files,OliveTin) $(call delete-files,OliveTin.armhf) $(call delete-files,OliveTin.exe) + rm -f service/resource_windows_*.syso $(call delete-files,reports) $(call delete-files,gen) diff --git a/service/Makefile b/service/Makefile index dee7cc9..5d3044a 100644 --- a/service/Makefile +++ b/service/Makefile @@ -19,11 +19,14 @@ compile-x64-lin: go build -o OliveTin go env -u GOOS -compile-x64-win: +compile-x64-win: windows-resources go env -w GOOS=windows GOARCH=amd64 go build -o OliveTin.exe go env -u GOOS GOARCH +windows-resources: + $(MAKE) -wC .. windows-resources + compile: compile-armhf compile-x64-lin compile-x64-win codestyle: go-tools @@ -33,7 +36,7 @@ codestyle: go-tools gocritic check ./... test: unittests - + tests: unittests unittests: diff --git a/var/windows/OliveTin.exe.manifest b/var/windows/OliveTin.exe.manifest new file mode 100644 index 0000000..90faaa7 --- /dev/null +++ b/var/windows/OliveTin.exe.manifest @@ -0,0 +1,25 @@ + + + + + + + + + + + true + PerMonitorV2 + + + diff --git a/var/windows/OliveTin.ico b/var/windows/OliveTin.ico new file mode 100644 index 0000000000000000000000000000000000000000..446dd82e1cfa38cd517d8b2027382c01da987f0a GIT binary patch literal 109595 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 literal 0 HcmV?d00001 diff --git a/var/windows/OliveTin.wxs b/var/windows/OliveTin.wxs new file mode 100644 index 0000000..807dd5b --- /dev/null +++ b/var/windows/OliveTin.wxs @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/var/windows/build-msi.sh b/var/windows/build-msi.sh new file mode 100755 index 0000000..42aeb07 --- /dev/null +++ b/var/windows/build-msi.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +DIST_DIR="${DIST_DIR:-${REPO_ROOT}/dist}" +ARCH="${ARCH:-amd64}" +ZIP_NAME="OliveTin-windows-${ARCH}.zip" +ZIP_PATH="${DIST_DIR}/${ZIP_NAME}" +MSI_NAME="OliveTin-windows-${ARCH}.msi" +MSI_PATH="${DIST_DIR}/${MSI_NAME}" + +if [[ ! -f "${ZIP_PATH}" ]]; then + echo "Windows archive not found: ${ZIP_PATH}" >&2 + exit 1 +fi + +if ! command -v wixl >/dev/null || ! command -v wixl-heat >/dev/null; then + echo "wixl and wixl-heat are required (install the wixl/msitools package)" >&2 + exit 1 +fi + +normalize_windows_version() { + local raw="${1#v}" + raw="${raw%%-*}" + if [[ ! "${raw}" =~ ^[0-9]+(\.[0-9]+){0,3}$ ]]; then + echo "0.0.0.0" + return + fi + local -a parts=() + IFS='.' read -r -a parts <<<"${raw}" + local major="${parts[0]:-0}" + local minor="${parts[1]:-0}" + local patch="${parts[2]:-0}" + local build="${parts[3]:-0}" + printf '%s.%s.%s.%s' "${major}" "${minor}" "${patch}" "${build}" +} + +VERSION="${VERSION:-}" +if [[ -z "${VERSION}" ]]; then + VERSION="$(git -C "${REPO_ROOT}" describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || true)" +fi +if [[ -z "${VERSION}" ]]; then + echo "Could not determine release version; set VERSION explicitly" >&2 + exit 1 +fi +WINDOWS_VERSION="$(normalize_windows_version "${VERSION}")" + +STAGING="$(mktemp -d)" +APP_STAGING="$(mktemp -d)" +HEAT_WXS="$(mktemp)" +trap 'rm -rf "${STAGING}" "${APP_STAGING}" "${HEAT_WXS}"' EXIT + +unzip -q "${ZIP_PATH}" -d "${STAGING}" +SOURCE_ROOT="${STAGING}/OliveTin-windows-${ARCH}" + +if [[ ! -f "${SOURCE_ROOT}/OliveTin.exe" ]]; then + echo "OliveTin.exe not found in ${SOURCE_ROOT}" >&2 + exit 1 +fi + +if [[ ! -f "${SOURCE_ROOT}/config.yaml" ]]; then + echo "config.yaml not found in ${SOURCE_ROOT}" >&2 + exit 1 +fi + +mkdir -p "${APP_STAGING}/webui" +cp "${SOURCE_ROOT}/OliveTin.exe" "${APP_STAGING}/" +cp -a "${SOURCE_ROOT}/webui/." "${APP_STAGING}/webui/" + +( + cd "${APP_STAGING}" + find . -type f | sed 's|^\./||' +) | wixl-heat \ + -p "" \ + --component-group CG.AppFiles \ + --var var.SourceDir \ + --directory-ref INSTALLDIR \ + --win64 \ + > "${HEAT_WXS}" + +wixl \ + -v \ + -a x64 \ + -D "Version=${WINDOWS_VERSION}" \ + -D "Win64=yes" \ + -D "SourceDir=${APP_STAGING}" \ + -D "ConfigSource=${SOURCE_ROOT}/config.yaml" \ + -o "${MSI_PATH}" \ + "${SCRIPT_DIR}/OliveTin.wxs" \ + "${HEAT_WXS}" + +echo "Built ${MSI_PATH}" diff --git a/var/windows/generate-resources.sh b/var/windows/generate-resources.sh new file mode 100755 index 0000000..50e562c --- /dev/null +++ b/var/windows/generate-resources.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +SERVICE_DIR="${REPO_ROOT}/service" +VERSIONINFO_JSON="${SCRIPT_DIR}/versioninfo.json" +ICON_PATH="${SCRIPT_DIR}/OliveTin.ico" +MANIFEST_PATH="${SCRIPT_DIR}/OliveTin.exe.manifest" +GOVERSIONINFO_VERSION="${GOVERSIONINFO_VERSION:-v1.5.0}" + +usage() { + cat </dev/null 2>&1; then + git -C "${REPO_ROOT}" describe --tags --abbrev=0 + return + fi + echo "0.0.0" +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +if [[ ! -f "${VERSIONINFO_JSON}" ]]; then + echo "versioninfo.json not found: ${VERSIONINFO_JSON}" >&2 + exit 1 +fi + +if [[ ! -f "${ICON_PATH}" ]]; then + echo "icon not found: ${ICON_PATH}" >&2 + exit 1 +fi + +WINDOWS_VERSION="$(normalize_windows_version "$(resolve_version "${1:-}")")" +echo "Generating Windows resources for version ${WINDOWS_VERSION}" + +go install "github.com/josephspurrier/goversioninfo/cmd/goversioninfo@${GOVERSIONINFO_VERSION}" + +WORK_DIR="$(mktemp -d)" +trap 'rm -rf "${WORK_DIR}"' EXIT + +( + cd "${WORK_DIR}" + goversioninfo \ + -64 \ + -platform-specific \ + -icon="${ICON_PATH}" \ + -manifest="${MANIFEST_PATH}" \ + -file-version="${WINDOWS_VERSION}" \ + -product-version="${WINDOWS_VERSION}" \ + "${VERSIONINFO_JSON}" +) + +rm -f "${SERVICE_DIR}"/resource_windows_*.syso +mv "${WORK_DIR}"/resource_windows_*.syso "${SERVICE_DIR}/" +echo "Wrote Windows resource files to ${SERVICE_DIR}" diff --git a/var/windows/upload-msi-release.sh b/var/windows/upload-msi-release.sh new file mode 100755 index 0000000..3773c28 --- /dev/null +++ b/var/windows/upload-msi-release.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +DIST_DIR="${DIST_DIR:-${REPO_ROOT}/dist}" +ARCH="${ARCH:-amd64}" +MSI_NAME="OliveTin-windows-${ARCH}.msi" +MSI_PATH="${DIST_DIR}/${MSI_NAME}" +TAG="${1:-}" + +if [[ -z "${TAG}" ]]; then + echo "Usage: $(basename "$0") " >&2 + exit 1 +fi + +if [[ ! -f "${MSI_PATH}" ]]; then + echo "MSI not found: ${MSI_PATH}" >&2 + exit 1 +fi + +if ! command -v gh >/dev/null; then + echo "gh is required to upload the MSI to GitHub releases" >&2 + exit 1 +fi + +checksums_path="${DIST_DIR}/checksums.txt" +if [[ -f "${checksums_path}" ]] && ! grep -qF " ${MSI_NAME}" "${checksums_path}"; then + ( + cd "${DIST_DIR}" + sha256sum "${MSI_NAME}" + ) >> "${checksums_path}" +fi + +gh release upload "${TAG}" "${MSI_PATH}" --clobber +if [[ -f "${checksums_path}" ]]; then + gh release upload "${TAG}" "${checksums_path}" --clobber +fi + +echo "Uploaded ${MSI_NAME} to release ${TAG}" diff --git a/var/windows/versioninfo.json b/var/windows/versioninfo.json new file mode 100644 index 0000000..7822648 --- /dev/null +++ b/var/windows/versioninfo.json @@ -0,0 +1,41 @@ +{ + "FixedFileInfo": { + "FileVersion": { + "Major": 0, + "Minor": 0, + "Patch": 0, + "Build": 0 + }, + "ProductVersion": { + "Major": 0, + "Minor": 0, + "Patch": 0, + "Build": 0 + }, + "FileFlagsMask": "3f", + "FileFlags ": "00", + "FileOS": "040004", + "FileType": "01", + "FileSubType": "00" + }, + "StringFileInfo": { + "Comments": "https://github.com/OliveTin/OliveTin", + "CompanyName": "James Read", + "FileDescription": "OliveTin web interface for running shell commands", + "FileVersion": "0.0.0.0", + "InternalName": "OliveTin", + "LegalCopyright": "Copyright (C) James Read. Licensed under AGPL-3.0.", + "LegalTrademarks": "", + "OriginalFilename": "OliveTin.exe", + "PrivateBuild": "", + "ProductName": "OliveTin", + "ProductVersion": "0.0.0.0", + "SpecialBuild": "" + }, + "VarFileInfo": { + "Translation": { + "LangID": "0409", + "CharsetID": "04B0" + } + } +}