Skip to content

Commit df49394

Browse files
fix(windows): resolve PHP install failures and prevent false CI coverage (#65)
Co-authored-by: Rózsa Zoltán <67325669+rozsazoltan@users.noreply.github.com> Signed-off-by: Artemeey <artemeey.ru@mail.ru>
1 parent 56a3ecc commit df49394

13 files changed

Lines changed: 1173 additions & 894 deletions

.github/scripts/ci-checks.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ fn check_installed_tools(args: &[String]) -> Result<(), String> {
207207

208208
mise_exec(&["php", "--version"], false)?;
209209

210+
if runner_os == "Windows" {
211+
require_windows_spaced_mise_install_path()?;
212+
}
213+
210214
let php_version_raw = mise_exec(&["php", "-r", "echo PHP_VERSION;"], true)?;
211215
let php_version_text = php_version_raw.trim();
212216
let php_version = PhpVersion::parse(php_version_text)?;
@@ -267,6 +271,45 @@ fn check_installed_tools(args: &[String]) -> Result<(), String> {
267271
Ok(())
268272
}
269273

274+
275+
fn require_windows_spaced_mise_install_path() -> Result<(), String> {
276+
let mise_data_dir = env::var("MISE_DATA_DIR")
277+
.map_err(|_| "MISE_DATA_DIR must be set for Windows install smoke tests".to_string())?;
278+
279+
if !mise_data_dir.contains(' ') {
280+
return Err(format!(
281+
"Windows install smoke tests must use a spaced MISE_DATA_DIR, got {mise_data_dir:?}"
282+
));
283+
}
284+
285+
let php_binary = mise_exec(&["php", "-r", "echo PHP_BINARY;"], true)?;
286+
let php_binary = normalize_windows_path(php_binary.trim());
287+
let mise_data_dir = normalize_windows_path(mise_data_dir.trim());
288+
289+
if !php_binary.contains(' ') {
290+
return Err(format!(
291+
"PHP_BINARY should contain a space to cover Windows quoting regressions, got {php_binary:?}"
292+
));
293+
}
294+
295+
if !php_binary.starts_with(&mise_data_dir) {
296+
return Err(format!(
297+
"PHP_BINARY should be installed under MISE_DATA_DIR. MISE_DATA_DIR={mise_data_dir:?}, PHP_BINARY={php_binary:?}"
298+
));
299+
}
300+
301+
println!("Windows install path is under spaced MISE_DATA_DIR: {php_binary}");
302+
Ok(())
303+
}
304+
305+
fn normalize_windows_path(value: &str) -> String {
306+
value
307+
.trim_matches('"')
308+
.replace('/', "\\")
309+
.trim_end_matches('\\')
310+
.to_ascii_lowercase()
311+
}
312+
270313
fn require_php_extension(extension: &str, reason: &str) -> Result<(), String> {
271314
let modules = mise_exec(&["php", "-m"], true)?;
272315
let found = modules

.github/workflows/cache.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
permissions:
1212
contents: write
13+
issues: write
1314

1415
steps:
1516
- name: Checkout default branch (for repo access)
@@ -43,8 +44,27 @@ jobs:
4344
python3 << 'EOF'
4445
import urllib.request
4546
import json
47+
import os
4648
import re
4749
50+
def read_existing_versions():
51+
if not os.path.exists("versions.txt"):
52+
return []
53+
54+
with open("versions.txt", "r") as f:
55+
return [line.strip() for line in f if line.strip()]
56+
57+
def series_key(version):
58+
m = re.match(r'^(\d+)\.(\d+)\.', version)
59+
if not m:
60+
return None
61+
62+
return f"{m.group(1)}.{m.group(2)}"
63+
64+
def major_key(version):
65+
m = re.match(r'^(\d+)\.', version)
66+
return m.group(1) if m else None
67+
4868
def fetch_tags():
4969
tags = []
5070
page = 1
@@ -84,6 +104,10 @@ jobs:
84104
suffix_order = 0 if not suffix else -1
85105
return (major, minor, patch, suffix_order)
86106
107+
old_versions = read_existing_versions()
108+
old_series = {series_key(v) for v in old_versions if series_key(v)}
109+
old_majors = {major_key(v) for v in old_versions if major_key(v)}
110+
87111
tags = fetch_tags()
88112
89113
seen = set()
@@ -99,9 +123,28 @@ jobs:
99123
with open("versions.txt", "w") as f:
100124
f.write("\n".join(versions) + "\n")
101125
126+
new_series = []
127+
if old_versions:
128+
latest_by_series = {}
129+
for version in versions:
130+
series = series_key(version)
131+
if series and series not in old_series and series not in latest_by_series:
132+
latest_by_series[series] = version
133+
134+
for series, representative in sorted(latest_by_series.items(), key=lambda item: [int(part) for part in item[0].split(".")]):
135+
major = series.split(".", 1)[0]
136+
scope = "major" if major not in old_majors else "minor"
137+
new_series.append((scope, series, representative))
138+
139+
with open("new-windows-series.txt", "w") as f:
140+
for scope, series, representative in new_series:
141+
f.write(f"{scope}\t{series}\t{representative}\n")
142+
102143
print(f"Fetched {len(versions)} versions.")
144+
print(f"Detected {len(new_series)} new PHP major/minor series.")
103145
EOF
104146
147+
105148
- name: Commit to cache branch if changed
106149
run: |
107150
git config user.name "github-actions[bot]"
@@ -115,3 +158,59 @@ jobs:
115158
git commit -m "chore: bump php versions cache (+${ADDED} lines)"
116159
git push origin cache
117160
fi
161+
162+
- name: Open Windows installer maintenance issues
163+
env:
164+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
165+
shell: bash
166+
run: |
167+
set -euo pipefail
168+
169+
if [ ! -s new-windows-series.txt ]; then
170+
echo "No new PHP major/minor series detected."
171+
exit 0
172+
fi
173+
174+
while IFS=$'\t' read -r scope series representative; do
175+
[ -n "${series:-}" ] || continue
176+
177+
if [ "$scope" = "major" ]; then
178+
title="Review Windows PHP installer mapping for PHP ${series} (new major)"
179+
else
180+
title="Review Windows PHP installer mapping for PHP ${series}"
181+
fi
182+
183+
existing="$(
184+
ISSUE_TITLE="$title" gh issue list \
185+
--state open \
186+
--search "${title} in:title" \
187+
--json title \
188+
| python3 -c 'import json, os, sys; title = os.environ["ISSUE_TITLE"]; print(sum(1 for issue in json.load(sys.stdin) if issue.get("title") == title))'
189+
)"
190+
191+
if [ "$existing" != "0" ]; then
192+
echo "Issue already exists: $title"
193+
continue
194+
fi
195+
196+
body_file="$(mktemp)"
197+
cat > "$body_file" <<EOF
198+
The PHP versions cache detected a new PHP ${scope} series: ${series}.
199+
200+
First detected version: ${representative}
201+
202+
Please review whether `lib/windows_php.lua` needs to be updated against the official PHP Windows installer script:
203+
https://www.php.net/include/download-instructions/windows.ps1
204+
205+
Focus areas:
206+
- Visual C++ toolset mapping (`vs16`, `vs17`, future values)
207+
- x64/x86 availability and fallback rules
208+
- release vs QA/archive URL behavior
209+
- ZIP naming conventions for NTS Windows builds
210+
211+
This issue was opened automatically by the PHP versions cache workflow because new major/minor PHP series can require Windows installer mapping changes.
212+
EOF
213+
214+
gh issue create --title "$title" --body-file "$body_file"
215+
rm -f "$body_file"
216+
done < new-windows-series.txt

.github/workflows/test.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,23 @@ jobs:
344344
install: false
345345
cache: false
346346

347+
- name: Configure spaced mise directories on Windows
348+
if: matrix.target.kind == 'hosted' && runner.os == 'Windows'
349+
shell: pwsh
350+
run: |
351+
$dirs = @{
352+
MISE_DATA_DIR = Join-Path $env:RUNNER_TEMP 'mise data dir'
353+
MISE_CACHE_DIR = Join-Path $env:RUNNER_TEMP 'mise cache dir'
354+
MISE_CONFIG_DIR = Join-Path $env:RUNNER_TEMP 'mise config dir'
355+
MISE_STATE_DIR = Join-Path $env:RUNNER_TEMP 'mise state dir'
356+
MISE_TMP_DIR = Join-Path $env:RUNNER_TEMP 'mise tmp dir'
357+
}
358+
359+
foreach ($item in $dirs.GetEnumerator()) {
360+
New-Item -ItemType Directory -Force -Path $item.Value | Out-Null
361+
"$($item.Key)=$($item.Value)" >> $env:GITHUB_ENV
362+
}
363+
347364
- name: Register plugin from PR source
348365
if: matrix.target.kind == 'hosted'
349366
run: mise plugin link php "${{ github.workspace }}"
@@ -444,6 +461,23 @@ jobs:
444461
install: false
445462
cache: false
446463

464+
- name: Configure spaced mise directories on Windows
465+
if: runner.os == 'Windows'
466+
shell: pwsh
467+
run: |
468+
$dirs = @{
469+
MISE_DATA_DIR = Join-Path $env:RUNNER_TEMP 'mise data dir'
470+
MISE_CACHE_DIR = Join-Path $env:RUNNER_TEMP 'mise cache dir'
471+
MISE_CONFIG_DIR = Join-Path $env:RUNNER_TEMP 'mise config dir'
472+
MISE_STATE_DIR = Join-Path $env:RUNNER_TEMP 'mise state dir'
473+
MISE_TMP_DIR = Join-Path $env:RUNNER_TEMP 'mise tmp dir'
474+
}
475+
476+
foreach ($item in $dirs.GetEnumerator()) {
477+
New-Item -ItemType Directory -Force -Path $item.Value | Out-Null
478+
"$($item.Key)=$($item.Value)" >> $env:GITHUB_ENV
479+
}
480+
447481
- name: Register plugin from PR source
448482
run: mise plugin link php "${{ github.workspace }}"
449483

0 commit comments

Comments
 (0)