diff --git a/.github/actions/docker-e2e-plan/action.yml b/.github/actions/docker-e2e-plan/action.yml new file mode 100644 index 00000000000..4dbb354157d --- /dev/null +++ b/.github/actions/docker-e2e-plan/action.yml @@ -0,0 +1,145 @@ +name: Docker E2E plan and hydrate +description: > + Create a Docker E2E lane plan, expose GitHub outputs, and optionally hydrate + the prebuilt package artifact plus shared Docker images needed by the plan. +inputs: + mode: + description: prepare, chunk, or targeted. + required: true + chunk: + description: Release-path chunk for mode=chunk. + required: false + default: "" + lanes: + description: Comma/space separated lane names for targeted or prepare mode. + required: false + default: "" + include-openwebui: + description: Whether Open WebUI is included when planning release/prepare coverage. + required: false + default: "true" + include-release-path-suites: + description: Whether prepare mode should plan all release-path suites. + required: false + default: "false" + hydrate-artifacts: + description: Whether to download/pull artifacts required by the plan. + required: false + default: "true" +outputs: + credentials: + description: Comma-separated credential groups required by selected lanes. + value: ${{ steps.plan.outputs.credentials }} + needs_bare_image: + description: "1 when selected lanes require the bare Docker E2E image." + value: ${{ steps.plan.outputs.needs_bare_image }} + needs_e2e_image: + description: "1 when selected lanes require any Docker E2E image." + value: ${{ steps.plan.outputs.needs_e2e_image }} + needs_functional_image: + description: "1 when selected lanes require the functional Docker E2E image." + value: ${{ steps.plan.outputs.needs_functional_image }} + needs_live_image: + description: "1 when selected lanes require building the live Docker image." + value: ${{ steps.plan.outputs.needs_live_image }} + needs_package: + description: "1 when selected lanes require the OpenClaw package tarball." + value: ${{ steps.plan.outputs.needs_package }} + plan_json: + description: Path to the generated plan JSON. + value: ${{ steps.plan.outputs.plan_json }} +runs: + using: composite + steps: + - name: Plan Docker E2E lanes + id: plan + shell: bash + env: + MODE: ${{ inputs.mode }} + CHUNK: ${{ inputs.chunk }} + LANES: ${{ inputs.lanes }} + INCLUDE_OPENWEBUI: ${{ inputs.include-openwebui }} + INCLUDE_RELEASE_PATH_SUITES: ${{ inputs.include-release-path-suites }} + run: | + set -euo pipefail + mkdir -p .artifacts/docker-tests + + case "$MODE" in + prepare) + plan_path=".artifacts/docker-tests/plan.json" + if [[ "$INCLUDE_RELEASE_PATH_SUITES" == "true" ]]; then + export OPENCLAW_DOCKER_ALL_PROFILE=release-path + export OPENCLAW_DOCKER_ALL_PLAN_RELEASE_ALL=1 + elif [[ -n "$LANES" ]]; then + export OPENCLAW_DOCKER_ALL_LANES="$LANES" + elif [[ "$INCLUDE_OPENWEBUI" == "true" ]]; then + export OPENCLAW_DOCKER_ALL_LANES=openwebui + fi + ;; + chunk) + if [[ -z "$CHUNK" ]]; then + echo "chunk input is required for Docker E2E chunk planning." >&2 + exit 1 + fi + export OPENCLAW_DOCKER_ALL_PROFILE=release-path + export OPENCLAW_DOCKER_ALL_CHUNK="$CHUNK" + plan_path=".artifacts/docker-tests/release-${CHUNK}-plan.json" + ;; + targeted) + if [[ -z "$LANES" ]]; then + echo "lanes input is required for Docker E2E targeted planning." >&2 + exit 1 + fi + export OPENCLAW_DOCKER_ALL_LANES="$LANES" + plan_path=".artifacts/docker-tests/targeted-plan.json" + ;; + *) + echo "mode must be prepare, chunk, or targeted. Got: $MODE" >&2 + exit 1 + ;; + esac + + export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI="$INCLUDE_OPENWEBUI" + node scripts/test-docker-all.mjs --plan-json > "$plan_path" + node scripts/docker-e2e.mjs github-outputs "$plan_path" >> "$GITHUB_OUTPUT" + echo "plan_json=$plan_path" >> "$GITHUB_OUTPUT" + + - name: Download OpenClaw Docker E2E package + if: inputs.hydrate-artifacts == 'true' && steps.plan.outputs.needs_package == '1' + uses: actions/download-artifact@v8 + with: + name: docker-e2e-package + path: .artifacts/docker-e2e-package + + - name: Pull shared bare Docker E2E image + if: inputs.hydrate-artifacts == 'true' && steps.plan.outputs.needs_bare_image == '1' + shell: bash + run: | + set -euo pipefail + docker pull "${OPENCLAW_DOCKER_E2E_BARE_IMAGE}" + + - name: Pull shared functional Docker E2E image + if: inputs.hydrate-artifacts == 'true' && steps.plan.outputs.needs_functional_image == '1' + shell: bash + run: | + set -euo pipefail + docker pull "${OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE}" + + - name: Validate Docker E2E credentials + if: inputs.hydrate-artifacts == 'true' + shell: bash + env: + CREDENTIALS: ${{ steps.plan.outputs.credentials }} + run: | + set -euo pipefail + credentials=",$CREDENTIALS," + if [[ "$credentials" == *",openai,"* ]]; then + [[ -n "${OPENAI_API_KEY:-}" ]] || { + echo "OPENAI_API_KEY is required for selected Docker E2E lanes." >&2 + exit 1 + } + fi + if [[ "$credentials" == *",anthropic,"* && -z "${ANTHROPIC_API_TOKEN:-}" && -z "${ANTHROPIC_API_KEY:-}" ]]; then + echo "ANTHROPIC_API_TOKEN or ANTHROPIC_API_KEY is required for selected Docker E2E lanes." >&2 + exit 1 + fi diff --git a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml index 1a0c9bcf160..46e953cd2de 100644 --- a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml +++ b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml @@ -466,54 +466,13 @@ jobs: - name: Hydrate live auth/profile inputs run: bash scripts/ci-hydrate-live-auth.sh - - name: Plan Docker E2E chunk + - name: Plan and hydrate Docker E2E chunk id: plan - shell: bash - run: | - set -euo pipefail - mkdir -p .artifacts/docker-tests - export OPENCLAW_DOCKER_ALL_PROFILE=release-path - export OPENCLAW_DOCKER_ALL_CHUNK="${DOCKER_E2E_CHUNK}" - export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI="${INCLUDE_OPENWEBUI}" - node scripts/test-docker-all.mjs --plan-json > ".artifacts/docker-tests/release-${DOCKER_E2E_CHUNK}-plan.json" - node scripts/docker-e2e.mjs github-outputs ".artifacts/docker-tests/release-${DOCKER_E2E_CHUNK}-plan.json" >> "$GITHUB_OUTPUT" - - - name: Download OpenClaw Docker E2E package - if: steps.plan.outputs.needs_package == '1' - uses: actions/download-artifact@v8 + uses: ./.github/actions/docker-e2e-plan with: - name: docker-e2e-package - path: .artifacts/docker-e2e-package - - - name: Pull shared bare Docker E2E image - if: steps.plan.outputs.needs_bare_image == '1' - shell: bash - run: | - set -euo pipefail - docker pull "${OPENCLAW_DOCKER_E2E_BARE_IMAGE}" - - - name: Pull shared functional Docker E2E image - if: steps.plan.outputs.needs_functional_image == '1' - shell: bash - run: | - set -euo pipefail - docker pull "${OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE}" - - - name: Validate chunk credentials - shell: bash - run: | - set -euo pipefail - credentials=",${{ steps.plan.outputs.credentials }}," - if [[ "$credentials" == *",openai,"* ]]; then - [[ -n "${OPENAI_API_KEY:-}" ]] || { - echo "OPENAI_API_KEY is required for selected Docker E2E lanes." >&2 - exit 1 - } - fi - if [[ "$credentials" == *",anthropic,"* && -z "${ANTHROPIC_API_TOKEN:-}" && -z "${ANTHROPIC_API_KEY:-}" ]]; then - echo "ANTHROPIC_API_TOKEN or ANTHROPIC_API_KEY is required for selected Docker E2E lanes." >&2 - exit 1 - fi + mode: chunk + chunk: ${{ matrix.chunk_id }} + include-openwebui: ${{ inputs.include_openwebui }} - name: Run Docker E2E chunk shell: bash @@ -632,53 +591,13 @@ jobs: - name: Hydrate live auth/profile inputs run: bash scripts/ci-hydrate-live-auth.sh - - name: Plan targeted Docker E2E lanes + - name: Plan and hydrate targeted Docker E2E lanes id: plan - shell: bash - run: | - set -euo pipefail - mkdir -p .artifacts/docker-tests - export OPENCLAW_DOCKER_ALL_LANES="${DOCKER_E2E_LANES}" - export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI="${INCLUDE_OPENWEBUI}" - node scripts/test-docker-all.mjs --plan-json > .artifacts/docker-tests/targeted-plan.json - node scripts/docker-e2e.mjs github-outputs .artifacts/docker-tests/targeted-plan.json >> "$GITHUB_OUTPUT" - - - name: Download OpenClaw Docker E2E package - if: steps.plan.outputs.needs_package == '1' - uses: actions/download-artifact@v8 + uses: ./.github/actions/docker-e2e-plan with: - name: docker-e2e-package - path: .artifacts/docker-e2e-package - - - name: Pull shared bare Docker E2E image - if: steps.plan.outputs.needs_bare_image == '1' - shell: bash - run: | - set -euo pipefail - docker pull "${OPENCLAW_DOCKER_E2E_BARE_IMAGE}" - - - name: Pull shared functional Docker E2E image - if: steps.plan.outputs.needs_functional_image == '1' - shell: bash - run: | - set -euo pipefail - docker pull "${OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE}" - - - name: Validate targeted lane credentials - shell: bash - run: | - set -euo pipefail - credentials=",${{ steps.plan.outputs.credentials }}," - if [[ "$credentials" == *",openai,"* ]]; then - [[ -n "${OPENAI_API_KEY:-}" ]] || { - echo "OPENAI_API_KEY is required for selected Docker E2E lanes." >&2 - exit 1 - } - fi - if [[ "$credentials" == *",anthropic,"* && -z "${ANTHROPIC_API_TOKEN:-}" && -z "${ANTHROPIC_API_KEY:-}" ]]; then - echo "ANTHROPIC_API_TOKEN or ANTHROPIC_API_KEY is required for selected Docker E2E lanes." >&2 - exit 1 - fi + mode: targeted + lanes: ${{ inputs.docker_lanes }} + include-openwebui: ${{ inputs.include_openwebui }} - name: Run targeted Docker E2E lanes shell: bash @@ -807,25 +726,13 @@ jobs: - name: Plan Docker E2E images id: plan - shell: bash - env: - DOCKER_E2E_LANES: ${{ inputs.docker_lanes }} - INCLUDE_RELEASE_PATH_SUITES: ${{ inputs.include_release_path_suites }} - INCLUDE_OPENWEBUI: ${{ inputs.include_openwebui }} - run: | - set -euo pipefail - mkdir -p .artifacts/docker-tests - if [[ "${INCLUDE_RELEASE_PATH_SUITES}" == "true" ]]; then - export OPENCLAW_DOCKER_ALL_PROFILE=release-path - export OPENCLAW_DOCKER_ALL_PLAN_RELEASE_ALL=1 - elif [[ -n "${DOCKER_E2E_LANES}" ]]; then - export OPENCLAW_DOCKER_ALL_LANES="${DOCKER_E2E_LANES}" - elif [[ "${INCLUDE_OPENWEBUI}" == "true" ]]; then - export OPENCLAW_DOCKER_ALL_LANES=openwebui - fi - export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI="${INCLUDE_OPENWEBUI}" - node scripts/test-docker-all.mjs --plan-json > .artifacts/docker-tests/plan.json - node scripts/docker-e2e.mjs github-outputs .artifacts/docker-tests/plan.json >> "$GITHUB_OUTPUT" + uses: ./.github/actions/docker-e2e-plan + with: + mode: prepare + lanes: ${{ inputs.docker_lanes }} + include-release-path-suites: ${{ inputs.include_release_path_suites }} + include-openwebui: ${{ inputs.include_openwebui }} + hydrate-artifacts: "false" - name: Setup Node environment if: steps.plan.outputs.needs_package == '1'