refactor(artifacts): harmonize Windows to Linux raw-file collection
Windows produced an intermediate C:\CI\output\artifacts.zip that upload-artifact then re-zipped (zip-in-zip), while Linux deposited raw files. Make both paths consistent: the build stages raw outputs into a collect dir; collect zips it only as a transport archive, fetches, and extracts into the host artifact dir; actions/upload-artifact produces the single final archive. - _windows_build: param artifact_zip -> output_dir; stage raw files (in-place when source IS the collect dir, else wipe+copy), no Compress-Archive; absolute artifact-source resolved. - _windows_collect: zip guest dir as transport, fetch, extract (mirror _linux_collect); guest_path is now the collect directory. - job.py / build_run CLI: pass output_dir; rename --guest-artifact-zip -> --guest-output-dir. - Tests updated for the raw-file contract. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -231,7 +231,7 @@ def _windows_build(
|
||||
ip_address: str,
|
||||
credential_target: str,
|
||||
workdir: str,
|
||||
artifact_zip: str,
|
||||
output_dir: str,
|
||||
host_source_dir: str | None,
|
||||
clone_url: str | None,
|
||||
clone_branch: str,
|
||||
@@ -251,7 +251,7 @@ def _windows_build(
|
||||
# Prepare workdir + artifact output directory.
|
||||
prep_ps = (
|
||||
f"$work = {_ps_quote(workdir)}; "
|
||||
f"$out = Split-Path {_ps_quote(artifact_zip)} -Parent; "
|
||||
f"$out = {_ps_quote(output_dir)}; "
|
||||
"if (-not (Test-Path $out)) { New-Item -ItemType Directory -Path $out -Force | Out-Null }; "
|
||||
"if (Test-Path $work) { Remove-Item $work -Recurse -Force }; "
|
||||
"New-Item -ItemType Directory -Path $work -Force | Out-Null"
|
||||
@@ -346,34 +346,44 @@ def _windows_build(
|
||||
click.echo("[build run] artifact packaging skipped (--skip-artifact).")
|
||||
return
|
||||
|
||||
# Package the artifact source into the requested zip on the guest.
|
||||
# Stage the artifact source into the collect dir as raw files
|
||||
# (no intermediate zip — `actions/upload-artifact` produces the
|
||||
# single final archive; mirrors the Linux flow, avoids zip-in-zip).
|
||||
# artifact_source may be absolute (e.g. C:\CI\output) or relative
|
||||
# to the build workdir. PowerShell Join-Path does NOT treat a
|
||||
# rooted second segment as absolute (it concatenates, yielding
|
||||
# C:\CI\build\C:\CI\output), so resolve it explicitly.
|
||||
if build_command:
|
||||
src_rel = artifact_source or "dist"
|
||||
else:
|
||||
src_rel = "bin\\CIOutput"
|
||||
# to the build workdir; PowerShell Join-Path does not treat a
|
||||
# rooted segment as absolute, so resolve explicitly. When the
|
||||
# source IS the collect dir (build wrote there directly), collect
|
||||
# in place — do NOT wipe it (that deleted the build output).
|
||||
src_rel = (artifact_source or "dist") if build_command else "bin\\CIOutput"
|
||||
|
||||
pkg_ps = (
|
||||
f"$work = {_ps_quote(workdir)}; "
|
||||
f"$rel = {_ps_quote(src_rel)}; "
|
||||
"$src = if ([System.IO.Path]::IsPathRooted($rel)) "
|
||||
"{ $rel } else { Join-Path $work $rel }; "
|
||||
f"$zip = {_ps_quote(artifact_zip)}; "
|
||||
"if (-not (Test-Path $src)) { "
|
||||
" throw \"[build run] artifact source not found: $src\" }; "
|
||||
"$dir = Split-Path $zip -Parent; "
|
||||
"if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }; "
|
||||
"if (Test-Path $zip) { Remove-Item $zip -Force }; "
|
||||
"if (Test-Path $src -PathType Leaf) { "
|
||||
" Compress-Archive -Path $src -DestinationPath $zip -Force "
|
||||
f"$out = {_ps_quote(output_dir)}; "
|
||||
"$sf = [System.IO.Path]::GetFullPath($src).TrimEnd('\\'); "
|
||||
"$of = [System.IO.Path]::GetFullPath($out).TrimEnd('\\'); "
|
||||
"$inPlace = ($sf -ieq $of) -or "
|
||||
"$sf.StartsWith($of + '\\', "
|
||||
"[System.StringComparison]::OrdinalIgnoreCase); "
|
||||
"if ($inPlace) { "
|
||||
" if (-not (Test-Path $out) -or "
|
||||
" -not (Get-ChildItem -Force -- $out)) { "
|
||||
" throw \"[build run] artifact source not found or empty: $out\" } "
|
||||
"} else { "
|
||||
" Compress-Archive -Path (Join-Path $src '*') -DestinationPath $zip -Force }"
|
||||
" if (-not (Test-Path $src)) { "
|
||||
" throw \"[build run] artifact source not found: $src\" }; "
|
||||
" if (Test-Path $out) { Remove-Item $out -Recurse -Force }; "
|
||||
" New-Item -ItemType Directory -Path $out -Force | Out-Null; "
|
||||
" if (Test-Path $src -PathType Leaf) { "
|
||||
" Copy-Item $src -Destination $out -Force "
|
||||
" } else { "
|
||||
" Copy-Item (Join-Path $src '*') -Destination $out -Recurse -Force } "
|
||||
"}"
|
||||
)
|
||||
t.run(pkg_ps)
|
||||
click.echo(f"[build run] artifact written to {artifact_zip}")
|
||||
click.echo(f"[build run] artifact staged at {output_dir}")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- CLI
|
||||
@@ -426,10 +436,11 @@ def _windows_build(
|
||||
help="Workdir inside the guest (defaults: Win=C:\\CI\\build, Linux=/opt/ci/build).",
|
||||
)
|
||||
@click.option(
|
||||
"--guest-artifact-zip",
|
||||
"guest_artifact_zip",
|
||||
"--guest-output-dir",
|
||||
"guest_output_dir",
|
||||
default=None,
|
||||
help="Artifact zip path inside the Windows guest (default: C:\\CI\\output\\artifacts.zip).",
|
||||
help="Collect dir inside the Windows guest (default: C:\\CI\\output). "
|
||||
"Raw build outputs are staged here; upload-artifact zips them.",
|
||||
)
|
||||
@click.option(
|
||||
"--guest-linux-work-dir",
|
||||
@@ -468,7 +479,7 @@ def build_run(
|
||||
gitea_credential_target: str,
|
||||
build_command: str,
|
||||
guest_work_dir: str | None,
|
||||
guest_artifact_zip: str | None,
|
||||
guest_output_dir: str | None,
|
||||
guest_linux_work_dir: str | None,
|
||||
guest_linux_output_dir: str,
|
||||
guest_artifact_source: str,
|
||||
@@ -485,7 +496,7 @@ def build_run(
|
||||
* ``--host-source-dir`` — local directory zipped/tarred and uploaded;
|
||||
* ``--clone-url`` — ``git clone`` invoked inside the guest.
|
||||
|
||||
Phase C hook: ``--guest-work-dir`` and ``--guest-artifact-zip`` are
|
||||
Phase C hook: ``--guest-work-dir`` and ``--guest-output-dir`` are
|
||||
parameterised; defaults are applied here, never inside the transport
|
||||
layer.
|
||||
"""
|
||||
@@ -533,14 +544,14 @@ def build_run(
|
||||
raise click.ClickException(str(exc)) from exc
|
||||
else:
|
||||
workdir = guest_work_dir or "C:\\CI\\build"
|
||||
artifact_zip = guest_artifact_zip or "C:\\CI\\output\\artifacts.zip"
|
||||
output_dir = guest_output_dir or "C:\\CI\\output"
|
||||
target = credential_target or config.guest_cred_target
|
||||
try:
|
||||
_windows_build(
|
||||
ip_address=ip_address,
|
||||
credential_target=target,
|
||||
workdir=workdir,
|
||||
artifact_zip=artifact_zip,
|
||||
output_dir=output_dir,
|
||||
host_source_dir=host_source_dir,
|
||||
clone_url=clone_url,
|
||||
clone_branch=clone_branch,
|
||||
|
||||
Reference in New Issue
Block a user