1
0
mirror of https://github.com/dockur/windows.git synced 2026-07-27 21:42:36 +07:00

Compare commits

...

31 Commits

Author SHA1 Message Date
Kroese 6be5570cfc Update install.yml 2026-07-27 14:43:26 +02:00
Kroese ed44aea5f8 Update validate.yml 2026-07-27 14:02:43 +02:00
Kroese 12161b51ed Update install.yml 2026-07-27 13:48:09 +02:00
Kroese 02795f2009 Update install.yml 2026-07-27 13:22:56 +02:00
Kroese 2fb6f9c149 Update validate.yml 2026-07-27 13:19:43 +02:00
Kroese a4da9b6d59 Update links.yml 2026-07-27 13:11:57 +02:00
Kroese 3b53688d93 Update install.yml 2026-07-27 11:58:24 +02:00
Kroese f166298c6e Update install.yml 2026-07-27 11:46:42 +02:00
Kroese d4a5f462e4 Update validate.yml 2026-07-27 11:09:20 +02:00
Kroese a96db30599 Update install.yml 2026-07-27 11:08:41 +02:00
Kroese 68b121a4f0 Update validate.yml 2026-07-27 11:06:04 +02:00
Kroese 68c1d57cfd Update validate.yml 2026-07-27 11:04:37 +02:00
Kroese 2a5e3519ed Update install.yml 2026-07-27 11:04:18 +02:00
Kroese 9e834ff359 Update install.yml 2026-07-27 03:06:40 +02:00
Kroese fb320b06e8 Update install.yml 2026-07-27 02:56:27 +02:00
Kroese 5271489998 Update install.yml 2026-07-27 01:43:10 +02:00
Kroese dcfa51f337 Update install.yml 2026-07-27 01:28:22 +02:00
Kroese 0fc0ac30ec Update install.yml 2026-07-27 01:22:59 +02:00
Kroese b60e59a236 Update install.yml 2026-07-27 01:17:08 +02:00
Kroese 6301211c62 Update install.yml 2026-07-27 01:07:53 +02:00
Kroese 86631059fb Update install.yml 2026-07-27 00:51:25 +02:00
Kroese 57ed97f5e5 Update validate.yml 2026-07-27 00:19:18 +02:00
Kroese 4a9e5bbee5 Update install.yml 2026-07-27 00:18:17 +02:00
Kroese 10ef198ddd Update install.yml 2026-07-27 00:12:56 +02:00
Kroese 5327694d06 Update install.yml 2026-07-26 21:55:49 +02:00
Kroese 5287b0ba85 fix: Detect IA32-only EFI media as legacy (#1998) 2026-07-26 21:06:40 +02:00
Kroese f6fcb46958 build: Update workflows (#1996) 2026-07-26 20:37:20 +02:00
Kroese 4fdc3f0428 docs: List Tiny versions (#1997) 2026-07-26 20:36:28 +02:00
Kroese 16f763912b fix: Use qemu32 for Vista x86 and Win7 x86 (#1995) 2026-07-26 19:44:18 +02:00
Kroese e00d1aead1 fix: Use qemu32 for x86 Windows versions (#1994) 2026-07-26 18:09:58 +02:00
Kroese 78ba661605 fix: Default to IDE disk for 32-bit WinXP versions (#1993) 2026-07-26 17:43:59 +02:00
5 changed files with 589 additions and 327 deletions
+416 -76
View File
@@ -19,10 +19,10 @@ on:
default: ubuntu-24.04
type: string
image:
description: Container image to test
branch:
description: Repository branch to build
required: false
default: ghcr.io/dockur/windows:latest
default: dev
type: string
callback:
@@ -31,12 +31,42 @@ on:
default: powershell
type: string
machine:
description: QEMU machine type exposed to Windows
required: false
default: q35
type: string
cpu:
description: CPU model exposed to Windows
required: false
default: host
default: ""
type: string
cpu_flags:
description: Additional CPU flags exposed to Windows
required: false
default: ""
type: string
disk_type:
description: Disk controller type exposed to Windows
required: false
default: ""
type: string
network:
description: Network backend exposed to Windows
required: false
default: ""
type: string
kill_on_failure:
description: Stop the workflow when an installation failure is detected
required: false
default: false
type: boolean
expected_caption:
description: Text expected in the Windows caption
required: true
@@ -69,9 +99,45 @@ jobs:
env:
CONTAINER: windows-test
IMAGE: ${{ inputs.image }}
IMAGE: windows-validation:local
TUNNEL: windows-test-tunnel
steps:
- name: Resolve branch
id: branch
shell: bash
env:
REQUESTED_BRANCH: ${{ inputs.branch }}
GITHUB_TOKEN: ${{ github.token }}
run: |
set -Eeuo pipefail
authorization="$(
printf 'x-access-token:%s' "$GITHUB_TOKEN" |
base64 -w 0
)"
if git \
-c "http.extraheader=Authorization: basic $authorization" \
ls-remote \
--exit-code \
--heads \
"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git" \
"refs/heads/$REQUESTED_BRANCH" > /dev/null 2>&1; then
branch="$REQUESTED_BRANCH"
else
branch="master"
echo "Branch '$REQUESTED_BRANCH' does not exist; using '$branch'."
fi
echo "branch=$branch" >> "$GITHUB_OUTPUT"
- name: Checkout branch
uses: actions/checkout@v7
with:
ref: ${{ steps.branch.outputs.branch }}
- name: Check KVM
shell: bash
run: |
@@ -146,6 +212,81 @@ jobs:
printf '%s\n' "$token" > "$RUNNER_TEMP/data/readme.txt"
cat > "$RUNNER_TEMP/oem/sync-log.bat" <<'BATCH'
@echo off
setlocal
:sync
if exist C:\OEM\install.log (
copy /Y C:\OEM\install.log \\host.lan\Data\install.tmp >nul 2>&1
if not errorlevel 1 (
move /Y \\host.lan\Data\install.tmp \\host.lan\Data\install.log >nul 2>&1
)
)
if /I "%~1"=="once" exit /B
if exist C:\OEM\install.done exit /B
ping 127.0.0.1 -n 6 >nul
goto sync
BATCH
cat > "$RUNNER_TEMP/oem/shutdown.vbs" <<'VBSCRIPT'
On Error Resume Next
Dim service
Dim systems
Dim system
Set service = GetObject("winmgmts:{impersonationLevel=impersonate,(Shutdown)}!\\.\root\cimv2")
Set systems = service.ExecQuery("SELECT * FROM Win32_OperatingSystem")
For Each system In systems
system.Win32Shutdown 5
Next
VBSCRIPT
cat > "$RUNNER_TEMP/oem/watchdog.vbs" <<'VBSCRIPT'
Option Explicit
Const ForAppending = 8
Dim filesystem
Dim file
Dim shell
Dim service
Dim systems
Dim system
WScript.Sleep 180000
Set filesystem = CreateObject("Scripting.FileSystemObject")
If filesystem.FileExists("C:\OEM\install.done") Then
WScript.Quit 0
End If
On Error Resume Next
Set file = filesystem.OpenTextFile("C:\OEM\install.log", ForAppending, True)
file.WriteLine Now & " - Callback failed for 3 minutes."
file.Close
Set file = filesystem.CreateTextFile("C:\OEM\install.done", True)
file.Close
Set shell = CreateObject("WScript.Shell")
shell.Run "shutdown.exe -s -f -t 0", 0, False
Set service = GetObject("winmgmts:{impersonationLevel=impersonate,(Shutdown)}!\\.\root\cimv2")
Set systems = service.ExecQuery("SELECT * FROM Win32_OperatingSystem")
For Each system In systems
system.Win32Shutdown 5
Next
VBSCRIPT
case "$CALLBACK" in
powershell)
cat > "$RUNNER_TEMP/oem/ready.ps1" <<'POWERSHELL'
@@ -156,29 +297,29 @@ jobs:
$ErrorActionPreference = "Stop"
$windows = Get-CimInstance Win32_OperatingSystem
$registry = Get-ItemProperty `
"HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
$platform = switch (
$env:PROCESSOR_ARCHITECTURE.ToUpperInvariant()
) {
"AMD64" {
"x64"
}
"ARM64" {
"arm64"
}
"X86" {
"x86"
}
default {
$env:PROCESSOR_ARCHITECTURE.ToLowerInvariant()
}
}
while ($true) {
try {
$windows = Get-CimInstance Win32_OperatingSystem
$registry = Get-ItemProperty `
"HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
$platform = switch (
$env:PROCESSOR_ARCHITECTURE.ToUpperInvariant()
) {
"AMD64" {
"x64"
}
"ARM64" {
"arm64"
}
"X86" {
"x86"
}
default {
$env:PROCESSOR_ARCHITECTURE.ToLowerInvariant()
}
}
$share = (
Get-Content `
-LiteralPath "\\host.lan\Data\readme.txt" `
@@ -214,6 +355,7 @@ jobs:
break
}
catch {
Write-Output "$(Get-Date -Format s) - Callback retry: $($_.Exception.Message)"
Start-Sleep -Seconds 10
}
}
@@ -221,9 +363,27 @@ jobs:
cat > "$RUNNER_TEMP/oem/install.bat" <<EOF
@echo off
del /Q C:\OEM\install.done 2>nul
start "" /B cmd.exe /C C:\OEM\sync-log.bat
start "" /B cscript.exe //B //NoLogo C:\OEM\watchdog.vbs
powershell.exe -NoProfile -ExecutionPolicy Bypass ^
-File C:\OEM\ready.ps1 ^
-Token "$token"
set "result=%errorlevel%"
if not "%result%"=="0" (
echo %date% %time% - Callback failed.>>C:\OEM\install.log
type nul > C:\OEM\install.done
shutdown.exe -s -f -t 0 >nul 2>&1
if errorlevel 1 cscript.exe //B //NoLogo C:\OEM\shutdown.vbs
exit /B %result%
)
type nul > C:\OEM\install.done
call C:\OEM\sync-log.bat once
exit /B %result%
EOF
;;
@@ -327,34 +487,41 @@ jobs:
Dim temporary
Dim destination
Dim file
Set filesystem = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")
Set locator = CreateObject("WbemScripting.SWbemLocator")
Set service = locator.ConnectServer(".", "root\cimv2")
Set systems = service.ExecQuery("SELECT Caption, Version, BuildNumber FROM Win32_OperatingSystem")
caption = ""
version = ""
build = ""
For Each system In systems
caption = CStr(system.Caption)
version = CStr(system.Version)
build = CStr(system.BuildNumber)
Exit For
Next
edition = ReadRegistry(shell, "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EditionID")
platform = GetPlatform(shell)
Dim success
temporary = "\\host.lan\Data\windows.tmp"
destination = "\\host.lan\Data\windows.json"
Do
On Error Resume Next
success = False
share = ReadTextFile(filesystem, "\\host.lan\Data\readme.txt")
On Error Resume Next
Err.Clear
Set filesystem = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")
Set locator = CreateObject("WbemScripting.SWbemLocator")
Set service = locator.ConnectServer(".", "root\cimv2")
Set systems = service.ExecQuery("SELECT Caption, Version, BuildNumber FROM Win32_OperatingSystem")
caption = ""
version = ""
build = ""
If Err.Number = 0 Then
For Each system In systems
caption = CStr(system.Caption)
version = CStr(system.Version)
build = CStr(system.BuildNumber)
Exit For
Next
End If
If Err.Number = 0 Then
edition = ReadRegistry(shell, "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EditionID")
platform = GetPlatform(shell)
share = ReadTextFile(filesystem, "\\host.lan\Data\readme.txt")
End If
If Err.Number = 0 Then
json = _
@@ -371,7 +538,9 @@ jobs:
Set file = filesystem.OpenTextFile(temporary, ForWriting, True)
file.Write json
file.Close
End If
If Err.Number = 0 Then
If filesystem.FileExists(destination) Then
filesystem.DeleteFile destination, True
End If
@@ -380,47 +549,91 @@ jobs:
End If
If Err.Number = 0 Then
On Error GoTo 0
Exit Do
success = True
Else
WScript.Echo _
Now & _
" - Callback retry: 0x" & _
Hex(Err.Number) & _
" - " & _
Err.Description
End If
Err.Clear
On Error GoTo 0
If success Then
Exit Do
End If
WScript.Sleep 10000
Loop
VBSCRIPT
cat > "$RUNNER_TEMP/oem/install.bat" <<EOF
@echo off
del /Q C:\OEM\install.done 2>nul
start "" /B cmd.exe /C C:\OEM\sync-log.bat
start "" /B cscript.exe //B //NoLogo C:\OEM\watchdog.vbs
cscript.exe //B //NoLogo C:\OEM\ready.vbs "$token"
set "result=%errorlevel%"
if not "%result%"=="0" (
echo %date% %time% - Callback failed.>>C:\OEM\install.log
type nul > C:\OEM\install.done
shutdown.exe -s -f -t 0 >nul 2>&1
if errorlevel 1 cscript.exe //B //NoLogo C:\OEM\shutdown.vbs
exit /B %result%
)
type nul > C:\OEM\install.done
call C:\OEM\sync-log.bat once
exit /B %result%
EOF
;;
esac
echo "token=$token" >> "$GITHUB_OUTPUT"
- name: Pull image
- name: Build image
shell: bash
run: |
set -Eeuo pipefail
docker pull "$IMAGE"
echo "Building branch: ${{ steps.branch.outputs.branch }}"
echo "Commit: $(git rev-parse HEAD)"
for attempt in 1 2 3; do
if docker build \
--tag "$IMAGE" \
.; then
break
fi
if (( attempt == 3 )); then
echo "Image build failed after $attempt attempts."
exit 1
fi
delay=$((attempt * 15))
echo "Image build failed, retrying in $delay seconds..."
sleep "$delay"
done
docker image inspect "$IMAGE" \
--format 'Digest: {{index .RepoDigests 0}}'
--format 'Image ID: {{.Id}}'
- name: Install and validate Windows
- name: Start Windows container
shell: bash
env:
CPU: ${{ inputs.cpu }}
EXPECTED_TOKEN: ${{ steps.test.outputs.token }}
EXPECTED_CAPTION: ${{ inputs.expected_caption }}
EXPECTED_EDITION: ${{ inputs.expected_edition }}
EXPECTED_PLATFORM: ${{ inputs.platform }}
MINIMUM_BUILD: ${{ inputs.minimum_build }}
CPU_FLAGS: ${{ inputs.cpu_flags }}
DISK_TYPE: ${{ inputs.disk_type }}
MACHINE: ${{ inputs.machine }}
NETWORK: ${{ inputs.network }}
VERSION: ${{ inputs.version }}
DISPLAY_NAME: ${{ inputs.name }}
run: |
set -Eeuo pipefail
@@ -430,16 +643,83 @@ jobs:
--device /dev/net/tun \
--cap-add NET_ADMIN \
--stop-timeout 120 \
--env "MACHINE=$MACHINE" \
--env "VERSION=$VERSION" \
--env "RAM_SIZE=half" \
--env "CPU_CORES=half" \
--env "CPU_MODEL=$CPU" \
--env "DISK_SIZE=64G" \
--env "CPU_MODEL=$CPU" \
--env "CPU_FLAGS=$CPU_FLAGS" \
--env "DISK_TYPE=$DISK_TYPE" \
--env "NETWORK=$NETWORK" \
--env "LOG=Y" \
--env "DEBUG=Y" \
--volume "$RUNNER_TEMP/data:/shared" \
--volume "$RUNNER_TEMP/oem:/oem:ro" \
--volume "$RUNNER_TEMP/storage:/storage" \
"$IMAGE"
- name: Start noVNC tunnel
id: tunnel
shell: bash
run: |
set -Eeuo pipefail
if docker run --detach \
--name "$TUNNEL" \
--network "container:$CONTAINER" \
cloudflare/cloudflared:latest \
tunnel \
--no-autoupdate \
--url http://127.0.0.1:8006 > /dev/null 2>/dev/null; then
novnc_url=""
for _ in {1..30}; do
novnc_url="$(
docker logs "$TUNNEL" 2>&1 |
grep -Eo 'https://[-a-z0-9]+\.trycloudflare\.com' |
tail -n 1 || true
)"
[ -n "$novnc_url" ] && break
sleep 2
done
if [ -n "$novnc_url" ]; then
echo
echo "::notice title=noVNC viewer::$novnc_url"
echo "noVNC viewer: $novnc_url"
echo "Warning: this temporary URL is publicly accessible."
echo "url=$novnc_url" >> "$GITHUB_OUTPUT"
{
echo "### noVNC viewer"
echo
echo "[$novnc_url]($novnc_url)"
echo
echo "> This temporary URL is publicly accessible while the job is running."
} >> "$GITHUB_STEP_SUMMARY"
else
echo "::warning::Failed to obtain a noVNC tunnel URL."
docker logs "$TUNNEL" 2>&1 || true
fi
else
echo "::warning::Failed to start the noVNC tunnel."
fi
- name: Install and validate Windows
shell: bash
env:
KILL_ON_FAILURE: ${{ inputs.kill_on_failure }}
EXPECTED_TOKEN: ${{ steps.test.outputs.token }}
EXPECTED_CAPTION: ${{ inputs.expected_caption }}
EXPECTED_EDITION: ${{ inputs.expected_edition }}
EXPECTED_PLATFORM: ${{ inputs.platform }}
MINIMUM_BUILD: ${{ inputs.minimum_build }}
DISPLAY_NAME: ${{ inputs.name }}
run: |
set -Eeuo pipefail
echo
echo "Container log:"
echo "------------------------------------------------------------"
@@ -450,18 +730,61 @@ jobs:
"$CONTAINER" &
logs_pid="$!"
guest_log="$RUNNER_TEMP/data/install.log"
(
offset=0
snapshot="$RUNNER_TEMP/install-log.snapshot"
while true; do
if cp "$guest_log" "$snapshot" 2>/dev/null; then
size="$(stat -c %s "$snapshot" 2>/dev/null || echo 0)"
if (( size < offset )); then
offset=0
fi
if (( size > offset )); then
tail -c "+$((offset + 1))" "$snapshot" 2>/dev/null |
sed -u 's/^/[install.bat] /' || true
offset="$size"
fi
fi
sleep 2
done
) &
guest_logs_pid="$!"
stop_logs() {
kill "$logs_pid" 2>/dev/null || true
wait "$logs_pid" 2>/dev/null || true
kill "$logs_pid" "$guest_logs_pid" 2>/dev/null || true
wait "$logs_pid" "$guest_logs_pid" 2>/dev/null || true
}
trap stop_logs EXIT
failure_checks_disabled=0
handle_failure() {
local message="$1"
if [[ "$KILL_ON_FAILURE" == "true" ]]; then
return 1
fi
echo
echo "Automatic termination is disabled by kill_on_failure."
echo "The container and noVNC tunnel will remain available."
echo "::warning title=Failure detected::$message"
failure_checks_disabled=1
return 0
}
deadline=$((SECONDS + 9000))
reboot_timeout=1800
minimum_reboots=1
boot_loop_limit=5
boot_loop_limit=10
first_bios_start=-1
while (( SECONDS < deadline )); do
@@ -481,22 +804,30 @@ jobs:
container_log="$(docker logs "$CONTAINER" 2>&1 || true)"
if grep -Eqi \
'KVM internal error|KVM: entry failed|hardware error 0x[0-9a-f]+|Triple fault' \
<<< "$container_log"; then
if (( failure_checks_disabled == 0 )) &&
grep -Eqi \
'KVM internal error|KVM: entry failed|hardware error 0x[0-9a-f]+|Triple fault' \
<<< "$container_log"; then
echo
echo "------------------------------------------------------------"
echo "Detected a fatal QEMU or KVM error."
exit 1
if ! handle_failure "Detected a fatal QEMU or KVM error."; then
exit 1
fi
fi
if grep -Eqi \
'CDBOOT: Cannot boot from CD.*Code: 5' \
<<< "$container_log"; then
if (( failure_checks_disabled == 0 )) &&
grep -Eqi \
'CDBOOT: Cannot boot from CD.*Code: 5' \
<<< "$container_log"; then
echo
echo "------------------------------------------------------------"
echo "The installation media could not be booted."
exit 1
if ! handle_failure "The installation media could not be booted."; then
exit 1
fi
fi
bios_starts="$(
@@ -537,7 +868,8 @@ jobs:
first_bios_start=$SECONDS
fi
if (( first_bios_start >= 0 &&
if (( failure_checks_disabled == 0 &&
first_bios_start >= 0 &&
SECONDS - first_bios_start >= reboot_timeout &&
reboots < minimum_reboots )); then
echo
@@ -546,10 +878,14 @@ jobs:
"$((reboot_timeout / 60)) minutes after the first BIOS start."
echo "Observed reboots: $reboots"
echo "Required reboots: $minimum_reboots"
exit 1
if ! handle_failure "The installation did not reboot in time."; then
exit 1
fi
fi
if (( bios_starts >= boot_loop_limit )) &&
if (( failure_checks_disabled == 0 &&
bios_starts >= boot_loop_limit )) &&
(( hard_disk_boots >= boot_loop_limit ||
dvd_boots >= boot_loop_limit ||
not_bootable_disk >= boot_loop_limit ||
@@ -566,7 +902,10 @@ jobs:
echo "Unreadable boot-disk failures: $unreadable_boot_disk"
echo "No-bootable-device failures: $no_bootable_device"
echo "BOOTMGR failures: $bootmgr_missing"
exit 1
if ! handle_failure "Detected a repeated BIOS boot loop."; then
exit 1
fi
fi
response=""
@@ -677,4 +1016,5 @@ jobs:
if: always()
shell: bash
run: |
docker rm --force "$TUNNEL" 2>/dev/null || true
docker rm --force "$CONTAINER" 2>/dev/null || true
+107 -17
View File
@@ -23,12 +23,18 @@ jobs:
uses: actions/checkout@v7
with:
fetch-depth: 0
-
name: Install aria2
run: |
if ! command -v aria2c > /dev/null; then
sudo apt-get update -qq
sudo apt-get install -qq --no-install-recommends -y aria2
fi
-
name: Validate all download mirrors
id: validate
run: |
errors=0
skipped=0
tested=0
host=""
failed_links=""
@@ -37,21 +43,108 @@ jobs:
ignored_domains=(
files.dog
bobpony.com
)
wget https://github.com/lwthiker/curl-impersonate/releases/download/v0.6.1/curl-impersonate-v0.6.1.x86_64-linux-gnu.tar.gz
tar -xzf curl-impersonate-v0.6.1.x86_64-linux-gnu.tar.gz
sudo cp curl-impersonate-ff /usr/local/bin/
check() {
local url="$1" http
local url="$1"
local agent="Mozilla/5.0 (X11; Linux x86_64; rv:154.0) Gecko/20100101 Firefox/154.0"
local tmp output pid blocks bytes rc status delay
local attempt=1
local attempts=3
local start
http=$(curl-impersonate-ff -sSL -o /dev/null -w "%{http_code}" --max-time 10 -I -- "$url" 2>&1) || http="000"
[[ "$http" == 2* ]] && return 0
tmp=$(mktemp -d)
http=$(curl-impersonate-ff -sSL -o /dev/null -w "%{http_code}" --max-time 10 -r "0-0" -- "$url" 2>&1) || http="000"
[[ "$http" == 2* ]]
while (( attempt <= attempts )); do
output="$tmp/aria2.log"
rm -f -- "$tmp/probe" "$tmp/probe.aria2" "$output"
start=$SECONDS
aria2c \
--no-conf=true \
--connect-timeout=30 \
--timeout=30 \
--max-tries=2 \
--retry-wait=2 \
--async-dns=false \
--follow-metalink=false \
--follow-torrent=false \
--user-agent="$agent" \
--split=4 \
--max-connection-per-server=4 \
--file-allocation=none \
--allow-overwrite=true \
--auto-file-renaming=false \
--continue=false \
--dir="$tmp" \
--out=probe \
--console-log-level=error \
--summary-interval=0 \
--download-result=hide \
--show-console-readout=false \
--enable-color=false \
-- "$url" > "$output" 2>&1 &
pid=$!
while kill -0 "$pid" 2>/dev/null; do
if [[ -f "$tmp/probe" ]]; then
blocks=$(stat -c '%b' "$tmp/probe" 2>/dev/null || echo 0)
bytes=$((blocks * 512))
if (( bytes >= 1048576 )); then
kill "$pid" 2>/dev/null || true
wait "$pid" 2>/dev/null || true
rm -rf -- "$tmp"
return 0
fi
fi
if (( SECONDS - start >= 60 )); then
kill "$pid" 2>/dev/null || true
break
fi
sleep 0.2
done
if wait "$pid"; then
rc=0
else
rc=$?
fi
blocks=0
if [[ -f "$tmp/probe" ]]; then
blocks=$(stat -c '%b' "$tmp/probe" 2>/dev/null || echo 0)
fi
bytes=$((blocks * 512))
if (( bytes >= 1048576 || (rc == 0 && bytes > 0) )); then
rm -rf -- "$tmp"
return 0
fi
status=$(sed -n 's/.*status=\([0-9][0-9][0-9]\).*/\1/p' "$output" | tail -n 1)
if (( attempt < attempts )) && [[ "$status" == "429" || "$status" == 5?? ]]; then
delay=$((attempt * 15))
echo " HTTP ${status}, retrying in ${delay} seconds..." >&2
sleep "$delay"
attempt=$((attempt + 1))
continue
fi
sed 's/^/ /' "$output" >&2
echo " Downloaded bytes: $bytes" >&2
echo " aria2c exit status: $rc" >&2
rm -rf -- "$tmp"
return 1
done
rm -rf -- "$tmp"
return 1
}
isIgnoredDomain() {
@@ -93,8 +186,7 @@ jobs:
seen[$url]=1
if isIgnoredDomain "$url"; then
echo "SKIP: $url (ignored domain)"
skipped=$((skipped + 1))
echo "SKIP: $url"
continue
fi
@@ -108,15 +200,13 @@ jobs:
failed_links+="$url"$'\n'
failed_links_html+="<li><a href=\"$url\">$url</a></li>"$'\n'
fi
sleep 2
done < "src/define.sh"
echo ""
printf '%d/%d tested links valid\n' "$((tested - errors))" "$tested"
if (( skipped > 0 )); then
printf '%d link(s) skipped for ignored domains\n' "$skipped"
fi
if (( errors > 0 )); then
printf '%d blocking failure(s)\n' "$errors"
+37 -217
View File
@@ -1,4 +1,4 @@
name: Validation
name: XP Validation
on:
release:
@@ -11,239 +11,59 @@ permissions:
contents: read
concurrency:
group: validation-${{ github.ref }}
group: xp-validation-${{ github.ref }}
cancel-in-progress: true
jobs:
desktop:
xp:
strategy:
fail-fast: false
matrix:
include:
- name: Windows 11 Pro
version: "11"
expected_caption: Windows 11
expected_edition: Professional
minimum_build: 22000
platform: x64
- name: host + no OSVW
cpu: host
cpu_flags: osvw=off
- name: Windows 11 LTSC
version: "11l"
expected_caption: Windows 11
expected_edition: EnterpriseS
minimum_build: 26100
platform: x64
- name: host + no AMD legacy features
cpu: host
cpu_flags: osvw=off,topoext=off,cr8legacy=off,svm=off,x2apic=off
- name: Windows 11 Enterprise
version: "11e"
expected_caption: Windows 11
expected_edition: Enterprise
minimum_build: 22000
platform: x64
- name: qemu32
cpu: qemu32
cpu_flags: ""
- name: Windows 11 IoT Enterprise
version: "11i"
expected_caption: Windows 11
expected_edition: IoTEnterpriseS
minimum_build: 26100
platform: x64
- name: kvm32
cpu: kvm32
cpu_flags: ""
- name: Windows 10 Pro
version: "10"
expected_caption: Windows 10
expected_edition: Professional
minimum_build: 10240
platform: x64
- name: Opteron G1
cpu: Opteron_G1
cpu_flags: ""
- name: Windows 10 LTSC
version: "10l"
expected_caption: Windows 10
expected_edition: EnterpriseS
minimum_build: 17763
platform: x64
- name: Opteron G2
cpu: Opteron_G2
cpu_flags: ""
- name: Windows 10 Enterprise
version: "10e"
expected_caption: Windows 10
expected_edition: Enterprise
minimum_build: 10240
platform: x64
- name: Opteron G3
cpu: Opteron_G3
cpu_flags: ""
- name: Windows 10 IoT Enterprise
version: "10i"
expected_caption: Windows 10
expected_edition: IoTEnterpriseS
minimum_build: 19044
platform: x64
- name: host
cpu: host
cpu_flags: ""
- name: Windows 8.1 Enterprise
version: "8e"
expected_caption: Windows 8.1
expected_edition: Enterprise
minimum_build: 9600
platform: x64
name: Windows XP x86 - ${{ matrix.name }}
name: ${{ matrix.name }}
uses: ./.github/workflows/install.yml
with:
name: ${{ matrix.name }}
version: ${{ matrix.version }}
expected_caption: ${{ matrix.expected_caption }}
expected_edition: ${{ matrix.expected_edition }}
minimum_build: ${{ matrix.minimum_build }}
platform: ${{ matrix.platform }}
tiny:
strategy:
fail-fast: false
matrix:
include:
- name: Core11
version: "core11"
expected_caption: Windows 11
minimum_build: 22000
platform: x64
- name: Tiny11
version: "tiny11"
expected_caption: Windows 11
minimum_build: 22000
platform: x64
- name: Tiny10
version: "tiny10"
expected_caption: Windows 10
minimum_build: 19041
platform: x64
name: ${{ matrix.name }}
uses: ./.github/workflows/install.yml
with:
name: ${{ matrix.name }}
version: ${{ matrix.version }}
expected_caption: ${{ matrix.expected_caption }}
minimum_build: ${{ matrix.minimum_build }}
platform: ${{ matrix.platform }}
server:
strategy:
fail-fast: false
matrix:
include:
- name: Windows Server 2025
version: "2025"
expected_caption: Windows Server 2025
minimum_build: 26100
platform: x64
- name: Windows Server 2022
version: "2022"
expected_caption: Windows Server 2022
minimum_build: 20348
platform: x64
- name: Windows Server 2019
version: "2019"
expected_caption: Windows Server 2019
minimum_build: 17763
platform: x64
- name: Windows Server 2016
version: "2016"
expected_caption: Windows Server 2016
minimum_build: 14393
platform: x64
- name: Windows Server 2012 R2
version: "2012"
expected_caption: Windows Server 2012 R2
minimum_build: 9600
platform: x64
name: ${{ matrix.name }}
uses: ./.github/workflows/install.yml
with:
name: ${{ matrix.name }}
version: ${{ matrix.version }}
expected_caption: ${{ matrix.expected_caption }}
minimum_build: ${{ matrix.minimum_build }}
platform: ${{ matrix.platform }}
legacy:
strategy:
fail-fast: false
matrix:
include:
- name: Windows 7 Ultimate
version: "7u"
cpu: host
expected_caption: Windows 7
minimum_build: 7601
platform: x64
- name: Windows 7 Ultimate x86
version: "7x86"
cpu: host
expected_caption: Windows 7
minimum_build: 7601
platform: x86
- name: Windows Vista Ultimate
version: "vu"
cpu: host
expected_caption: Windows Vista
minimum_build: 6002
platform: x64
- name: Windows Vista Ultimate x86
version: "vistax86"
cpu: host
expected_caption: Windows Vista
minimum_build: 6002
platform: x86
- name: Windows XP Professional
version: "xp"
cpu: host
expected_caption: Windows XP
minimum_build: 2600
platform: x86
- name: Windows XP Professional x64
version: "xp64"
cpu: host
expected_caption: Windows XP
minimum_build: 3790
platform: x64
- name: Windows 2000 Professional
version: "2k"
cpu: host
expected_caption: Windows 2000
minimum_build: 2195
platform: x86
- name: Windows Server 2008 R2
version: "2008"
cpu: host
expected_caption: Windows Server 2008 R2
minimum_build: 7601
platform: x64
- name: Windows Server 2003 R2
version: "2003"
cpu: host
expected_caption: Windows Server 2003
minimum_build: 3790
platform: x64
name: ${{ matrix.name }}
uses: ./.github/workflows/install.yml
with:
name: ${{ matrix.name }}
version: ${{ matrix.version }}
name: XP q35 + ${{ matrix.name }} + blk
version: "xp"
callback: legacy
machine: q35
cpu: ${{ matrix.cpu }}
expected_caption: ${{ matrix.expected_caption }}
minimum_build: ${{ matrix.minimum_build }}
platform: ${{ matrix.platform }}
cpu_flags: ${{ matrix.cpu_flags }}
disk_type: blk
kill_on_failure: true
expected_caption: Windows XP
minimum_build: 2600
platform: x86
+4
View File
@@ -133,6 +133,10 @@ kubectl apply -f https://raw.githubusercontent.com/dockur/windows/refs/heads/mas
| `2012` | Windows Server 2012 | 4.3 GB |
| `2008` | Windows Server 2008 | 3.0 GB |
| `2003` | Windows Server 2003 | 0.6 GB |
||||
| `core11` | Tiny11 Core | 3.0 GB |
| `tiny11` | Tiny11 | 5.3 GB |
| `tiny10` | Tiny10 | 3.6 GB |
> [!TIP]
> To install ARM64 versions of Windows use [dockur/windows-arm](https://github.com/dockur/windows-arm/).
+25 -17
View File
@@ -386,15 +386,24 @@ abortInstall() {
local dir="$1"
local iso="$2"
local efi
local efi efi32 efi64
[[ "${iso,,}" == *".esd" ]] && exit 60
enabled "${UNPACK:-}" && exit 60
efi=$(find "$dir" -maxdepth 1 -type d -iname efi -print -quit)
if [[ "${PLATFORM,,}" == "x64" ]]; then
efi=$(find "$dir" -maxdepth 1 -type d -iname efi -print -quit)
efi32=$(find "$dir" -maxdepth 3 -type f \
-ipath '*/efi/boot/bootia32.efi' -print -quit)
efi64=$(find "$dir" -maxdepth 3 -type f \
-ipath '*/efi/boot/bootx64.efi' -print -quit)
if [ -z "$efi" ] ||
{ [ -n "$efi32" ] && [ -z "$efi64" ]; }; then
BOOT_MODE="windows_legacy"
fi
if [ -z "$efi" ]; then
[[ "${PLATFORM,,}" == "x64" ]] && BOOT_MODE="windows_legacy"
fi
if [ -n "$CUSTOM" ]; then
@@ -733,19 +742,7 @@ setMachine() {
BOOT_MODE="windows_legacy"
[ -z "${ADAPTER:-}" ] && ADAPTER="rtl8139" ;;
"winxp"* )
DISK_TYPE="blk"
BOOT_MODE="windows_legacy"
[ -z "${SOUND:-}" ] && SOUND="usb-audio"
if [ -z "${CPU_MODEL:-}" ] || [[ "${CPU_MODEL:-}" == "host" ]]; then
# Workaround for boot loop on AMD EPYC processors
if [[ "${id,,}" == "winxpx86"* && "${CPU,,}" == *"amd epyc"* ]]; then
CPU_MODEL="qemu32"
fi
fi ;;
"win2003"* )
"winxp"* | "win2003"* )
DISK_TYPE="blk"
BOOT_MODE="windows_legacy"
[ -z "${SOUND:-}" ] && SOUND="usb-audio" ;;
@@ -755,13 +752,24 @@ setMachine() {
esac
case "${id,,}" in
"winvistax86"* | "win7x86"* )
# Fix boot loop issue on AMD EPYC processors
[ -z "${CPU_MODEL:-}" ] && CPU_MODEL="qemu32" ;;
esac
case "${id,,}" in
"winxp"* | "win2003"* | "winvistax86"* | "win7x86"* | "win2008r2x86"* )
if isQ35 "${MACHINE:-q35}"; then
# Prevent bluescreen if 64 bit PCI hole size is >2G.
ARGS="-global q35-pcihost.x-pci-hole64-fix=false"
fi ;;
esac