From 0385f9d10c30b86234f5aa482da55e5b4f92b626 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Fri, 30 May 2025 15:15:23 +0100 Subject: [PATCH 01/10] chore: add script to create Windows resources Signed-off-by: Babak K. Shandiz --- script/gen-winres.ps1 | 60 +++++++++++++++++++++++++++++++++++++++++++ script/winres.json | 58 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 script/gen-winres.ps1 create mode 100644 script/winres.json diff --git a/script/gen-winres.ps1 b/script/gen-winres.ps1 new file mode 100644 index 000000000..cce7f6078 --- /dev/null +++ b/script/gen-winres.ps1 @@ -0,0 +1,60 @@ +#!/usr/bin/env pwsh + +# Generate Windows resource files as '.syso' +# +# Usage: +# gen-winres.ps1 +# +# Arguments: +# comma-separated list of architectures (e.g. "386,amd64,arm64") +# version string (e.g. "1.0.0") +# path to the `winres.json` file containing static metadata +# directory where the generated `.syso` files should be placed +# +# The created `.syso` files are named as `rsrc_windows_.syso` which helps +# Go compiler to pick the correct file based on the target architecture. +# + +$ErrorActionPreference = "Stop" + +$_arch = $args[0] +if ([string]::IsNullOrEmpty($_arch)) { + Write-Host "error: architecture argument is missing" + exit 1 +} + +$_version = $args[1] +if ([string]::IsNullOrEmpty($_version)) { + Write-Host "error: version argument is missing" + exit 1 +} + +$_winresJson = $args[2] +if ([string]::IsNullOrEmpty($_winresJson)) { + Write-Host "error: path to winres.json is missing" + exit 1 +} + +if (-not (Test-Path $_winresJson)) { + Write-Host "error: winres.json file not found at '$_winresjson'" + exit 1 +} + +$_output = $args[3] +if ([string]::IsNullOrEmpty($_output)) { + Write-Host "error: output path is missing" + exit 1 +} + +# Note that we intentionally leave the `--file-version` option in the command +# below, because it's meant to be a 4-component version, while ours is a semver +# (3-component). If we populate the `--file-version` with our semver value, then +# a zero component will be added to the end, which is not what we want. + +go run github.com/tc-hib/go-winres@v0.3.3 make ` + --arch "$_arch" ` + --product-version "$_version" ` + --in "$_winresJson" ` + --out rsrc + +Move-Item -Path ".\rsrc_*.syso" -Destination "$_output" -Force diff --git a/script/winres.json b/script/winres.json new file mode 100644 index 000000000..a9febba47 --- /dev/null +++ b/script/winres.json @@ -0,0 +1,58 @@ +{ + "RT_GROUP_ICON": { + "APP": { + "0000": [] + } + }, + "RT_MANIFEST": { + "#1": { + "0409": { + "identity": { + "name": "", + "version": "" + }, + "description": "", + "minimum-os": "win7", + "execution-level": "as invoker", + "ui-access": false, + "auto-elevate": false, + "dpi-awareness": "system", + "disable-theming": false, + "disable-window-filtering": false, + "high-resolution-scrolling-aware": false, + "ultra-high-resolution-scrolling-aware": false, + "long-path-aware": false, + "printer-driver-isolation": false, + "gdi-scaling": false, + "segment-heap": false, + "use-common-controls-v6": false + } + } + }, + "RT_VERSION": { + "#1": { + "0000": { + "fixed": { + "file_version": "0.0.0.0", + "product_version": "0.0.0.0" + }, + "info": { + "0409": { + "Comments": "", + "CompanyName": "GitHub", + "FileDescription": "GitHub CLI", + "FileVersion": "", + "InternalName": "gh", + "LegalCopyright": "", + "LegalTrademarks": "", + "OriginalFilename": "gh.exe", + "PrivateBuild": "", + "ProductName": "GitHub CLI", + "ProductVersion": "", + "SpecialBuild": "" + } + } + } + } + } +} \ No newline at end of file From 121483ad4ac5b5dd8d8c6b2692c4e842018b535c Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Fri, 30 May 2025 15:16:28 +0100 Subject: [PATCH 02/10] chore: prepare Windows resources `.syso` files before build Signed-off-by: Babak K. Shandiz --- .goreleaser.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index 6ef1ecc8b..6d980a1ea 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -11,6 +11,8 @@ before: {{ if eq .Runtime.Goos "windows" }}echo{{ end }} make manpages GH_VERSION={{.Version}} - >- # On linux the completions are used in nfpms below, but on macos they are used outside in the deployment build. {{ if eq .Runtime.Goos "windows" }}echo{{ end }} make completions + - >- # We need to create the `.syso` files (per architecture) to embed Windows resources (version info) + pwsh .\script\gen-winres.ps1 386,amd64,arm64 '{{ .Version }}' .\script\winres.json .\cmd\gh\ builds: - id: macos #build:macos goos: [darwin] From d1a544172528d8da2a9f6ef60a954b0185269775 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Fri, 30 May 2025 18:19:55 +0100 Subject: [PATCH 03/10] chore: ensure output path is a directory Signed-off-by: Babak K. Shandiz --- script/gen-winres.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/script/gen-winres.ps1 b/script/gen-winres.ps1 index cce7f6078..beb9ea001 100644 --- a/script/gen-winres.ps1 +++ b/script/gen-winres.ps1 @@ -46,6 +46,11 @@ if ([string]::IsNullOrEmpty($_output)) { exit 1 } +if (-not (Test-Path $_output -PathType Container)) { + Write-Host "error: output path '$_output' is not a directory" + exit 1 +} + # Note that we intentionally leave the `--file-version` option in the command # below, because it's meant to be a 4-component version, while ours is a semver # (3-component). If we populate the `--file-version` with our semver value, then From 5ed59d09933163d5554e74802b399be10dd63c1f Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Fri, 30 May 2025 18:23:15 +0100 Subject: [PATCH 04/10] chore: fix variable name casing Signed-off-by: Babak K. Shandiz --- script/gen-winres.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/gen-winres.ps1 b/script/gen-winres.ps1 index beb9ea001..c28f2da47 100644 --- a/script/gen-winres.ps1 +++ b/script/gen-winres.ps1 @@ -36,7 +36,7 @@ if ([string]::IsNullOrEmpty($_winresJson)) { } if (-not (Test-Path $_winresJson)) { - Write-Host "error: winres.json file not found at '$_winresjson'" + Write-Host "error: winres.json file not found at '$_winresJson'" exit 1 } From f81976256139672c887d6a0b7bacfe5800a64ae7 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Tue, 24 Jun 2025 11:46:34 +0100 Subject: [PATCH 05/10] chore: exclude generated `.syso` files from git repo Signed-off-by: Babak K. Shandiz --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 272b7703d..a4b73ac7a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ /pkg_payload /build/macOS/resources +# Windows resource files +/cmd/gh/*.syso + # VS Code .vscode From 925b0bcb033533f1ade718d8d527c24b44ac4721 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Tue, 24 Jun 2025 11:55:50 +0100 Subject: [PATCH 06/10] refactor: switch to `github.com/josephspurrier/goversioninfo` Signed-off-by: Babak K. Shandiz --- script/gen-winres.ps1 | 75 +++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 35 deletions(-) mode change 100644 => 100755 script/gen-winres.ps1 diff --git a/script/gen-winres.ps1 b/script/gen-winres.ps1 old mode 100644 new mode 100755 index c28f2da47..26020c93d --- a/script/gen-winres.ps1 +++ b/script/gen-winres.ps1 @@ -1,65 +1,70 @@ #!/usr/bin/env pwsh -# Generate Windows resource files as '.syso' -# -# Usage: -# gen-winres.ps1 -# -# Arguments: -# comma-separated list of architectures (e.g. "386,amd64,arm64") -# version string (e.g. "1.0.0") -# path to the `winres.json` file containing static metadata -# directory where the generated `.syso` files should be placed -# -# The created `.syso` files are named as `rsrc_windows_.syso` which helps -# Go compiler to pick the correct file based on the target architecture. -# +$_usage = @" +Generate Windows resource files as ``.syso`` + +Usage: + gen-winres.ps1 + +Arguments: + string to set as file version (e.g. "1.0.0") + string to set as product version (e.g. "1.0.0") + path to the ``versioninfo.json`` file containing static metadata + directory where the generated ``.syso`` files should be placed + +The created ``.syso`` files are named as ``resource_windows_.syso``. This +helps Go compiler to pick the correct file based on the target platform and +architecture. +"@ $ErrorActionPreference = "Stop" -$_arch = $args[0] -if ([string]::IsNullOrEmpty($_arch)) { - Write-Host "error: architecture argument is missing" +$_file_version = $args[0] +if ([string]::IsNullOrEmpty($_file_version)) { + Write-Host "error: file-version argument is missing" + Write-Host $_usage exit 1 } -$_version = $args[1] -if ([string]::IsNullOrEmpty($_version)) { - Write-Host "error: version argument is missing" +$_product_version = $args[1] +if ([string]::IsNullOrEmpty($_product_version)) { + Write-Host "error: product-version argument is missing" + Write-Host $_usage exit 1 } -$_winresJson = $args[2] -if ([string]::IsNullOrEmpty($_winresJson)) { - Write-Host "error: path to winres.json is missing" +$_versioninfo_path = $args[2] +if ([string]::IsNullOrEmpty($_versioninfo_path)) { + Write-Host "error: path to versioninfo.json is missing" + Write-Host $_usage exit 1 } -if (-not (Test-Path $_winresJson)) { - Write-Host "error: winres.json file not found at '$_winresJson'" +if (-not (Test-Path $_versioninfo_path)) { + Write-Host "error: file not found at '$_versioninfo_path'" + Write-Host $_usage exit 1 } $_output = $args[3] if ([string]::IsNullOrEmpty($_output)) { Write-Host "error: output path is missing" + Write-Host $_usage exit 1 } if (-not (Test-Path $_output -PathType Container)) { Write-Host "error: output path '$_output' is not a directory" + Write-Host $_usage exit 1 } -# Note that we intentionally leave the `--file-version` option in the command -# below, because it's meant to be a 4-component version, while ours is a semver -# (3-component). If we populate the `--file-version` with our semver value, then -# a zero component will be added to the end, which is not what we want. +go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.5.0 -go run github.com/tc-hib/go-winres@v0.3.3 make ` - --arch "$_arch" ` - --product-version "$_version" ` - --in "$_winresJson" ` - --out rsrc +goversioninfo ` + -64 -arm -platform-specific ` + -file-version "$_file_version" ` + -product-version "$_product_version" ` + "$_versioninfo_path" -Move-Item -Path ".\rsrc_*.syso" -Destination "$_output" -Force +Move-Item -Path "resource_windows_*.syso" -Destination "$_output" -Force From 68d9513038960d9b5efe5c28c7904af1258a5c5c Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Tue, 24 Jun 2025 11:56:10 +0100 Subject: [PATCH 07/10] chore: add `versioninfo.template.json` Signed-off-by: Babak K. Shandiz --- script/versioninfo.template.json | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 script/versioninfo.template.json diff --git a/script/versioninfo.template.json b/script/versioninfo.template.json new file mode 100644 index 000000000..6096837ff --- /dev/null +++ b/script/versioninfo.template.json @@ -0,0 +1,43 @@ +{ + "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": "", + "CompanyName": "GitHub", + "FileDescription": "GitHub CLI", + "FileVersion": "", + "InternalName": "gh", + "LegalCopyright": "", + "LegalTrademarks": "", + "OriginalFilename": "gh.exe", + "PrivateBuild": "", + "ProductName": "GitHub CLI", + "ProductVersion": "", + "SpecialBuild": "" + }, + "VarFileInfo": { + "Translation": { + "LangID": "0409", + "CharsetID": "04B0" + } + }, + "IconPath": "", + "ManifestPath": "" +} \ No newline at end of file From ee5ec5e058704e46582f38b3c05019ff48416b1d Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Tue, 24 Jun 2025 11:57:30 +0100 Subject: [PATCH 08/10] chore: delete `script/winres.json` Signed-off-by: Babak K. Shandiz --- script/winres.json | 58 ---------------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 script/winres.json diff --git a/script/winres.json b/script/winres.json deleted file mode 100644 index a9febba47..000000000 --- a/script/winres.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "RT_GROUP_ICON": { - "APP": { - "0000": [] - } - }, - "RT_MANIFEST": { - "#1": { - "0409": { - "identity": { - "name": "", - "version": "" - }, - "description": "", - "minimum-os": "win7", - "execution-level": "as invoker", - "ui-access": false, - "auto-elevate": false, - "dpi-awareness": "system", - "disable-theming": false, - "disable-window-filtering": false, - "high-resolution-scrolling-aware": false, - "ultra-high-resolution-scrolling-aware": false, - "long-path-aware": false, - "printer-driver-isolation": false, - "gdi-scaling": false, - "segment-heap": false, - "use-common-controls-v6": false - } - } - }, - "RT_VERSION": { - "#1": { - "0000": { - "fixed": { - "file_version": "0.0.0.0", - "product_version": "0.0.0.0" - }, - "info": { - "0409": { - "Comments": "", - "CompanyName": "GitHub", - "FileDescription": "GitHub CLI", - "FileVersion": "", - "InternalName": "gh", - "LegalCopyright": "", - "LegalTrademarks": "", - "OriginalFilename": "gh.exe", - "PrivateBuild": "", - "ProductName": "GitHub CLI", - "ProductVersion": "", - "SpecialBuild": "" - } - } - } - } - } -} \ No newline at end of file From 480240fd0b5ae3d3eea87015863d98a9e03d2d35 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Tue, 24 Jun 2025 12:59:47 +0100 Subject: [PATCH 09/10] chore: create `.syso` libs only on Windows Signed-off-by: Babak K. Shandiz --- .goreleaser.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 6d980a1ea..309e2ca8f 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -12,7 +12,7 @@ before: - >- # On linux the completions are used in nfpms below, but on macos they are used outside in the deployment build. {{ if eq .Runtime.Goos "windows" }}echo{{ end }} make completions - >- # We need to create the `.syso` files (per architecture) to embed Windows resources (version info) - pwsh .\script\gen-winres.ps1 386,amd64,arm64 '{{ .Version }}' .\script\winres.json .\cmd\gh\ + {{ if ne .Runtime.Goos "windows" }}echo{{ end }} pwsh .\script\gen-winres.ps1 '{{ .Version }} ({{time "2006-01-02"}})' '{{ .Version }}' .\script\versioninfo.template.json .\cmd\gh\ builds: - id: macos #build:macos goos: [darwin] From 9c54fb3e0d499406d2274e354e1f7d47b48dca2f Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Tue, 24 Jun 2025 22:19:37 +0100 Subject: [PATCH 10/10] chore: improve error message when `versioninfo.json` is not found Co-authored-by: Andy Feller --- script/gen-winres.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/gen-winres.ps1 b/script/gen-winres.ps1 index 26020c93d..e5eab1c9c 100755 --- a/script/gen-winres.ps1 +++ b/script/gen-winres.ps1 @@ -41,7 +41,7 @@ if ([string]::IsNullOrEmpty($_versioninfo_path)) { } if (-not (Test-Path $_versioninfo_path)) { - Write-Host "error: file not found at '$_versioninfo_path'" + Write-Host "error: path to versioninfo.json '$_versioninfo_path' is not a file" Write-Host $_usage exit 1 }