feat: Windows icons and MSI support
This commit is contained in:
parent
e61c8b036d
commit
abf4fc2cf0
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
service/OliveTin
|
||||
service/OliveTin.armhf
|
||||
service/OliveTin.exe
|
||||
service/resource_windows_*.syso
|
||||
service/reports
|
||||
releases/
|
||||
dist/
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ version: 2
|
|||
before:
|
||||
hooks:
|
||||
- make service-prep
|
||||
- make windows-resources VERSION={{ .Version }}
|
||||
|
||||
builds:
|
||||
- env:
|
||||
|
|
|
|||
|
|
@ -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}'
|
||||
|
|
|
|||
7
Makefile
7
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
version="1.0.0.0"
|
||||
processorArchitecture="*"
|
||||
name="OliveTin.OliveTin"
|
||||
type="win32" />
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*" />
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 107 KiB |
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product
|
||||
Id="*"
|
||||
Name="OliveTin $(var.Version)"
|
||||
Language="1033"
|
||||
Version="$(var.Version)"
|
||||
Manufacturer="James Read"
|
||||
UpgradeCode="8B5E3F2A-1C4D-4E6F-9A0B-2D3C4E5F6071">
|
||||
<Package
|
||||
InstallerVersion="500"
|
||||
Compressed="yes"
|
||||
InstallScope="perMachine"
|
||||
Description="OliveTin web interface for running shell commands"
|
||||
Comments="https://github.com/OliveTin/OliveTin" />
|
||||
|
||||
<MajorUpgrade
|
||||
AllowSameVersionUpgrades="yes"
|
||||
DowngradeErrorMessage="A newer version of OliveTin is already installed." />
|
||||
<MediaTemplate />
|
||||
|
||||
<Feature Id="ProductFeature" Title="OliveTin" Level="1">
|
||||
<ComponentGroupRef Id="CG.AppFiles" />
|
||||
<ComponentRef Id="ConfigFile" />
|
||||
</Feature>
|
||||
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
<Directory Id="ProgramFiles64Folder">
|
||||
<Directory Id="INSTALLDIR" Name="OliveTin" />
|
||||
</Directory>
|
||||
<Directory Id="CommonAppDataFolder">
|
||||
<Directory Id="ConfigDir" Name="OliveTin" />
|
||||
</Directory>
|
||||
</Directory>
|
||||
|
||||
<DirectoryRef Id="ConfigDir">
|
||||
<Component Id="ConfigFile" Guid="A1B2C3D4-E5F6-7890-ABCD-EF1234567890" Win64="yes">
|
||||
<File
|
||||
Id="ConfigYaml"
|
||||
Source="$(var.ConfigSource)"
|
||||
Name="config.yaml"
|
||||
KeyPath="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
</Product>
|
||||
</Wix>
|
||||
|
|
@ -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}"
|
||||
|
|
@ -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 <<EOF
|
||||
Usage: $(basename "$0") [version]
|
||||
|
||||
Generate Windows resource (.syso) files for embedding in OliveTin.exe.
|
||||
|
||||
version Release version (e.g. 3.0.0 or v3.0.0). Defaults to VERSION env,
|
||||
then the latest git tag, then 0.0.0.
|
||||
EOF
|
||||
}
|
||||
|
||||
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}"
|
||||
}
|
||||
|
||||
resolve_version() {
|
||||
if [[ -n "${VERSION:-}" ]]; then
|
||||
echo "${VERSION}"
|
||||
return
|
||||
fi
|
||||
if [[ $# -gt 0 && -n "${1:-}" ]]; then
|
||||
echo "${1}"
|
||||
return
|
||||
fi
|
||||
if git -C "${REPO_ROOT}" describe --tags --abbrev=0 >/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}"
|
||||
|
|
@ -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") <release-tag>" >&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}"
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue