Isolate modern and Win7 workspaces (T-604)
This commit is contained in:
@@ -10,6 +10,8 @@ import sys
|
||||
|
||||
|
||||
MAX_LEGACY_GO_VERSION = (1, 20)
|
||||
MODERN_TOOLCHAIN = "go1.25.0"
|
||||
LEGACY_TOOLCHAIN = "go1.20.14"
|
||||
|
||||
|
||||
def version_tuple(value):
|
||||
@@ -52,9 +54,10 @@ def required_version(path, module_path):
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def run_go(repo_root, cwd, arguments, go_work):
|
||||
def run_go(cwd, arguments, go_work, toolchain):
|
||||
environment = os.environ.copy()
|
||||
environment["GOWORK"] = str(go_work) if go_work else "off"
|
||||
environment["GOTOOLCHAIN"] = toolchain
|
||||
result = subprocess.run(
|
||||
["go"] + arguments,
|
||||
cwd=str(cwd),
|
||||
@@ -70,6 +73,130 @@ def run_go(repo_root, cwd, arguments, go_work):
|
||||
return result.stdout
|
||||
|
||||
|
||||
def workspace_modules(workspace, toolchain):
|
||||
document = json.loads(
|
||||
run_go(
|
||||
workspace.parent,
|
||||
["work", "edit", "-json"],
|
||||
workspace,
|
||||
toolchain,
|
||||
)
|
||||
)
|
||||
return {
|
||||
(workspace.parent / entry["DiskPath"]).resolve()
|
||||
for entry in document.get("Use", [])
|
||||
}
|
||||
|
||||
|
||||
def display_path(path, repo_root):
|
||||
try:
|
||||
return str(path.relative_to(repo_root))
|
||||
except ValueError:
|
||||
return str(path)
|
||||
|
||||
|
||||
def workspace_layout_violation(workspace, actual, expected, repo_root):
|
||||
if actual == expected:
|
||||
return None
|
||||
actual_names = sorted(display_path(path, repo_root) for path in actual)
|
||||
expected_names = sorted(display_path(path, repo_root) for path in expected)
|
||||
return "{} contains {}, want {}".format(
|
||||
display_path(workspace, repo_root),
|
||||
actual_names,
|
||||
expected_names,
|
||||
)
|
||||
|
||||
|
||||
def validate_workspace_layout(repo_root):
|
||||
root_workspace = repo_root / "go.work"
|
||||
win7_workspace = repo_root / "app-win7" / "go.work"
|
||||
expected = {
|
||||
root_workspace: {
|
||||
(repo_root / "app-modern").resolve(),
|
||||
(repo_root / "core").resolve(),
|
||||
},
|
||||
win7_workspace: {
|
||||
(repo_root / "app-win7").resolve(),
|
||||
(repo_root / "core").resolve(),
|
||||
},
|
||||
}
|
||||
toolchains = {
|
||||
root_workspace: MODERN_TOOLCHAIN,
|
||||
win7_workspace: LEGACY_TOOLCHAIN,
|
||||
}
|
||||
violations = []
|
||||
for workspace, expected_modules in expected.items():
|
||||
actual_modules = workspace_modules(workspace, toolchains[workspace])
|
||||
violation = workspace_layout_violation(
|
||||
workspace,
|
||||
actual_modules,
|
||||
expected_modules,
|
||||
repo_root,
|
||||
)
|
||||
if violation:
|
||||
violations.append(violation)
|
||||
return violations
|
||||
|
||||
|
||||
def resolved_module_version(cwd, workspace, toolchain, module_path):
|
||||
document = json.loads(
|
||||
run_go(
|
||||
cwd,
|
||||
["list", "-m", "-json", module_path],
|
||||
workspace,
|
||||
toolchain,
|
||||
)
|
||||
)
|
||||
return document.get("Version", "")
|
||||
|
||||
|
||||
def module_version_violation(label, module_path, actual, expected):
|
||||
if actual == expected:
|
||||
return None
|
||||
return "{} workspace resolves {} {}, want {}".format(
|
||||
label,
|
||||
module_path,
|
||||
actual,
|
||||
expected,
|
||||
)
|
||||
|
||||
|
||||
def validate_workspace_gio_versions(repo_root):
|
||||
checks = (
|
||||
(
|
||||
"modern",
|
||||
repo_root / "app-modern",
|
||||
repo_root / "go.work",
|
||||
MODERN_TOOLCHAIN,
|
||||
"v0.10.1",
|
||||
),
|
||||
(
|
||||
"win7",
|
||||
repo_root / "app-win7",
|
||||
repo_root / "app-win7" / "go.work",
|
||||
LEGACY_TOOLCHAIN,
|
||||
"v0.6.0",
|
||||
),
|
||||
)
|
||||
violations = []
|
||||
for label, cwd, workspace, toolchain, expected in checks:
|
||||
actual = resolved_module_version(
|
||||
cwd,
|
||||
workspace,
|
||||
toolchain,
|
||||
"gioui.org",
|
||||
)
|
||||
violation = module_version_violation(
|
||||
label,
|
||||
"gioui.org",
|
||||
actual,
|
||||
expected,
|
||||
)
|
||||
if violation:
|
||||
violations.append(violation)
|
||||
return violations
|
||||
|
||||
|
||||
def validate_pins(repo_root):
|
||||
expected_go_directives = {
|
||||
repo_root / "go.work": "1.25.0",
|
||||
@@ -106,7 +233,12 @@ def validate_pins(repo_root):
|
||||
|
||||
|
||||
def validate_go20_toolchain(repo_root):
|
||||
output = run_go(repo_root, repo_root, ["version"], None).strip()
|
||||
output = run_go(
|
||||
repo_root,
|
||||
["version"],
|
||||
None,
|
||||
LEGACY_TOOLCHAIN,
|
||||
).strip()
|
||||
if "go1.20.14" not in output:
|
||||
return ["compatibility scan uses {!r}, want go1.20.14".format(output)]
|
||||
return []
|
||||
@@ -114,22 +246,23 @@ def validate_go20_toolchain(repo_root):
|
||||
|
||||
def validate_module_versions(repo_root):
|
||||
module_sets = (
|
||||
("core", repo_root / "core", None),
|
||||
("core", repo_root / "core", None, LEGACY_TOOLCHAIN),
|
||||
(
|
||||
"win7",
|
||||
repo_root / "app-win7",
|
||||
repo_root / "app-win7" / "go.work",
|
||||
LEGACY_TOOLCHAIN,
|
||||
),
|
||||
)
|
||||
violations = []
|
||||
checked = 0
|
||||
|
||||
for label, cwd, go_work in module_sets:
|
||||
for label, cwd, go_work, toolchain in module_sets:
|
||||
output = run_go(
|
||||
repo_root,
|
||||
cwd,
|
||||
["list", "-m", "-json", "all"],
|
||||
go_work,
|
||||
toolchain,
|
||||
)
|
||||
for module in decode_json_stream(output):
|
||||
checked += 1
|
||||
@@ -153,12 +286,45 @@ def self_check():
|
||||
raise AssertionError("Go 1.20.14 should be accepted")
|
||||
if not version_tuple("1.21")[:2] > MAX_LEGACY_GO_VERSION:
|
||||
raise AssertionError("Go 1.21 should be rejected")
|
||||
fake_root = pathlib.Path("/repo")
|
||||
fake_workspace = fake_root / "go.work"
|
||||
fake_expected = {fake_root / "core", fake_root / "app-modern"}
|
||||
if workspace_layout_violation(
|
||||
fake_workspace,
|
||||
fake_expected,
|
||||
fake_expected,
|
||||
fake_root,
|
||||
):
|
||||
raise AssertionError("matching workspace layout should be accepted")
|
||||
if not workspace_layout_violation(
|
||||
fake_workspace,
|
||||
fake_expected | {fake_root / "app-win7"},
|
||||
fake_expected,
|
||||
fake_root,
|
||||
):
|
||||
raise AssertionError("unexpected workspace module should be rejected")
|
||||
if module_version_violation(
|
||||
"win7",
|
||||
"gioui.org",
|
||||
"v0.6.0",
|
||||
"v0.6.0",
|
||||
):
|
||||
raise AssertionError("matching Gio version should be accepted")
|
||||
if not module_version_violation(
|
||||
"win7",
|
||||
"gioui.org",
|
||||
"v0.10.1",
|
||||
"v0.6.0",
|
||||
):
|
||||
raise AssertionError("mismatched Gio version should be rejected")
|
||||
|
||||
|
||||
def main():
|
||||
self_check()
|
||||
repo_root = pathlib.Path(__file__).resolve().parents[1]
|
||||
violations = validate_pins(repo_root)
|
||||
violations.extend(validate_workspace_layout(repo_root))
|
||||
violations.extend(validate_workspace_gio_versions(repo_root))
|
||||
violations.extend(validate_go20_toolchain(repo_root))
|
||||
module_violations, checked = validate_module_versions(repo_root)
|
||||
violations.extend(module_violations)
|
||||
@@ -169,7 +335,8 @@ def main():
|
||||
raise SystemExit(1)
|
||||
|
||||
print(
|
||||
"Go version check passed: pins valid; {} module records are Go 1.20-compatible.".format(
|
||||
"Go version check passed: workspace isolation and pins valid; "
|
||||
"{} module records are Go 1.20-compatible.".format(
|
||||
checked
|
||||
)
|
||||
)
|
||||
|
||||
@@ -35,7 +35,13 @@ New-Item -ItemType Directory -Force -Path (Join-Path $Root "dist") | Out-Null
|
||||
|
||||
Invoke-Step "Sync root workspace" {
|
||||
$env:GOTOOLCHAIN = "go1.25.0"
|
||||
Remove-Item Env:GOWORK -ErrorAction SilentlyContinue
|
||||
$env:GOWORK = (Resolve-Path "go.work").Path
|
||||
go work sync
|
||||
}
|
||||
|
||||
Invoke-Step "Sync Win7 workspace" {
|
||||
$env:GOTOOLCHAIN = "go1.25.0"
|
||||
$env:GOWORK = (Resolve-Path "app-win7/go.work").Path
|
||||
go work sync
|
||||
}
|
||||
|
||||
@@ -54,7 +60,8 @@ Invoke-Step "Validate core architecture boundary" {
|
||||
}
|
||||
|
||||
Invoke-Step "Validate Go and dependency pins" {
|
||||
$env:GOTOOLCHAIN = "go1.20.14"
|
||||
Remove-Item Env:GOTOOLCHAIN -ErrorAction SilentlyContinue
|
||||
Remove-Item Env:GOWORK -ErrorAction SilentlyContinue
|
||||
python scripts/check_go_versions.py
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,10 @@ fi
|
||||
mkdir -p dist
|
||||
|
||||
echo "==> Sync root workspace"
|
||||
GOTOOLCHAIN=go1.25.0 go work sync
|
||||
GOTOOLCHAIN=go1.25.0 GOWORK="$ROOT_DIR/go.work" go work sync
|
||||
|
||||
echo "==> Sync Win7 workspace"
|
||||
GOTOOLCHAIN=go1.25.0 GOWORK="$ROOT_DIR/app-win7/go.work" go work sync
|
||||
|
||||
echo "==> Validate harness governance"
|
||||
"$PYTHON" scripts/validate_agent_context.py
|
||||
@@ -38,7 +41,7 @@ echo "==> Validate core architecture boundary"
|
||||
"$PYTHON" scripts/check_core_boundaries.py
|
||||
|
||||
echo "==> Validate Go and dependency pins"
|
||||
GOTOOLCHAIN=go1.20.14 "$PYTHON" scripts/check_go_versions.py
|
||||
"$PYTHON" scripts/check_go_versions.py
|
||||
|
||||
echo "==> Vet and test core with Go 1.20.14"
|
||||
GOTOOLCHAIN=go1.20.14 GOWORK=off go -C core vet ./...
|
||||
|
||||
Reference in New Issue
Block a user