Skip to content

Commit d259fc2

Browse files
authored
feat: allow Windows SDK version to be picked up from custom visual studio components (#372)
1 parent 82838c4 commit d259fc2

File tree

8 files changed

+142
-45
lines changed

8 files changed

+142
-45
lines changed

.github/workflows/main.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,8 @@ jobs:
379379
uses: `${repo}@${branch}`,
380380
with: {
381381
'swift-version': 'latest',
382-
'check-latest': '${{ needs.ci.outputs.check_latest }}'
382+
'check-latest': '${{ needs.ci.outputs.check_latest }}',
383+
'visual-studio-components': 'Microsoft.VisualStudio.Component.Windows11SDK.22621'
383384
}
384385
}
385386
]

__tests__/installer/windows.test.ts

+24-5
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ describe('windows toolchain installation verification', () => {
2828
catalog: {productDisplayVersion: '17'},
2929
properties: {
3030
setupEngineFilePath: path.join('C:', 'Visual Studio', 'setup.exe')
31-
}
31+
},
32+
components: [
33+
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
34+
'Microsoft.VisualStudio.Component.Windows11SDK.22621'
35+
]
3236
})
3337
const vsEnvs = [
3438
`UniversalCRTSdkDir=${path.join('C:', 'Windows Kits')}`,
@@ -46,16 +50,19 @@ describe('windows toolchain installation verification', () => {
4650
})
4751

4852
it('tests adding additional components', async () => {
53+
jest.spyOn(os, 'release').mockReturnValue('10.0.17063')
4954
jest
5055
.spyOn(core, 'getInput')
5156
.mockReturnValue(
5257
'Microsoft.VisualStudio.Component.VC.ATL;Microsoft.VisualStudio.Component.VC.CMake.Project;Microsoft.VisualStudio.Component.Windows10SDK'
5358
)
5459
const installer = new WindowsToolchainInstaller(toolchain)
55-
expect(installer['vsRequirement'].components.slice(2)).toStrictEqual([
60+
expect(installer['vsRequirement'].components).toStrictEqual([
61+
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
5662
'Microsoft.VisualStudio.Component.VC.ATL',
5763
'Microsoft.VisualStudio.Component.VC.CMake.Project',
58-
'Microsoft.VisualStudio.Component.Windows10SDK'
64+
'Microsoft.VisualStudio.Component.Windows10SDK',
65+
'Microsoft.VisualStudio.Component.Windows10SDK.17763'
5966
])
6067
})
6168

@@ -77,6 +84,18 @@ describe('windows toolchain installation verification', () => {
7784
])
7885
})
7986

87+
it('tests setting up on Windows 11 with custom SDK', async () => {
88+
jest.spyOn(os, 'release').mockReturnValue('10.0.26100')
89+
jest
90+
.spyOn(core, 'getInput')
91+
.mockReturnValue('Microsoft.VisualStudio.Component.Windows11SDK.22621')
92+
const installer = new WindowsToolchainInstaller(toolchain)
93+
expect(installer['vsRequirement'].components).toStrictEqual([
94+
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
95+
'Microsoft.VisualStudio.Component.Windows11SDK.22621'
96+
])
97+
})
98+
8099
it('tests download without caching', async () => {
81100
const installer = new WindowsToolchainInstaller(toolchain)
82101
expect(installer['version']).toStrictEqual(parseSemVer('5.8'))
@@ -181,7 +200,7 @@ describe('windows toolchain installation verification', () => {
181200
.mockResolvedValue()
182201
await installer['add']('')
183202
expect(setupSpy).toHaveBeenCalled()
184-
expect(updateSpy).toHaveBeenCalledWith('root', true)
203+
expect(updateSpy).toHaveBeenCalledWith('root')
185204
})
186205

187206
it('tests unpack for failed path matching without additional module setup', async () => {
@@ -231,7 +250,7 @@ describe('windows toolchain installation verification', () => {
231250
.mockResolvedValue()
232251
await installer['add']('')
233252
expect(setupSpy).toHaveBeenCalled()
234-
expect(updateSpy).toHaveBeenCalledWith('root', false)
253+
expect(updateSpy).toHaveBeenCalledWith('root')
235254
})
236255

237256
it('tests add to PATH', async () => {

__tests__/utils/visual_studio/setup.test.ts

+36-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as path from 'path'
22
import {promises as fs} from 'fs'
3+
import os from 'os'
34
import * as exec from '@actions/exec'
45
import {VisualStudio} from '../../../src/utils/visual_studio'
56

@@ -11,7 +12,11 @@ describe('visual studio setup validation', () => {
1112
catalog: {productDisplayVersion: '17'},
1213
properties: {
1314
setupEngineFilePath: path.join('C:', 'Visual Studio', 'setup.exe')
14-
}
15+
},
16+
components: [
17+
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
18+
'Microsoft.VisualStudio.Component.Windows11SDK.22621'
19+
]
1520
})
1621

1722
beforeEach(() => {
@@ -33,7 +38,7 @@ describe('visual studio setup validation', () => {
3338
stderr: ''
3439
})
3540
await expect(
36-
VisualStudio.setup({version: '16', components: ['Component']})
41+
VisualStudio.setup({version: '16', components: visualStudio.components})
3742
).rejects.toMatchObject(
3843
new Error(
3944
`Unable to find any Visual Studio installation for version: 16.`
@@ -51,7 +56,35 @@ describe('visual studio setup validation', () => {
5156
stderr: ''
5257
})
5358
await expect(
54-
VisualStudio.setup({version: '16', components: ['Component']})
59+
VisualStudio.setup({version: '16', components: visualStudio.components})
5560
).resolves.toMatchObject(visualStudio)
5661
})
62+
63+
it('tests visual studio environment setup', async () => {
64+
jest.spyOn(os, 'arch').mockReturnValue('x64')
65+
const execSpy = jest.spyOn(exec, 'getExecOutput').mockResolvedValue({
66+
exitCode: 0,
67+
stdout: '',
68+
stderr: ''
69+
})
70+
await visualStudio.env()
71+
const arg = execSpy.mock.calls.at(0)
72+
expect(arg).toBeTruthy()
73+
expect(arg?.[0]).toBe('cmd')
74+
expect(arg?.[1]).toStrictEqual([
75+
'/k',
76+
path.join(
77+
visualStudio.installationPath,
78+
'Common7',
79+
'Tools',
80+
'VsDevCmd.bat'
81+
),
82+
'-arch=x64',
83+
'-winsdk=10.0.22621.0',
84+
'&&',
85+
'set',
86+
'&&',
87+
'exit'
88+
])
89+
})
5790
})

dist/index.js

+36-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/installer/windows/index.ts

+16-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as core from '@actions/core'
55
import * as semver from 'semver'
66
import {VerifyingToolchainInstaller} from '../verify'
77
import {WindowsToolchainSnapshot} from '../../snapshot'
8-
import {VisualStudio} from '../../utils'
8+
import {VisualStudio, VISUAL_STUDIO_WINSDK_COMPONENT_REGEX} from '../../utils'
99
import {Installation, CustomInstallation} from './installation'
1010

1111
export class WindowsToolchainInstaller extends VerifyingToolchainInstaller<WindowsToolchainSnapshot> {
@@ -22,14 +22,23 @@ export class WindowsToolchainInstaller extends VerifyingToolchainInstaller<Windo
2222
private get vsRequirement() {
2323
const componentsStr = core.getInput('visual-studio-components')
2424
const providedComponents = componentsStr ? componentsStr.split(';') : []
25+
const winsdkComponent = providedComponents.find(component => {
26+
return (
27+
(VISUAL_STUDIO_WINSDK_COMPONENT_REGEX.exec(component)?.length ?? 0) > 1
28+
)
29+
})
30+
31+
const vsComponents = [
32+
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
33+
...providedComponents
34+
]
35+
if (!winsdkComponent) {
36+
vsComponents.push(this.winsdk)
37+
}
2538
return {
2639
version: '16',
2740
swift: this.version,
28-
components: [
29-
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
30-
this.winsdk,
31-
...providedComponents
32-
]
41+
components: vsComponents
3342
}
3443
}
3544

@@ -89,10 +98,7 @@ export class WindowsToolchainInstaller extends VerifyingToolchainInstaller<Windo
8998
}
9099

91100
const visualStudio = await VisualStudio.setup(this.vsRequirement)
92-
await visualStudio.update(
93-
sdkroot,
94-
!this.version || semver.lt(this.version, '6.0.0')
95-
)
101+
await visualStudio.update(sdkroot)
96102
const swiftFlags = [
97103
'-sdk',
98104
sdkroot,

src/utils/visual_studio/base.ts

+22-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ import * as os from 'os'
22
import * as path from 'path'
33
import {getExecOutput} from '@actions/exec'
44

5+
export const VISUAL_STUDIO_WINSDK_COMPONENT_REGEX =
6+
/Microsoft\.VisualStudio\.Component\.Windows[0-9]+SDK\.([0-9]+)/
7+
58
export class VisualStudio {
69
private constructor(
710
readonly installationPath: string,
811
readonly installationVersion: string,
912
readonly catalog: VisualStudioCatalog,
10-
readonly properties: VisualStudioProperties
13+
readonly properties: VisualStudioProperties,
14+
readonly components: string[]
1115
) {}
1216

1317
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -16,7 +20,8 @@ export class VisualStudio {
1620
json.installationPath,
1721
json.installationVersion,
1822
json.catalog,
19-
json.properties
23+
json.properties,
24+
json.components
2025
)
2126
}
2227

@@ -28,12 +33,27 @@ export class VisualStudio {
2833
'Tools',
2934
'VsDevCmd.bat'
3035
)
36+
37+
const args = []
38+
const sdkComponentMatch = this.components
39+
.map(component => {
40+
return VISUAL_STUDIO_WINSDK_COMPONENT_REGEX.exec(component)
41+
})
42+
.filter(match => {
43+
return match && match.length > 1
44+
})
45+
.at(0)
46+
if (sdkComponentMatch) {
47+
args.push(`-winsdk=10.0.${sdkComponentMatch[1]}.0`)
48+
}
49+
3150
const {stdout} = await getExecOutput(
3251
'cmd',
3352
[
3453
'/k',
3554
nativeToolsScriptx86,
3655
`-arch=${os.arch()}`,
56+
...args,
3757
'&&',
3858
'set',
3959
'&&',

src/utils/visual_studio/setup.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ VisualStudio.setup = async function (requirement: VisualStudioRequirement) {
3535
'-version',
3636
requirement.version
3737
])
38-
const vs = VisualStudio.createFromJSON(JSON.parse(stdout)[0])
38+
const vs = VisualStudio.createFromJSON({
39+
...JSON.parse(stdout)[0],
40+
components: requirement.components
41+
})
3942
if (!vs.installationPath) {
4043
throw new Error(
4144
`Unable to find any Visual Studio installation for version: ${requirement.version}.`

0 commit comments

Comments
 (0)