Install Smoke #19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Install Smoke | |
| on: | |
| schedule: | |
| - cron: "17 3 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| run_bun_global_install_smoke: | |
| description: Run the Bun global install image-provider smoke | |
| required: false | |
| default: false | |
| type: boolean | |
| update_baseline_version: | |
| description: Baseline openclaw version or dist-tag for installer update smoke | |
| required: false | |
| default: latest | |
| type: string | |
| workflow_call: | |
| inputs: | |
| ref: | |
| description: Git ref to validate | |
| required: false | |
| type: string | |
| run_bun_global_install_smoke: | |
| description: Run the Bun global install image-provider smoke | |
| required: false | |
| default: true | |
| type: boolean | |
| update_baseline_version: | |
| description: Baseline openclaw version or dist-tag for installer update smoke | |
| required: false | |
| default: latest | |
| type: string | |
| permissions: | |
| contents: read | |
| packages: write | |
| concurrency: | |
| group: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && format('{0}-{1}-{2}', github.workflow, github.event_name, github.run_id) || format('{0}-{1}', github.workflow, github.ref) }} | |
| cancel-in-progress: ${{ github.event_name != 'workflow_call' }} | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| jobs: | |
| preflight: | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| docs_only: ${{ steps.manifest.outputs.docs_only }} | |
| run_install_smoke: ${{ steps.manifest.outputs.run_install_smoke }} | |
| run_fast_install_smoke: ${{ steps.manifest.outputs.run_fast_install_smoke }} | |
| run_full_install_smoke: ${{ steps.manifest.outputs.run_full_install_smoke }} | |
| run_bun_global_install_smoke: ${{ steps.manifest.outputs.run_bun_global_install_smoke }} | |
| target_sha: ${{ steps.manifest.outputs.target_sha }} | |
| dockerfile_image: ${{ steps.manifest.outputs.dockerfile_image }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| fetch-depth: 1 | |
| fetch-tags: false | |
| persist-credentials: false | |
| submodules: false | |
| - name: Build install-smoke CI manifest | |
| id: manifest | |
| env: | |
| OPENCLAW_CI_EVENT_NAME: ${{ github.event_name }} | |
| OPENCLAW_CI_WORKFLOW_BUN_GLOBAL_INSTALL_SMOKE: ${{ inputs.run_bun_global_install_smoke || 'false' }} | |
| run: | | |
| event_name="${OPENCLAW_CI_EVENT_NAME:-}" | |
| workflow_bun_global_install_smoke="${OPENCLAW_CI_WORKFLOW_BUN_GLOBAL_INSTALL_SMOKE:-false}" | |
| docs_only=false | |
| run_fast_install_smoke=true | |
| run_full_install_smoke=true | |
| run_bun_global_install_smoke=false | |
| run_install_smoke=true | |
| target_sha="$(git rev-parse HEAD)" | |
| owner="$(printf '%s' "${GITHUB_REPOSITORY_OWNER:-openclaw}" | tr '[:upper:]' '[:lower:]')" | |
| dockerfile_image="ghcr.io/${owner}/openclaw-dockerfile-smoke:${target_sha}" | |
| if [ "$event_name" = "schedule" ]; then | |
| run_bun_global_install_smoke=true | |
| elif [ "$event_name" = "workflow_dispatch" ] || [ "$event_name" = "workflow_call" ]; then | |
| if [ "$workflow_bun_global_install_smoke" = "true" ]; then | |
| run_bun_global_install_smoke=true | |
| fi | |
| fi | |
| { | |
| echo "docs_only=$docs_only" | |
| echo "run_install_smoke=$run_install_smoke" | |
| echo "run_fast_install_smoke=$run_fast_install_smoke" | |
| echo "run_full_install_smoke=$run_full_install_smoke" | |
| echo "run_bun_global_install_smoke=$run_bun_global_install_smoke" | |
| echo "target_sha=$target_sha" | |
| echo "dockerfile_image=$dockerfile_image" | |
| } >> "$GITHUB_OUTPUT" | |
| install-smoke-fast: | |
| needs: [preflight] | |
| if: needs.preflight.outputs.run_fast_install_smoke == 'true' && needs.preflight.outputs.run_full_install_smoke != 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2404 | |
| env: | |
| DOCKER_BUILD_SUMMARY: "false" | |
| DOCKER_BUILD_RECORD_UPLOAD: "false" | |
| steps: | |
| - name: Checkout CLI | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| - name: Set up Blacksmith Docker Builder | |
| uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1 | |
| with: | |
| max-cache-size-mb: 800000 | |
| # Keep release smoke builds bounded and log-producing. The Blacksmith | |
| # build action can leave jobs in-progress without step logs when a remote | |
| # builder stalls; an explicit buildx invocation fails closed instead. | |
| - name: Build root Dockerfile smoke image | |
| run: | | |
| timeout 45m docker buildx build \ | |
| --progress=plain \ | |
| --load \ | |
| --build-arg OPENCLAW_EXTENSIONS=matrix \ | |
| -t openclaw-dockerfile-smoke:local \ | |
| -t openclaw-ext-smoke:local \ | |
| -f ./Dockerfile \ | |
| . | |
| - name: Run root Dockerfile CLI smoke | |
| run: | | |
| docker run --rm --entrypoint sh openclaw-dockerfile-smoke:local -lc ' | |
| which openclaw && | |
| openclaw --version && | |
| node -e " | |
| const fs = require(\"node:fs\"); | |
| const path = require(\"node:path\"); | |
| const pkg = require(\"/app/package.json\"); | |
| for (const [dep, rel] of Object.entries(pkg.pnpm?.patchedDependencies ?? {})) { | |
| const absolute = path.join(\"/app\", rel); | |
| if (!fs.existsSync(absolute)) { | |
| throw new Error(`missing patch for ${dep}: ${rel}`); | |
| } | |
| } | |
| " | |
| ' | |
| - name: Run agents delete shared workspace Docker CLI smoke | |
| env: | |
| OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE: openclaw-dockerfile-smoke:local | |
| OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD: "1" | |
| run: bash scripts/e2e/agents-delete-shared-workspace-docker.sh | |
| - name: Run Docker gateway network e2e | |
| env: | |
| OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE: openclaw-dockerfile-smoke:local | |
| OPENCLAW_GATEWAY_NETWORK_E2E_SKIP_BUILD: "1" | |
| run: bash scripts/e2e/gateway-network-docker.sh | |
| - name: Smoke test Dockerfile with matrix extension build arg | |
| run: | | |
| docker run --rm --entrypoint sh openclaw-ext-smoke:local -lc ' | |
| which openclaw && | |
| openclaw --version && | |
| node -e " | |
| const Module = require(\"node:module\"); | |
| const matrixPackage = require(\"/app/extensions/matrix/package.json\"); | |
| const requireFromMatrix = Module.createRequire(\"/app/extensions/matrix/package.json\"); | |
| const runtimeDeps = Object.keys(matrixPackage.dependencies ?? {}); | |
| if (runtimeDeps.length === 0) { | |
| throw new Error( | |
| \"matrix package has no declared runtime dependencies; smoke cannot validate install mirroring\", | |
| ); | |
| } | |
| for (const dep of runtimeDeps) { | |
| requireFromMatrix.resolve(dep); | |
| } | |
| const { spawnSync } = require(\"node:child_process\"); | |
| const run = spawnSync(\"openclaw\", [\"plugins\", \"list\", \"--json\"], { encoding: \"utf8\" }); | |
| if (run.status !== 0) { | |
| process.stderr.write(run.stderr || run.stdout || \"plugins list failed\\n\"); | |
| process.exit(run.status ?? 1); | |
| } | |
| const parsed = JSON.parse(run.stdout); | |
| const matrix = (parsed.plugins || []).find((entry) => entry.id === \"matrix\"); | |
| if (!matrix) { | |
| throw new Error(\"matrix plugin missing from bundled plugin list\"); | |
| } | |
| const matrixDiag = (parsed.diagnostics || []).filter( | |
| (diag) => | |
| typeof diag.source === \"string\" && | |
| diag.source.includes(\"/extensions/matrix\") && | |
| typeof diag.message === \"string\" && | |
| diag.message.includes(\"extension entry escapes package directory\"), | |
| ); | |
| if (matrixDiag.length > 0) { | |
| throw new Error( | |
| \"unexpected matrix diagnostics: \" + | |
| matrixDiag.map((diag) => diag.message).join(\"; \"), | |
| ); | |
| } | |
| " | |
| ' | |
| root_dockerfile_image: | |
| needs: [preflight] | |
| if: needs.preflight.outputs.run_full_install_smoke == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2404 | |
| outputs: | |
| image_ref: ${{ steps.image.outputs.image_ref }} | |
| env: | |
| DOCKER_BUILD_SUMMARY: "false" | |
| DOCKER_BUILD_RECORD_UPLOAD: "false" | |
| steps: | |
| - name: Checkout CLI | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| - name: Log in to GHCR | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| - name: Check for existing root Dockerfile smoke image | |
| id: existing | |
| env: | |
| IMAGE_REF: ${{ needs.preflight.outputs.dockerfile_image }} | |
| run: | | |
| set -euo pipefail | |
| if timeout 180s docker pull "$IMAGE_REF"; then | |
| echo "exists=true" >> "$GITHUB_OUTPUT" | |
| echo "Using existing root Dockerfile smoke image: \`$IMAGE_REF\`" >> "$GITHUB_STEP_SUMMARY" | |
| else | |
| echo "exists=false" >> "$GITHUB_OUTPUT" | |
| echo "No existing root Dockerfile smoke image found for \`$IMAGE_REF\`; building it." >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| - name: Set up Blacksmith Docker Builder | |
| if: steps.existing.outputs.exists != 'true' | |
| uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1 | |
| with: | |
| max-cache-size-mb: 800000 | |
| # Build once with the matrix extension and publish by target SHA. Use a | |
| # direct buildx command so release jobs emit Docker progress and time out. | |
| - name: Build and push root Dockerfile smoke image | |
| if: steps.existing.outputs.exists != 'true' | |
| env: | |
| IMAGE_REF: ${{ needs.preflight.outputs.dockerfile_image }} | |
| run: | | |
| timeout 45m docker buildx build \ | |
| --progress=plain \ | |
| --push \ | |
| --build-arg OPENCLAW_EXTENSIONS=matrix \ | |
| -t "$IMAGE_REF" \ | |
| -f ./Dockerfile \ | |
| . | |
| - name: Record root image output | |
| id: image | |
| env: | |
| IMAGE_REF: ${{ needs.preflight.outputs.dockerfile_image }} | |
| run: echo "image_ref=$IMAGE_REF" >> "$GITHUB_OUTPUT" | |
| - name: Summarize root image | |
| env: | |
| IMAGE_REF: ${{ needs.preflight.outputs.dockerfile_image }} | |
| TARGET_SHA: ${{ needs.preflight.outputs.target_sha }} | |
| run: | | |
| { | |
| echo "## Root Dockerfile smoke image" | |
| echo | |
| echo "- Target SHA: \`${TARGET_SHA}\`" | |
| echo "- Image: \`${IMAGE_REF}\`" | |
| echo "- Reused existing image: \`${{ steps.existing.outputs.exists }}\`" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| qr_package_install_smoke: | |
| needs: [preflight] | |
| if: needs.preflight.outputs.run_full_install_smoke == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2404 | |
| steps: | |
| - name: Checkout CLI | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| - name: Run QR package install smoke | |
| env: | |
| OPENCLAW_QR_SMOKE_FORCE_INSTALL: "1" | |
| run: bash scripts/e2e/qr-import-docker.sh | |
| root_dockerfile_smokes: | |
| needs: [preflight, root_dockerfile_image] | |
| if: needs.preflight.outputs.run_full_install_smoke == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2404 | |
| steps: | |
| - name: Checkout CLI | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| - name: Log in to GHCR | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| - name: Pull root Dockerfile smoke image | |
| env: | |
| IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }} | |
| run: timeout 600s docker pull "$IMAGE_REF" | |
| - name: Run root Dockerfile CLI smoke | |
| env: | |
| IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }} | |
| run: | | |
| docker run --rm --entrypoint sh "$IMAGE_REF" -lc 'which openclaw && openclaw --version' | |
| - name: Run agents delete shared workspace Docker CLI smoke | |
| env: | |
| OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE: ${{ needs.root_dockerfile_image.outputs.image_ref }} | |
| OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD: "1" | |
| run: bash scripts/e2e/agents-delete-shared-workspace-docker.sh | |
| - name: Run Docker gateway network e2e | |
| env: | |
| OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE: ${{ needs.root_dockerfile_image.outputs.image_ref }} | |
| OPENCLAW_GATEWAY_NETWORK_E2E_SKIP_BUILD: "1" | |
| run: bash scripts/e2e/gateway-network-docker.sh | |
| - name: Smoke test Dockerfile with matrix extension build arg | |
| env: | |
| IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }} | |
| run: | | |
| docker run --rm --entrypoint sh "$IMAGE_REF" -lc ' | |
| which openclaw && | |
| openclaw --version && | |
| node -e " | |
| const Module = require(\"node:module\"); | |
| const matrixPackage = require(\"/app/extensions/matrix/package.json\"); | |
| const requireFromMatrix = Module.createRequire(\"/app/extensions/matrix/package.json\"); | |
| const runtimeDeps = Object.keys(matrixPackage.dependencies ?? {}); | |
| if (runtimeDeps.length === 0) { | |
| throw new Error( | |
| \"matrix package has no declared runtime dependencies; smoke cannot validate install mirroring\", | |
| ); | |
| } | |
| for (const dep of runtimeDeps) { | |
| requireFromMatrix.resolve(dep); | |
| } | |
| const { spawnSync } = require(\"node:child_process\"); | |
| const run = spawnSync(\"openclaw\", [\"plugins\", \"list\", \"--json\"], { encoding: \"utf8\" }); | |
| if (run.status !== 0) { | |
| process.stderr.write(run.stderr || run.stdout || \"plugins list failed\\n\"); | |
| process.exit(run.status ?? 1); | |
| } | |
| const parsed = JSON.parse(run.stdout); | |
| const matrix = (parsed.plugins || []).find((entry) => entry.id === \"matrix\"); | |
| if (!matrix) { | |
| throw new Error(\"matrix plugin missing from bundled plugin list\"); | |
| } | |
| const matrixDiag = (parsed.diagnostics || []).filter( | |
| (diag) => | |
| typeof diag.source === \"string\" && | |
| diag.source.includes(\"/extensions/matrix\") && | |
| typeof diag.message === \"string\" && | |
| diag.message.includes(\"extension entry escapes package directory\"), | |
| ); | |
| if (matrixDiag.length > 0) { | |
| throw new Error( | |
| \"unexpected matrix diagnostics: \" + | |
| matrixDiag.map((diag) => diag.message).join(\"; \"), | |
| ); | |
| } | |
| " | |
| ' | |
| installer_smoke: | |
| needs: [preflight, root_dockerfile_image] | |
| if: needs.preflight.outputs.run_full_install_smoke == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2404 | |
| env: | |
| DOCKER_BUILD_SUMMARY: "false" | |
| DOCKER_BUILD_RECORD_UPLOAD: "false" | |
| steps: | |
| - name: Checkout CLI | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| - name: Log in to GHCR | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| - name: Pull root Dockerfile smoke image | |
| env: | |
| IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }} | |
| run: timeout 600s docker pull "$IMAGE_REF" | |
| - name: Set up Blacksmith Docker Builder | |
| uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1 | |
| with: | |
| max-cache-size-mb: 800000 | |
| - name: Build installer smoke image | |
| run: | | |
| timeout 20m docker buildx build \ | |
| --progress=plain \ | |
| --load \ | |
| -t openclaw-install-smoke:local \ | |
| -f ./scripts/docker/install-sh-smoke/Dockerfile \ | |
| ./scripts/docker | |
| - name: Build installer non-root image | |
| run: | | |
| timeout 20m docker buildx build \ | |
| --progress=plain \ | |
| --load \ | |
| -t openclaw-install-nonroot:local \ | |
| -f ./scripts/docker/install-sh-nonroot/Dockerfile \ | |
| ./scripts/docker | |
| - name: Setup Node environment for installer smoke | |
| uses: ./.github/actions/setup-node-env | |
| with: | |
| install-bun: "false" | |
| install-deps: "true" | |
| - name: Run installer docker tests | |
| env: | |
| OPENCLAW_INSTALL_URL: https://openclaw.ai/install.sh | |
| OPENCLAW_INSTALL_CLI_URL: https://openclaw.ai/install-cli.sh | |
| OPENCLAW_NO_ONBOARD: "1" | |
| OPENCLAW_INSTALL_SMOKE_SKIP_CLI: "1" | |
| OPENCLAW_INSTALL_SMOKE_SKIP_IMAGE_BUILD: "1" | |
| OPENCLAW_INSTALL_NONROOT_SKIP_IMAGE_BUILD: "1" | |
| OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT: "0" | |
| OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL: "1" | |
| OPENCLAW_INSTALL_SMOKE_SKIP_PREVIOUS: "1" | |
| OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE: ${{ inputs.update_baseline_version || 'latest' }} | |
| OPENCLAW_INSTALL_SMOKE_UPDATE_DIST_IMAGE: ${{ needs.root_dockerfile_image.outputs.image_ref }} | |
| OPENCLAW_INSTALL_SMOKE_UPDATE_SKIP_LOCAL_BUILD: "1" | |
| run: bash scripts/test-install-sh-docker.sh | |
| bun_global_install_smoke: | |
| needs: [preflight, root_dockerfile_image] | |
| if: needs.preflight.outputs.run_full_install_smoke == 'true' && needs.preflight.outputs.run_bun_global_install_smoke == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2404 | |
| steps: | |
| - name: Checkout CLI | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| - name: Log in to GHCR | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| - name: Pull root Dockerfile smoke image | |
| env: | |
| IMAGE_REF: ${{ needs.root_dockerfile_image.outputs.image_ref }} | |
| run: timeout 600s docker pull "$IMAGE_REF" | |
| - name: Setup Node environment for Bun smoke | |
| uses: ./.github/actions/setup-node-env | |
| with: | |
| install-bun: "true" | |
| install-deps: "true" | |
| - name: Run Bun global install image-provider smoke | |
| env: | |
| OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE: ${{ needs.root_dockerfile_image.outputs.image_ref }} | |
| OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD: "0" | |
| run: bash scripts/e2e/bun-global-install-smoke.sh | |
| docker-e2e-fast: | |
| needs: [preflight] | |
| if: needs.preflight.outputs.run_fast_install_smoke == 'true' || needs.preflight.outputs.run_full_install_smoke == 'true' | |
| runs-on: blacksmith-16vcpu-ubuntu-2404 | |
| timeout-minutes: 12 | |
| env: | |
| DOCKER_BUILD_SUMMARY: "false" | |
| DOCKER_BUILD_RECORD_UPLOAD: "false" | |
| steps: | |
| - name: Checkout CLI | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| - name: Set up Blacksmith Docker Builder | |
| uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1 | |
| with: | |
| max-cache-size-mb: 800000 | |
| - name: Setup Node environment for package smoke | |
| uses: ./.github/actions/setup-node-env | |
| with: | |
| install-bun: "false" | |
| install-deps: "true" |