Skip to content

Commit c82592e

Browse files
committed
Add support for windows-2025 runner images (#65)
1 parent b2fcdb9 commit c82592e

File tree

3 files changed

+122
-11
lines changed

3 files changed

+122
-11
lines changed

.github/workflows/test.main.kts

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import kotlin.math.min
5656
val environments = listOf(
5757
"windows-2019",
5858
"windows-2022",
59+
"windows-2025",
5960
"windows-latest"
6061
)
6162

.github/workflows/test.yaml

+35
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ jobs:
8686
environment:
8787
- 'windows-2019'
8888
- 'windows-2022'
89+
- 'windows-2025'
8990
- 'windows-latest'
9091
distribution:
9192
- user-id: 'invalid'
@@ -127,6 +128,7 @@ jobs:
127128
environment:
128129
- 'windows-2019'
129130
- 'windows-2022'
131+
- 'windows-2025'
130132
- 'windows-latest'
131133
wsl-version:
132134
- '-1'
@@ -167,6 +169,7 @@ jobs:
167169
environment:
168170
- 'windows-2019'
169171
- 'windows-2022'
172+
- 'windows-2025'
170173
- 'windows-latest'
171174
distribution:
172175
- wsl-id: 'Debian'
@@ -372,6 +375,7 @@ jobs:
372375
environment:
373376
- 'windows-2019'
374377
- 'windows-2022'
378+
- 'windows-2025'
375379
- 'windows-latest'
376380
distribution:
377381
- wsl-id: 'Debian'
@@ -936,6 +940,7 @@ jobs:
936940
environment:
937941
- 'windows-2019'
938942
- 'windows-2022'
943+
- 'windows-2025'
939944
- 'windows-latest'
940945
distribution:
941946
- wsl-id: 'Debian'
@@ -1045,6 +1050,7 @@ jobs:
10451050
environment:
10461051
- 'windows-2019'
10471052
- 'windows-2022'
1053+
- 'windows-2025'
10481054
- 'windows-latest'
10491055
distribution:
10501056
- wsl-id: 'Debian'
@@ -1190,6 +1196,7 @@ jobs:
11901196
environment:
11911197
- 'windows-2019'
11921198
- 'windows-2022'
1199+
- 'windows-2025'
11931200
- 'windows-latest'
11941201
distribution:
11951202
- wsl-id: 'Debian'
@@ -1326,6 +1333,7 @@ jobs:
13261333
matrix:
13271334
environment:
13281335
- 'windows-2022'
1336+
- 'windows-2025'
13291337
- 'windows-latest'
13301338
distribution:
13311339
- wsl-id: 'Debian'
@@ -1407,6 +1415,7 @@ jobs:
14071415
matrix:
14081416
environment:
14091417
- 'windows-2022'
1418+
- 'windows-2025'
14101419
- 'windows-latest'
14111420
steps:
14121421
- id: 'step-0'
@@ -1457,6 +1466,7 @@ jobs:
14571466
environment:
14581467
- 'windows-2019'
14591468
- 'windows-2022'
1469+
- 'windows-2025'
14601470
- 'windows-latest'
14611471
distribution:
14621472
- wsl-id: 'Debian'
@@ -1538,6 +1548,7 @@ jobs:
15381548
environment:
15391549
- 'windows-2019'
15401550
- 'windows-2022'
1551+
- 'windows-2025'
15411552
- 'windows-latest'
15421553
distributions:
15431554
- distribution1:
@@ -1694,6 +1705,7 @@ jobs:
16941705
environment:
16951706
- 'windows-2019'
16961707
- 'windows-2022'
1708+
- 'windows-2025'
16971709
- 'windows-latest'
16981710
distribution:
16991711
- wsl-id: 'Debian'
@@ -1760,6 +1772,17 @@ jobs:
17601772
user-id: 'Debian'
17611773
match-pattern: '*Debian*'
17621774
default-absent-tool: 'dos2unix'
1775+
- environment: 'windows-2025'
1776+
distribution:
1777+
wsl-id: 'Debian'
1778+
user-id: 'Debian'
1779+
match-pattern: '*Debian*'
1780+
default-absent-tool: 'dos2unix'
1781+
distribution2:
1782+
wsl-id: 'Debian'
1783+
user-id: 'Debian'
1784+
match-pattern: '*Debian*'
1785+
default-absent-tool: 'dos2unix'
17631786
- environment: 'windows-latest'
17641787
distribution:
17651788
wsl-id: 'Debian'
@@ -1794,6 +1817,17 @@ jobs:
17941817
user-id: 'Ubuntu-20.04'
17951818
match-pattern: '*Ubuntu*20.04*'
17961819
default-absent-tool: 'dos2unix'
1820+
- environment: 'windows-2025'
1821+
distribution:
1822+
wsl-id: 'Debian'
1823+
user-id: 'Debian'
1824+
match-pattern: '*Debian*'
1825+
default-absent-tool: 'dos2unix'
1826+
distribution2:
1827+
wsl-id: 'Ubuntu'
1828+
user-id: 'Ubuntu-20.04'
1829+
match-pattern: '*Ubuntu*20.04*'
1830+
default-absent-tool: 'dos2unix'
17971831
- environment: 'windows-latest'
17981832
distribution:
17991833
wsl-id: 'Debian'
@@ -1981,6 +2015,7 @@ jobs:
19812015
environment:
19822016
- 'windows-2019'
19832017
- 'windows-2022'
2018+
- 'windows-2025'
19842019
- 'windows-latest'
19852020
distributions:
19862021
- incompatibleUbuntu: 'Ubuntu-22.04'

src/jsMain/kotlin/net/kautler/github/action/setup_wsl/SetupWsl.kt

+86-11
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import actions.exec.ExecOptions
3737
import actions.exec.exec
3838
import actions.io.mkdirP
3939
import actions.io.mv
40+
import actions.io.rmRF
4041
import actions.io.which
4142
import actions.tool.cache.cacheDir
4243
import actions.tool.cache.downloadTool
@@ -57,16 +58,25 @@ import node.buffer.BufferEncoding
5758
import node.fs.exists
5859
import node.fs.mkdtemp
5960
import node.fs.readdir
61+
import node.fs.stat
6062
import node.fs.writeFile
6163
import node.os.tmpdir
6264
import node.path.path
6365
import node.process.Platform
6466
import node.process.process
6567
import nullwritable.NullWritable
6668
import org.w3c.dom.url.URL
69+
import kotlin.time.Duration
70+
import kotlin.time.Duration.Companion.minutes
6771
import kotlin.time.Duration.Companion.seconds
6872
import actions.tool.cache.extractZip as toolCacheExtractZip
6973

74+
private const val BAD_WSL_EXE_PATH =
75+
"C:\\Users\\runneradmin\\AppData\\Local\\Microsoft\\WindowsApps\\wsl.exe"
76+
77+
private const val BAD_WSLCONFIG_EXE_PATH =
78+
"C:\\Users\\runneradmin\\AppData\\Local\\Microsoft\\WindowsApps\\wslconfig.exe"
79+
7080
suspend fun wslOutput(vararg args: String): String {
7181
val stdoutBuilder = StringBuilder()
7282
val stdoutBuilderUtf16Le = StringBuilder()
@@ -101,10 +111,6 @@ val wslHelp = GlobalScope.async(start = LAZY) {
101111
wslOutput("--help")
102112
}
103113

104-
val wslStatus = GlobalScope.async(start = LAZY) {
105-
wslOutput("--status")
106-
}
107-
108114
val distribution by lazy {
109115
val distributionId = getInput("distribution", InputOptions(required = true))
110116

@@ -125,6 +131,10 @@ val wslId = GlobalScope.async(start = LAZY) {
125131
distribution.wslId
126132
}
127133

134+
val wslInstallationNeeded = GlobalScope.async(start = LAZY) {
135+
wslOutput("--status").contains("is not installed")
136+
}
137+
128138
val installationNeeded = GlobalScope.async(start = LAZY) {
129139
exec(
130140
commandLine = "wsl",
@@ -292,6 +302,12 @@ suspend fun main() {
292302
if (getInput("only safe actions").isEmpty()
293303
|| !getBooleanInput("only safe actions")
294304
) {
305+
// on windows-2025 WSL is not installed at all currently, so install it without distribution
306+
// work-around for https://github.com/actions/runner-images/issues/11265
307+
if (wslInstallationNeeded()) {
308+
group("Install WSL", ::installWsl)
309+
}
310+
295311
if (installationNeeded()) {
296312
group("Install Distribution", ::installDistribution)
297313
}
@@ -370,31 +386,90 @@ suspend fun verifyWindowsEnvironment() {
370386
}
371387
}
372388

389+
suspend fun installWsl() {
390+
// part of work-around for https://github.com/actions/toolkit/issues/1925
391+
val deleteWslExe =
392+
runCatching { stat(BAD_WSL_EXE_PATH).isFile() }
393+
.getOrDefault(false)
394+
.not()
395+
val deleteWslConfigExe =
396+
runCatching { stat(BAD_WSLCONFIG_EXE_PATH).isFile() }
397+
.getOrDefault(false)
398+
.not()
399+
400+
exec(
401+
commandLine = "pwsh",
402+
args = arrayOf("-Command", """Start-Process wsl "--install --no-distribution""""),
403+
options = ExecOptions(ignoreReturnCode = true)
404+
)
405+
406+
waitForWslStatusNotContaining("is not installed", 5.minutes) {
407+
// part of work-around for https://github.com/actions/toolkit/issues/1925
408+
if (deleteWslExe) {
409+
rmRF(BAD_WSL_EXE_PATH)
410+
}
411+
if (deleteWslConfigExe) {
412+
rmRF(BAD_WSLCONFIG_EXE_PATH)
413+
}
414+
}
415+
}
416+
373417
suspend fun installDistribution() {
374418
executeWslCommand(
375419
wslArguments = arrayOf("--set-default-version", "${wslVersion()}")
376420
)
421+
377422
if (wslVersion() != 1u) {
378-
retry(5) {
423+
// part of work-around for https://github.com/actions/toolkit/issues/1925
424+
val deleteWslExe =
425+
runCatching { stat(BAD_WSL_EXE_PATH).isFile() }
426+
.getOrDefault(false)
427+
.not()
428+
val deleteWslConfigExe =
429+
runCatching { stat(BAD_WSLCONFIG_EXE_PATH).isFile() }
430+
.getOrDefault(false)
431+
.not()
432+
433+
retry(10) {
379434
executeWslCommand(
380435
wslArguments = arrayOf("--update")
381436
)
382437
}
383438

384-
(2..30)
385-
.asFlow()
386-
.onEach { delay(1.seconds) }
387-
.onStart { emit(1) }
388-
.map { wslStatus() }
389-
.firstOrNull { !it.contains("WSL is finishing an upgrade...") }
439+
// part of work-around for https://github.com/actions/toolkit/issues/1925
440+
waitForWslStatusNotContaining("WSL is finishing an upgrade...") {
441+
if (deleteWslExe) {
442+
rmRF(BAD_WSL_EXE_PATH)
443+
}
444+
if (deleteWslConfigExe) {
445+
rmRF(BAD_WSLCONFIG_EXE_PATH)
446+
}
447+
}
390448
}
449+
391450
exec(
392451
commandLine = """"${path.join(distributionDirectory(), distribution.installerFile)}"""",
393452
args = arrayOf("install", "--root"),
394453
options = ExecOptions(input = Buffer.from(""))
395454
)
396455
}
397456

457+
suspend fun waitForWslStatusNotContaining(
458+
text: String,
459+
duration: Duration = 30.seconds,
460+
preAction: suspend () -> Unit = {}
461+
) {
462+
(2..duration.inWholeSeconds)
463+
.asFlow()
464+
.onEach { delay(1.seconds) }
465+
.onStart { emit(1) }
466+
.map {
467+
preAction()
468+
wslOutput("--status")
469+
}
470+
.firstOrNull { !it.contains(text) }
471+
}
472+
398473
suspend fun adjustWslConf() {
399474
exec(
400475
commandLine = "wsl",

0 commit comments

Comments
 (0)