diff --git a/.github/workflows/fresh-host-acceptance.yml b/.github/workflows/fresh-host-acceptance.yml index cce442b..bb01451 100644 --- a/.github/workflows/fresh-host-acceptance.yml +++ b/.github/workflows/fresh-host-acceptance.yml @@ -4,15 +4,15 @@ on: workflow_call: inputs: docker_pull_parallelism: - description: Parallelism for hosted macOS Docker image pulling. + description: Parallelism for hosted Docker image pulling. required: false type: string default: "2" docker_pull_max_attempts: - description: Retry attempts for hosted macOS Docker image pulling. + description: Retry attempts for hosted Docker image pulling. required: false type: string - default: "3" + default: "5" enable_package_cache: description: Restore uv and npm download caches for bootstrap. required: false @@ -21,15 +21,15 @@ on: workflow_dispatch: inputs: docker_pull_parallelism: - description: Parallelism for hosted macOS Docker image pulling. + description: Parallelism for hosted Docker image pulling. required: true type: string default: "2" docker_pull_max_attempts: - description: Retry attempts for hosted macOS Docker image pulling. + description: Retry attempts for hosted Docker image pulling. required: true type: string - default: "3" + default: "5" enable_package_cache: description: Restore uv and npm download caches for bootstrap. required: true diff --git a/.github/workflows/fresh-host-core.yml b/.github/workflows/fresh-host-core.yml index d3b6fa2..6a9b4bf 100644 --- a/.github/workflows/fresh-host-core.yml +++ b/.github/workflows/fresh-host-core.yml @@ -10,7 +10,8 @@ on: docker_pull_max_attempts: required: false type: string - default: "3" + # Give the registry backoff room for transient Docker Hub blips. + default: "5" enable_package_cache: required: false type: boolean @@ -21,9 +22,6 @@ permissions: env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" - FRESH_HOST_DOCKER_PULL_PARALLELISM: "4" - # 5 retries let registry backoff survive transient Docker Hub issues - FRESH_HOST_DOCKER_PULL_MAX_ATTEMPTS: "5" FRESH_HOST_CACHE_ROOT: ${{ github.workspace }}/.github-cache UV_CACHE_DIR: ${{ github.workspace }}/.github-cache/uv npm_config_cache: ${{ github.workspace }}/.github-cache/npm @@ -34,6 +32,9 @@ jobs: name: Linux Fresh Host (${{ matrix.profile }}) runs-on: ubuntu-latest timeout-minutes: 75 + env: + FRESH_HOST_SELECTED_DOCKER_PULL_PARALLELISM: ${{ inputs.docker_pull_parallelism }} + FRESH_HOST_SELECTED_DOCKER_PULL_MAX_ATTEMPTS: ${{ inputs.docker_pull_max_attempts }} strategy: fail-fast: false matrix: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index acc0c2f..0800fc5 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -61,6 +61,6 @@ jobs: uses: ./.github/workflows/fresh-host-core.yml with: docker_pull_parallelism: "2" - docker_pull_max_attempts: "3" + docker_pull_max_attempts: "5" enable_package_cache: true secrets: inherit diff --git a/tests/suites/contracts/repo/test_ci_workflow_surfaces.py b/tests/suites/contracts/repo/test_ci_workflow_surfaces.py index b862051..c466fae 100644 --- a/tests/suites/contracts/repo/test_ci_workflow_surfaces.py +++ b/tests/suites/contracts/repo/test_ci_workflow_surfaces.py @@ -212,6 +212,38 @@ def test_fresh_host_core_workflow_stays_thin() -> None: assert ".github/scripts/fresh_host_images.py" not in text +def test_fresh_host_core_linux_job_honors_pull_tuning_inputs() -> None: + """The Linux fresh-host job must honor per-caller docker_pull_* inputs, like macOS.""" + loaded_workflow: object = yaml.safe_load(_workflow_text("fresh-host-core.yml")) + assert isinstance(loaded_workflow, dict) + workflow = cast(dict[object, object], loaded_workflow) + + jobs = _as_str_object_dict(workflow.get("jobs")) + assert jobs is not None + + # Both platform jobs must map the selected pull tuning env to the per-caller inputs. + for job_name in ("linux-fresh-host", "macos-fresh-host"): + job = _as_str_object_dict(jobs.get(job_name)) + assert job is not None, job_name + job_env = _as_str_object_dict(job.get("env")) + assert job_env is not None, job_name + assert ( + job_env.get("FRESH_HOST_SELECTED_DOCKER_PULL_PARALLELISM") + == "${{ inputs.docker_pull_parallelism }}" + ), job_name + assert ( + job_env.get("FRESH_HOST_SELECTED_DOCKER_PULL_MAX_ATTEMPTS") + == "${{ inputs.docker_pull_max_attempts }}" + ), job_name + + # The hard-coded top-level fallbacks must stay gone; if they return, the Linux prepull + # would silently override the per-caller inputs again. + workflow_env = _as_str_object_dict(workflow.get("env")) + assert workflow_env is not None + assert "FRESH_HOST_DOCKER_PULL_PARALLELISM" not in workflow_env + assert "FRESH_HOST_DOCKER_PULL_MAX_ATTEMPTS" not in workflow_env + + def test_fresh_host_workflow_preserves_dispatch_inputs_and_concurrency_controls() -> None: """Fresh-host acceptance should keep explicit tuning inputs and concurrency guards.""" text = _workflow_text("fresh-host-acceptance.yml")