hypertwist/scripts/run-hypertwist-remote-exact-source-browser-package-refresh.sh
2026-06-30 23:04:58 +00:00

423 lines
14 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
HYPERTWIST_REMOTE_WINDOWS_PASSWORD=... \
scripts/run-hypertwist-remote-exact-source-browser-package-refresh.sh
Options:
--worktree-root <path>
Optional Windows worktree root. Defaults to C:\HyperTwist_worktrees\phase10validate.
--report-stamp <YYYYMMDD>
Optional suffix used for the browser automation report and package archive.
Defaults to the current UTC date.
--fallback-worktree-root <path>
Optional fallback Windows worktree root to use if the primary refresh
fails. Useful when the maintained worktree is temporarily locked by
another Windows-side process.
--browser-filter <automation-filter>
Optional Unreal automation filter. Defaults to HyperTwist.Browser.
--browser-report-name <name>
Optional explicit browser automation report name. Defaults to
Browser-ExactSource-<report-stamp>.
--package-archive-dir <path>
Optional Windows archive directory for the higher-dimensional package run.
Defaults to <worktree-root>_packaged_phase6c_higherdim_refresh_<report-stamp>.
--sync-file <repo-relative-path>
Optional repo-relative file to sync into the remote Windows worktree before
validation. May be repeated.
--skip-build
Skip the remote Unreal editor build step.
--skip-browser-automation
Skip the HyperTwist.Browser automation refresh.
--skip-package
Skip the higher-dimensional package refresh.
--skip-browser-report-pull
Skip pulling the browser automation index.json back into docs/generated.
--skip-package-report-pull
Skip pulling the higher-dimensional package validation report back into
docs/generated.
--skip-summary-refresh
Skip re-rendering website/src/shared/generated/windows-package-validation-summary.json.
--skip-exact-source-support-sync
Skip syncing the bounded exact-source browser/package support files that
the fallback Windows validation root needs for truthful browser/package
refreshes.
--dry-run
Print the wrapper invocations without executing them.
Environment:
HYPERTWIST_REMOTE_WINDOWS_PASSWORD Required by the underlying remote wrappers.
HYPERTWIST_REMOTE_WINDOWS_WORKTREE_ROOT Optional default for --worktree-root.
HYPERTWIST_REMOTE_WINDOWS_FALLBACK_WORKTREE_ROOT
Optional default for --fallback-worktree-root.
HYPERTWIST_REMOTE_WINDOWS_SKIP_EXACT_SOURCE_SUPPORT_SYNC
Optional default for --skip-exact-source-support-sync.
EOF
}
ps_single_quote() {
printf "'%s'" "${1//\'/\'\'}"
}
run_or_print() {
if [[ "$dry_run" == "true" ]]; then
printf '%q ' "$@"
printf '\n'
return 0
fi
"$@"
}
worktree_root="${HYPERTWIST_REMOTE_WINDOWS_WORKTREE_ROOT:-C:\\HyperTwist_worktrees\\phase10validate}"
fallback_worktree_root="${HYPERTWIST_REMOTE_WINDOWS_FALLBACK_WORKTREE_ROOT:-}"
report_stamp="$(date -u '+%Y%m%d')"
browser_filter="HyperTwist.Browser"
browser_report_name=""
package_archive_dir=""
sync_files=()
skip_build="false"
skip_browser_automation="false"
skip_package="false"
skip_browser_report_pull="false"
skip_package_report_pull="false"
skip_summary_refresh="false"
skip_exact_source_support_sync="${HYPERTWIST_REMOTE_WINDOWS_SKIP_EXACT_SOURCE_SUPPORT_SYNC:-false}"
dry_run="false"
while [[ $# -gt 0 ]]; do
case "$1" in
--worktree-root)
worktree_root="${2:-}"
shift 2
;;
--report-stamp)
report_stamp="${2:-}"
shift 2
;;
--fallback-worktree-root)
fallback_worktree_root="${2:-}"
shift 2
;;
--browser-filter)
browser_filter="${2:-}"
shift 2
;;
--browser-report-name)
browser_report_name="${2:-}"
shift 2
;;
--package-archive-dir)
package_archive_dir="${2:-}"
shift 2
;;
--sync-file)
sync_files+=("${2:-}")
shift 2
;;
--skip-build)
skip_build="true"
shift
;;
--skip-browser-automation)
skip_browser_automation="true"
shift
;;
--skip-package)
skip_package="true"
shift
;;
--skip-browser-report-pull)
skip_browser_report_pull="true"
shift
;;
--skip-package-report-pull)
skip_package_report_pull="true"
shift
;;
--skip-summary-refresh)
skip_summary_refresh="true"
shift
;;
--skip-exact-source-support-sync)
skip_exact_source_support_sync="true"
shift
;;
--dry-run)
dry_run="true"
shift
;;
-h|--help)
usage
exit 0
;;
*)
usage >&2
exit 1
;;
esac
done
if [[ -z "$browser_report_name" ]]; then
browser_report_name="Browser-ExactSource-${report_stamp}"
fi
if [[ -z "$package_archive_dir" ]]; then
package_archive_dir="${worktree_root}_packaged_phase6c_higherdim_refresh_${report_stamp}"
fi
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "${script_dir}/.." && pwd)"
remote_ps_wrapper="${script_dir}/run-hypertwist-remote-windows-powershell.sh"
remote_build_wrapper="${script_dir}/run-hypertwist-remote-unreal-build.sh"
remote_automation_wrapper="${script_dir}/run-hypertwist-remote-unreal-automation.sh"
remote_sync_wrapper="${script_dir}/run-hypertwist-remote-windows-file-sync.sh"
remote_pull_wrapper="${script_dir}/run-hypertwist-remote-windows-file-pull.sh"
summary_refresh_script="${script_dir}/render-hypertwist-web-package-validation-summary.mjs"
for required_wrapper in \
"$remote_ps_wrapper" \
"$remote_build_wrapper" \
"$remote_automation_wrapper" \
"$remote_sync_wrapper" \
"$remote_pull_wrapper"
do
if [[ ! -x "$required_wrapper" ]]; then
echo "Expected executable wrapper at $required_wrapper" >&2
exit 1
fi
done
if [[ ! -f "$summary_refresh_script" ]]; then
echo "Expected summary refresh script at $summary_refresh_script" >&2
exit 1
fi
if [[ -z "${HYPERTWIST_REMOTE_WINDOWS_PASSWORD:-}" ]]; then
echo "Set HYPERTWIST_REMOTE_WINDOWS_PASSWORD before running this refresh." >&2
exit 1
fi
host_probe_command="Write-Output ('USER=' + [System.Security.Principal.WindowsIdentity]::GetCurrent().Name); Write-Output ('HOST=' + \$env:COMPUTERNAME)"
browser_report_local_path="docs/generated/browser_automation/${browser_report_name}/index.json"
package_report_local_path="docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json"
exact_source_support_files=(
"Content/Browser/index.html"
"Content/Browser/src/browser-runtime-bootstrap.js"
"Content/Browser/src/browser-spatial-runtime-fallback.js"
"Content/Browser/src/runtime/shell.ts"
"scripts/Invoke-HyperTwistHigherDimensionalPackage.ps1"
"scripts/Launch-HyperTwistHigherDimensionalPackage.ps1"
"docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_map_manifest.json"
"UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp"
"UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibraryInternal.h"
"UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibraryCoachPolicies.cpp"
"UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibraryCoachWorkflow.cpp"
"UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibraryCoachSummaries.cpp"
)
effective_sync_files=()
add_effective_sync_file() {
local candidate="$1"
local existing
for existing in "${effective_sync_files[@]}"; do
if [[ "$existing" == "$candidate" ]]; then
return 0
fi
done
effective_sync_files+=("$candidate")
}
if [[ "$skip_exact_source_support_sync" != "true" ]]; then
for sync_file in "${exact_source_support_files[@]}"; do
add_effective_sync_file "$sync_file"
done
fi
for sync_file in "${sync_files[@]}"; do
add_effective_sync_file "$sync_file"
done
run_refresh_for_root() {
local current_worktree_root="$1"
local current_validation_report_path="${current_worktree_root}\\docs\\generated\\higher_dimensional_training_maps\\phase6c_dedicated_family_package_validation_report.json"
local browser_report_remote_path="${current_worktree_root}\\UnrealHyperTwist\\Saved\\AutomationReports\\${browser_report_name}\\index.json"
local package_report_remote_path="$current_validation_report_path"
local current_package_script_path="${current_worktree_root}\\scripts\\Invoke-HyperTwistHigherDimensionalPackage.ps1"
local current_package_archive_dir="$package_archive_dir"
local current_game_target_receipt_path="${current_worktree_root}\\UnrealHyperTwist\\Binaries\\Win64\\UnrealHyperTwist.target"
local package_skip_build_clause=""
local pre_package_editor_build_ps_bool='$false'
local pre_package_editor_build_result='not-run'
local step_exit=0
if [[ "$current_worktree_root" != "$worktree_root" && "$package_archive_dir" == "${worktree_root}_packaged_phase6c_higherdim_refresh_${report_stamp}" ]]; then
current_package_archive_dir="${current_worktree_root}_packaged_phase6c_higherdim_refresh_${report_stamp}"
fi
echo "Re-proving remote Windows lane through ${current_worktree_root}."
if run_or_print "$remote_ps_wrapper" --command "$host_probe_command"; then
:
else
step_exit="$?"
return "$step_exit"
fi
if [[ ${#effective_sync_files[@]} -gt 0 ]]; then
echo "Syncing ${#effective_sync_files[@]} repo-relative exact-source support file(s) into ${current_worktree_root}."
local sync_command=("$remote_sync_wrapper")
local sync_file
for sync_file in "${effective_sync_files[@]}"; do
sync_command+=(--file "$sync_file")
done
sync_command+=(--remote-root "$current_worktree_root")
if run_or_print "${sync_command[@]}"; then
:
else
step_exit="$?"
return "$step_exit"
fi
fi
if [[ "$skip_build" != "true" ]]; then
echo "Running remote Unreal editor build."
if run_or_print "$remote_build_wrapper" --worktree-root "$current_worktree_root"; then
pre_package_editor_build_ps_bool='$true'
pre_package_editor_build_result='passed'
:
else
step_exit="$?"
return "$step_exit"
fi
fi
if [[ "$skip_browser_automation" != "true" ]]; then
echo "Running remote browser automation refresh (~10-20s once the editor lane is warm)."
if run_or_print \
env HYPERTWIST_REMOTE_WINDOWS_WORKTREE_ROOT="$current_worktree_root" \
"$remote_automation_wrapper" \
--filter "$browser_filter" \
--report-name "$browser_report_name"
then
:
else
step_exit="$?"
return "$step_exit"
fi
fi
if [[ "$skip_package" != "true" ]]; then
echo "Running remote higher-dimensional package refresh (~1-3m on the maintained lane)."
if [[ "$dry_run" == "true" ]]; then
echo "Dry run: package helper would auto-detect whether ${current_game_target_receipt_path} exists before deciding on -SkipBuild."
else
local package_skip_build_probe_output
if package_skip_build_probe_output="$(
"$remote_ps_wrapper" --command "\$GameTargetReceiptPath = $(ps_single_quote "$current_game_target_receipt_path"); Write-Output ('PACKAGE_SKIP_BUILD=' + (Test-Path -LiteralPath \$GameTargetReceiptPath).ToString().ToLowerInvariant())" \
| tr -d '\r'
)"; then
:
else
step_exit="$?"
return "$step_exit"
fi
if printf '%s\n' "$package_skip_build_probe_output" | grep -Fq 'PACKAGE_SKIP_BUILD=true'; then
package_skip_build_clause=" -SkipBuild"
echo "Package helper will reuse the existing Win64 game target receipt."
else
echo "Package helper will rebuild the Win64 game target because the packaged-game receipt is absent."
fi
fi
local package_command
package_command="$(
cat <<EOF
\$ProjectRoot = $(ps_single_quote "$current_worktree_root")
\$ArchiveDirectory = $(ps_single_quote "$current_package_archive_dir")
\$PackageScriptPath = $(ps_single_quote "$current_package_script_path")
\$ValidationReportPath = $(ps_single_quote "$current_validation_report_path")
\$PrePackageEditorBuildPerformed = ${pre_package_editor_build_ps_bool}
\$PrePackageEditorBuildResult = $(ps_single_quote "$pre_package_editor_build_result")
if (-not (Test-Path -LiteralPath \$PackageScriptPath)) {
throw "Higher-dimensional package script was not found at '\$PackageScriptPath'."
}
& \$PackageScriptPath -ProjectRoot \$ProjectRoot -ArchiveDirectory \$ArchiveDirectory -ValidationReportPath \$ValidationReportPath -PrePackageEditorBuildPerformed:\$PrePackageEditorBuildPerformed -PrePackageEditorBuildResult \$PrePackageEditorBuildResult${package_skip_build_clause}
exit \$LASTEXITCODE
EOF
)"
if run_or_print "$remote_ps_wrapper" --command "$package_command"; then
:
else
step_exit="$?"
return "$step_exit"
fi
fi
if [[ "$skip_browser_automation" != "true" && "$skip_browser_report_pull" != "true" ]]; then
echo "Pulling remote browser automation index.json back into docs/generated."
if run_or_print \
"$remote_pull_wrapper" \
--map "${browser_report_remote_path}::${browser_report_local_path}"
then
:
else
step_exit="$?"
return "$step_exit"
fi
fi
if [[ "$skip_package" != "true" && "$skip_package_report_pull" != "true" ]]; then
echo "Pulling remote higher-dimensional package report back into docs/generated."
if run_or_print \
"$remote_pull_wrapper" \
--map "${package_report_remote_path}::${package_report_local_path}"
then
:
else
step_exit="$?"
return "$step_exit"
fi
fi
if [[ "$skip_package" != "true" && "$skip_package_report_pull" != "true" && "$skip_summary_refresh" != "true" ]]; then
echo "Refreshing the checked-in website package-validation summary."
if run_or_print node "$summary_refresh_script"; then
:
else
step_exit="$?"
return "$step_exit"
fi
fi
}
active_worktree_root="$worktree_root"
if run_refresh_for_root "$worktree_root"; then
:
else
primary_exit="$?"
if [[ -n "$fallback_worktree_root" ]]; then
echo "Primary remote refresh failed on ${worktree_root}. Falling back to ${fallback_worktree_root}." >&2
run_refresh_for_root "$fallback_worktree_root"
active_worktree_root="$fallback_worktree_root"
else
exit "$primary_exit"
fi
fi
echo "Remote exact-source browser/package refresh complete through ${active_worktree_root}."