-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Embed Windows resources (VERSIONINFO) during build #11048
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Signed-off-by: Babak K. Shandiz <[email protected]>
Signed-off-by: Babak K. Shandiz <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for embedding Windows VERSIONINFO resources into the .exe build by generating .syso files from a static metadata file.
- Introduces
script/winres.jsonto hold placeholder metadata for Windows resources. - Adds
script/gen-winres.ps1to generate and move architecture-specific.sysofiles. - Updates
.goreleaser.ymlto invoke the PowerShell script before Windows builds.
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| script/winres.json | Defines structured placeholders for RT_GROUP_ICON, RT_MANIFEST, and RT_VERSION entries |
| script/gen-winres.ps1 | PowerShell script that runs go-winres make and moves generated .syso files |
| .goreleaser.yml | Added a before hook to run the generation script for embedding resources |
Comments suppressed due to low confidence (2)
script/gen-winres.ps1:39
- Use the correct variable casing in the error message (
$_winresJson) to match the variable name and avoid confusion.
Write-Host "error: winres.json file not found at '$_winresjson'"
script/gen-winres.ps1:54
- Verify that the import path (
github.com/tc-hib/go-winres) matches the intended module (the PR description mentionsgc-hib). Update this path if it was mistyped.
go run github.com/tc-hib/[email protected] make `
.goreleaser.yml
Outdated
| - >- # 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\ |
Copilot
AI
May 30, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrap the new pwsh .\script\gen-winres.ps1 hook in a Windows-only conditional (e.g. {{ if eq .Runtime.Goos "windows" }}) to prevent it from running on non-Windows targets and failing the build.
| pwsh .\script\gen-winres.ps1 386,amd64,arm64 '{{ .Version }}' .\script\winres.json .\cmd\gh\ | |
| {{ if eq .Runtime.Goos "windows" }}pwsh .\script\gen-winres.ps1 386,amd64,arm64 '{{ .Version }}' .\script\winres.json .\cmd\gh\{{ end }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The .Runtime.Goos holds the platform where the Goreleaser is invoked. So, it's not the target.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@babakks : you're correct: GOOS in this case is the operating system of the runner, which isn't the target per se but it is because we Windows releases are built on the Windows runner.
That said, I think the before hooks above short circuit the make commands on the Windows runner, which would / should result in just echoing the commands without running them.
You can look back into #7324 where completions were only built for Windows and Mac OS:
Lines 8 to 13 in 8b987e2
| before: | |
| hooks: | |
| - >- | |
| {{ if eq .Runtime.Goos "windows" }}echo{{ end }} make manpages GH_VERSION={{.Version}} | |
| - >- | |
| {{ if ne .Runtime.Goos "linux" }}echo{{ end }} make completions |
If these should only be present on Windows builds, then maybe this should be conditionalized for anything not Windows
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I noticed that, and it's annoying to see CI environment details are leaked into .goreleaser.yml. Anyway, I updated the command to only work on Windows.
Signed-off-by: Babak K. Shandiz <[email protected]>
Signed-off-by: Babak K. Shandiz <[email protected]>
|
Don't leave FileVersion as 0.0.0.0, both version fields are strings, but are in windows UI parsed to numeric only, even if the value is non numeric, 2.49.0.1, please ignore the UI. Example for git.exe: PS C:\> [System.Diagnostics.FileVersionInfo]::GetVersionInfo("C:\Program Files\Git\bin\git.exe").ProductVersion
2.49.0.windows.1
PS C:\> [System.Diagnostics.FileVersionInfo]::GetVersionInfo("C:\Program Files\Git\bin\git.exe").FileVersion
2.49.0.windows.1
PS C:\>.NET binaries instead have data such as:
Edit: But in this case follow output of |
|
Thanks for the note, @caspChristian! 🙏 I can confirm that was just the GUI behaviour. Regrading the
So, I think we should pick a format that works for us. As you pointed out, currently, the output of $ gh version
gh version 2.74.0 (2025-05-29)
https://github.com/cli/cli/releases/tag/v2.74.0The version and the build date are the only release-specific variables that we bake into the binary. So, I agree with your suggestion about using the
|
|
@andyfeller Since you somewhat defined the A/C for this, can you please confirm the suggested format of |
andyfeller
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: excellent PR write up!
Handful of questions and concerns I'd like to follow up on regarding automation and the underlying tool. 🤔
.goreleaser.yml
Outdated
| - >- # 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\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@babakks : you're correct: GOOS in this case is the operating system of the runner, which isn't the target per se but it is because we Windows releases are built on the Windows runner.
That said, I think the before hooks above short circuit the make commands on the Windows runner, which would / should result in just echoing the commands without running them.
You can look back into #7324 where completions were only built for Windows and Mac OS:
Lines 8 to 13 in 8b987e2
| before: | |
| hooks: | |
| - >- | |
| {{ if eq .Runtime.Goos "windows" }}echo{{ end }} make manpages GH_VERSION={{.Version}} | |
| - >- | |
| {{ if ne .Runtime.Goos "linux" }}echo{{ end }} make completions |
If these should only be present on Windows builds, then maybe this should be conditionalized for anything not Windows
script/gen-winres.ps1
Outdated
| # (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 ` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: this project does not appear to be actively maintained if even go.mod hasn't been changed in a year.
I know this was the tool that @iamazeem used in experimenting on this issue. The only other suggestion I could offer is https://github.com/josephspurrier/goversioninfo, which has more recent releases and appears to keep up with Dependabot security updates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I picked this one was it's simpler interface, especially regarding the setting of minimum OS version requirements. But that's a fair point. We're now using the one you mentioned. Also, now I'm thinking I don't agree with setting the min OS version.
script/winres.json
Outdated
| "version": "" | ||
| }, | ||
| "description": "", | ||
| "minimum-os": "win7", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest: if we continue using this dependency, then we should consider updating this to Win10
| "minimum-os": "win7", | |
| "minimum-os": "win10", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I believe it's not a good idea to state the minimum OS version in the metadata. One reason is that might be breaking change to users who are already using gh on older platforms, and it's not nice to break their experience. The other reason is that, now that we're using the other library/tool, we have to manually create the manifest file (in which the OS requirement is listed), which is something that is hard to follow/maintain over time, because we'd have to update a list of UUIDs associated with different Windows versions, and I'd rather leave it.
Signed-off-by: Babak K. Shandiz <[email protected]>
Signed-off-by: Babak K. Shandiz <[email protected]>
Signed-off-by: Babak K. Shandiz <[email protected]>
Signed-off-by: Babak K. Shandiz <[email protected]>
Signed-off-by: Babak K. Shandiz <[email protected]>
|
@andyfeller I've now switched to Via GUIVia CLI
|
andyfeller
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, @babakks; had just a couple of questions to clarify and will ship!
| {{ 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\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Is the current timestamp meant to take the place of the Build portion of the file version?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, as I suggested here, it will look like 2.74.0 (2025-05-29), which is similar to gh version output:
~ gh version
gh version 2.74.1 (2025-06-10)
https://github.com/cli/cli/releases/tag/v2.74.1
andyfeller
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Realizing my major concern about the command continuation was already addressed, this looks good to ship 👍
Co-authored-by: Andy Feller <[email protected]>
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [cli/cli](https://github.com/cli/cli) | minor | `v2.74.2` -> `v2.76.1` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>cli/cli (cli/cli)</summary> ### [`v2.76.1`](https://github.com/cli/cli/releases/tag/v2.76.1): GitHub CLI 2.76.1 [Compare Source](cli/cli@v2.76.0...v2.76.1) #### `gh pr create` regression fix This release fixes a regression introduced in `v2.76.0` where organization teams were retrieved outside of intentional use cases. This caused problems for GitHub Enterprise Server users using the GitHub Actions automatic token that does not have access to organization teams. For more information, see cli/cli#11360 #### What's Changed ##### 🐛 Fixes - Fix: `gh pr create`, only fetch teams when reviewers contain a team by [@​BagToad](https://github.com/BagToad) in cli/cli#11361 ##### 📚 Docs & Chores - add tenancy aware for san matcher by [@​ejahnGithub](https://github.com/ejahnGithub) in cli/cli#11261 - Run Lint and Tests on `push` to `trunk` branch by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11325 - update ownership of pkg/cmd/release/shared/ by [@​ejahnGithub](https://github.com/ejahnGithub) in cli/cli#11326 - Automate spam issue detection by [@​babakks](https://github.com/babakks) in cli/cli#11316 - Improve `api` `--preview` docs by [@​jsoref](https://github.com/jsoref) in cli/cli#11274 - Incorporate govulncheck into workflows by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11332 - chore(deps): bump advanced-security/filter-sarif from 1.0.0 to 1.0.1 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11298 - chore(deps): bump github.com/sigstore/sigstore-go from 1.0.0 to 1.1.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11307 **Full Changelog**: cli/cli@v2.76.0...v2.76.1 ### [`v2.76.0`](https://github.com/cli/cli/releases/tag/v2.76.0): GitHub CLI 2.76.0 [Compare Source](cli/cli@v2.75.1...v2.76.0) ####Copilot Coding Agent Support GitHub Copilot Pro+ and Copilot Enterprise subscribers can now assign issues to GitHub Copilot during issue creation using: - Command-line flag: `gh issue create --assignee @​copilot` - Launching web browser: `gh issue create --assignee @​copilot --web` - Or interactively selecting `Copilot (AI)` as assignee in `gh issue create` metadata For more details, refer to [the full changelog post for Copilot coding agent](https://github.blog/changelog/2025-05-19-github-copilot-coding-agent-in-public-preview/). #### What's Changed ##### ✨ Features - Assign Copilot during `gh issue create` by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11279 - Display immutable field in `release view` command by [@​bdehamer](https://github.com/bdehamer) in cli/cli#11251 ##### 🐛 Fixes - FIX: Do not fetch logs for skipped jobs by [@​babakks](https://github.com/babakks) in cli/cli#11312 - Transform `extension` and `filename` qualifiers into `path` qualifier for web code search by [@​samcoe](https://github.com/samcoe) in cli/cli#11211 ##### 📚 Docs & Chores - FIX: Workflow does not contain permissions by [@​BagToad](https://github.com/BagToad) in cli/cli#11322 - Add automated feature request response workflow by [@​BagToad](https://github.com/BagToad) in cli/cli#11299 **Full Changelog**: cli/cli@v2.75.1...v2.76.0 ### [`v2.75.1`](https://github.com/cli/cli/releases/tag/v2.75.1): GitHub CLI 2.75.1 [Compare Source](cli/cli@v2.75.0...v2.75.1) #### What's Changed ##### 🐛 Fixes - Ensure hostnames are visible in CLI website by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11295 - Revert "Fix: `gh pr create` prioritize `--title` and `--body` over `--fill` when `--web` is present" by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11300 ##### 📚 Docs & Chores - Ensure go directive is always .0 version in bump by [@​williammartin](https://github.com/williammartin) in cli/cli#11259 - Minor (1-word) documentation typo in generated `~/.config/gh/config.yml` by [@​kurahaupo](https://github.com/kurahaupo) in cli/cli#11246 - Automate closing of stale issues by [@​babakks](https://github.com/babakks) in cli/cli#11268 - Filter the `third-party/` folder out of CodeQL results by [@​BagToad](https://github.com/BagToad) in cli/cli#11278 - Exclude `third-party` source from golangci-lint by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11293 #####
Dependencies - Bump Go to 1.24.5 by [@​github-actions](https://github.com/github-actions)\[bot] in cli/cli#11255 - chore(deps): bump github.com/sigstore/protobuf-specs from 0.4.3 to 0.5.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11263 - chore(deps): bump golang.org/x/term from 0.32.0 to 0.33.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11266 - chore(deps): bump golang.org/x/sync from 0.15.0 to 0.16.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11264 - chore(deps): bump golang.org/x/text from 0.26.0 to 0.27.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11265 - chore(deps): bump golang.org/x/crypto from 0.39.0 to 0.40.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11275 #### New Contributors - [@​kurahaupo](https://github.com/kurahaupo) made their first contribution in cli/cli#11246 - [@​github-actions](https://github.com/github-actions)\[bot] made their first contribution in cli/cli#11255 **Full Changelog**: cli/cli@v2.75.0...v2.75.1 ### [`v2.75.0`](https://github.com/cli/cli/releases/tag/v2.75.0): GitHub CLI 2.75.0 [Compare Source](cli/cli@v2.74.2...v2.75.0) #### What's Changed ##### ✨ Features - init release verify subcommands by [@​ejahnGithub](https://github.com/ejahnGithub) in cli/cli#11018 - Embed Windows resources (VERSIONINFO) during build by [@​babakks](https://github.com/babakks) in cli/cli#11048 - Support `--no-repos-selected` on `gh secret set` by [@​williammartin](https://github.com/williammartin) in cli/cli#11217 ##### 🐛 Fixes - Fix: `gh pr create` prioritize `--title` and `--body` over `--fill` when `--web` is present by [@​dankrzeminski32](https://github.com/dankrzeminski32) in cli/cli#10547 - fix: get token for active user instead of blank if possible by [@​anuraaga](https://github.com/anuraaga) in cli/cli#11038 - Use Actions API to retrieve job run logs as a fallback mechanism by [@​babakks](https://github.com/babakks) in cli/cli#11172 - Fix query object state mutation during pagination by [@​babakks](https://github.com/babakks) in cli/cli#11244 - Handle `HTTP 404` when deleting remote branch in `pr merge` by [@​babakks](https://github.com/babakks) in cli/cli#11234 ##### 📚 Docs & Chores - chore: fix function name by [@​jinjingroad](https://github.com/jinjingroad) in cli/cli#11149 - chore: update Go version to 1.24 in devcontainer configuration and docs by [@​tMinamiii](https://github.com/tMinamiii) in cli/cli#11158 - Ensure lint workflow checks whether 3rd party license and code is up to date by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11047 - docs: install\_linux.md: add Solus linux install instructions by [@​chax](https://github.com/chax) in cli/cli#10823 - Fix missing newline in install\_linux.md by [@​BagToad](https://github.com/BagToad) in cli/cli#11160 - Ensure automation uses pinned go-licenses version by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11161 - Add `workflow_dispatch` support to MR Help Wanted check by [@​BagToad](https://github.com/BagToad) in cli/cli#11179 - Remove unused `GH_TOKEN` env variable from workflow by [@​BagToad](https://github.com/BagToad) in cli/cli#11190 - Add workflow to automate go version bumping by [@​williammartin](https://github.com/williammartin) in cli/cli#11189 - Fix inconsistent use of tabs and spaces by [@​Stefan-Heimersheim](https://github.com/Stefan-Heimersheim) in cli/cli#11194 - Decouple arg parsing from MR finder by [@​babakks](https://github.com/babakks) in cli/cli#11192 - docs: consistently use `apt` in installation instructions by [@​tklauser](https://github.com/tklauser) in cli/cli#11216 - Ensure bump go script has git user configured by [@​williammartin](https://github.com/williammartin) in cli/cli#11229 - Inject token into bump-go workflow by [@​williammartin](https://github.com/williammartin) in cli/cli#11233 - Reinstating Primer Style CLI content within `cli/cli` repository by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11060 - Add setup-go to bump-go workflow by [@​williammartin](https://github.com/williammartin) in cli/cli#11237 - Ensure GoReleaser does not break on Mac OS and Linux when skipping Windows `.rsyso` generation script by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11257 #####
Dependencies - Bump all dependencies except dev-tunnels by [@​williammartin](https://github.com/williammartin) in cli/cli#11203 - Update microsoft dev-tunnels to v0.1.13 by [@​williammartin](https://github.com/williammartin) in cli/cli#11205 - Consume dependabot minor versions for go modules by [@​williammartin](https://github.com/williammartin) in cli/cli#11213 #### New Contributors - [@​jinjingroad](https://github.com/jinjingroad) made their first contribution in cli/cli#11149 - [@​tMinamiii](https://github.com/tMinamiii) made their first contribution in cli/cli#11158 - [@​chax](https://github.com/chax) made their first contribution in cli/cli#10823 - [@​dankrzeminski32](https://github.com/dankrzeminski32) made their first contribution in cli/cli#10547 - [@​anuraaga](https://github.com/anuraaga) made their first contribution in cli/cli#11038 - [@​Stefan-Heimersheim](https://github.com/Stefan-Heimersheim) made their first contribution in cli/cli#11194 **Full Changelog**: cli/cli@v2.74.2...v2.75.0 </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90Il19-->

Fixes #10601
This PR adds another
Beforehook to our Goreleaser config to prepare Windows resources information (version info) as.sysofiles to be embedded into our.exebinary during build.There are a couple of notes regarding this implementation:
A new file, named
script/winres.jsonis added to hold the static metadata (e.g. company, product name, etc). The version fields are left empty in this file, which will be later populated during the call to the newly addedscript/gen-winres.ps1script. I didn't include the icon, though.The
script/gen-winres.ps1is PowerShell script that creates.sysofiles and moves them tocmd/ghto be picked up by Go compiler. Leaving them at the root of the repo has no effect. Under the hood the script uses thegithub.com/gc-hib/[email protected]module'smakecommand, to creates multiple.sysofiles per architecture. Thanks to the right naming (e.g.rsrc_windows_amd64.syso), the Go compiler only picks the one that matches the target architecture. So, we can simply create all.sysofiles at the beginning of the goreleaser session and leave the rest to Go compiler. Not to mention, leaving the files will have no effect when building for other platforms; although, we actually build them as separete jobs.The
FileVersionfield of the Windows resources structure is meant to be a 4-component version (e.g.1.1.1.1). I tried to assign it with our 3-component semver version but a zero 4th component appears in the GUI (See below). So, I think it's best to leave theFileVersionempty (which will be displayed as0.0.0.0) and just populate theProductVersionfield, which is fine. I've explained this in the script. Please let me know if you think it's worth having theFileVersionset.Verifying the binaries
To make sure the implementation is correct, I tried it with a simplified workflow that goes through the same steps as our deployment workflow, and then uploads the content of the
distdirectory as artifacts so you can download it and check the.exefiles. The workflow file is included at the end. You can run it on your own forks. However, make sure you're building the tag created from the last commit, otherwise the latest changes to the.goreleaser.ymlfile will not be used. By the way, this is the same workflow, ran on my own fork, and it's how the created.exelooks:For checking the
.exefiles, make sure you do it on Windows (through GUI or PowerShell). I don't know about macOS, but if you try PowerShell on Linux it will return an empty data structure (I learned this the hard way, 😄). Anyway, this is the PowerShell command to check the metadata being embedded:Sample workflow