Skip to content

pre-merge

pre-merge #59

Workflow file for this run

name: pre-merge
on:
pull_request:
branches: [master]
schedule:
- cron: '0 8 * * *'
workflow_dispatch:
inputs:
mode:
description: "Which lane to run"
type: choice
options:
- pre-merge
- nightly
default: pre-merge
jobs:
detect-changes:
if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'pre-merge')
runs-on: ubuntu-latest
outputs:
pika: ${{ steps.filter.outputs.pika || 'true' }}
pikachat: ${{ steps.filter.outputs.pikachat || 'true' }}
pikachat_openclaw_e2e: ${{ steps.filter.outputs.pikachat_openclaw_e2e || 'true' }}
agent_contracts: ${{ steps.filter.outputs.agent_contracts || 'true' }}
rmp: ${{ steps.filter.outputs.rmp || 'true' }}
notifications: ${{ steps.filter.outputs.notifications || 'true' }}
fixture: ${{ steps.filter.outputs.fixture || 'true' }}
steps:
- uses: dorny/paths-filter@v3
if: github.event_name == 'pull_request'
id: filter
with:
filters: |
pika:
- 'Cargo.toml'
- 'Cargo.lock'
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'justfile'
- '.github/**'
- 'rust/**'
- 'cli/**'
- 'crates/pika-desktop/**'
- 'crates/pika-media/**'
- 'crates/pika-marmot-runtime/**'
- 'crates/pika-nse/**'
- 'crates/pika-relay-profiles/**'
- 'crates/pika-tls/**'
- 'uniffi-bindgen/**'
- 'android/**'
- 'ios/**'
- 'docs/**'
- 'scripts/**'
- 'tools/**'
pikachat:
- 'Cargo.toml'
- 'Cargo.lock'
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'justfile'
- '.github/workflows/pre-merge.yml'
- 'cli/**'
- 'crates/pikachat-sidecar/**'
- 'crates/pika-marmot-runtime/**'
- 'crates/pika-relay-profiles/**'
- 'pikachat-openclaw/**'
- 'crates/pika-media/**'
- 'crates/pika-tls/**'
pikachat_openclaw_e2e:
- 'Cargo.toml'
- 'Cargo.lock'
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'justfile'
- '.github/workflows/pre-merge.yml'
- 'cli/**'
- 'crates/pikahut/**'
- 'crates/pikachat-sidecar/**'
- 'crates/pika-marmot-runtime/**'
- 'crates/pika-relay-profiles/**'
- 'crates/pika-media/**'
- 'crates/pika-tls/**'
- 'tools/**'
- 'pikachat-openclaw/openclaw/extensions/pikachat-openclaw/**'
agent_contracts:
- 'Cargo.toml'
- 'Cargo.lock'
- 'cli/Cargo.toml'
- 'cli/src/**'
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'justfile'
- '.github/workflows/pre-merge.yml'
- 'crates/pika-agent-microvm/**'
- 'crates/pika-server/src/agent_api.rs'
- 'crates/pika-server/src/agent_api_v1_contract.rs'
- 'crates/pika-marmot-runtime/**'
- 'crates/pika-relay-profiles/**'
- 'crates/pikahut/src/**'
- 'crates/pikahut/tests/integration_deterministic.rs'
- 'docs/agent-ci.md'
rmp:
- 'Cargo.toml'
- 'Cargo.lock'
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'justfile'
- '.github/workflows/pre-merge.yml'
- 'crates/rmp-cli/**'
notifications:
- 'Cargo.toml'
- 'Cargo.lock'
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'justfile'
- '.github/workflows/pre-merge.yml'
- 'crates/pika-notifications/**'
- 'crates/pika-server/**'
fixture:
- 'Cargo.toml'
- 'Cargo.lock'
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'justfile'
- '.github/workflows/pre-merge.yml'
- 'crates/pikahut/**'
- 'crates/pika-marmot-runtime/**'
- 'cmd/pika-relay/**'
check-pika:
needs: [detect-changes]
if: needs.detect-changes.outputs.pika == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-gradle-v1-${{ runner.os }}
path: ~/.gradle
- run: nix develop .#default -c just pre-merge-pika
check-pikachat:
needs: [detect-changes]
if: needs.detect-changes.outputs.pikachat == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
environment:
name: ${{ github.event_name == 'pull_request' && github.actor != 'justinmoon' && github.actor != 'futurepaul' && github.actor != 'AnthonyRonning' && github.actor != 'benthecarman' && github.actor != 'clarkmoody' && 'ci-approval' || 'ci-auto' }}
steps:
- uses: actions/checkout@v4
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- run: nix develop .#default -c just pre-merge-pikachat
check-pikachat-openclaw-e2e:
needs: [detect-changes]
if: needs.detect-changes.outputs.pikachat_openclaw_e2e == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
environment:
name: ${{ github.event_name == 'pull_request' && github.actor != 'justinmoon' && github.actor != 'futurepaul' && github.actor != 'AnthonyRonning' && github.actor != 'benthecarman' && github.actor != 'clarkmoody' && 'ci-approval' || 'ci-auto' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: openclaw/openclaw
path: openclaw
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- run: OPENCLAW_DIR=openclaw nix develop .#default -c just openclaw-pikachat-e2e
check-agent-contracts:
needs: [detect-changes]
if: needs.detect-changes.outputs.agent_contracts == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- run: nix develop .#default -c just pre-merge-agent-contracts
check-rmp:
needs: [detect-changes]
if: needs.detect-changes.outputs.rmp == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- run: nix develop .#rmp -c just pre-merge-rmp
check-notifications:
needs: [detect-changes]
if: needs.detect-changes.outputs.notifications == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- run: nix develop .#default -c just pre-merge-notifications
check-fixture:
needs: [detect-changes]
if: needs.detect-changes.outputs.fixture == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- run: nix develop .#default -c just pre-merge-fixture
pre-merge:
if: always() && (github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'pre-merge'))
needs: [detect-changes, check-pika, check-pikachat, check-pikachat-openclaw-e2e, check-agent-contracts, check-rmp, check-notifications, check-fixture]
runs-on: ubuntu-latest
steps:
- name: Evaluate lane results
run: |
failed=""
echo "detect-changes outputs:"
echo " pika=${{ needs.detect-changes.outputs.pika }}"
echo " pikachat=${{ needs.detect-changes.outputs.pikachat }}"
echo " pikachat_openclaw_e2e=${{ needs.detect-changes.outputs.pikachat_openclaw_e2e }}"
echo " agent_contracts=${{ needs.detect-changes.outputs.agent_contracts }}"
echo " rmp=${{ needs.detect-changes.outputs.rmp }}"
echo " notifications=${{ needs.detect-changes.outputs.notifications }}"
echo " fixture=${{ needs.detect-changes.outputs.fixture }}"
echo "Blocking pre-merge lanes:"
for lane in pika pikachat pikachat-openclaw-e2e agent-contracts rmp notifications fixture; do
result=""
case "$lane" in
pika) result="${{ needs.check-pika.result }}" ;;
pikachat) result="${{ needs.check-pikachat.result }}" ;;
pikachat-openclaw-e2e) result="${{ needs.check-pikachat-openclaw-e2e.result }}" ;;
agent-contracts) result="${{ needs.check-agent-contracts.result }}" ;;
rmp) result="${{ needs.check-rmp.result }}" ;;
notifications) result="${{ needs.check-notifications.result }}" ;;
fixture) result="${{ needs.check-fixture.result }}" ;;
esac
if [[ "$result" == "success" || "$result" == "skipped" ]]; then
echo "check-$lane: $result (ok)"
else
echo "check-$lane: $result (FAILED)"
failed="${failed}check-${lane} "
fi
done
echo "Advisory integration lanes:"
echo "nightly-* jobs are non-blocking for pre-merge and run only on schedule/manual nightly mode."
if [[ -n "$failed" ]]; then
echo "::error::Failed lanes: $failed"
exit 1
fi
nightly-linux:
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'nightly')
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- run: nix develop .#default -c just rmp-nightly-linux
nightly-pika:
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'nightly')
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- run: nix develop .#default -c just nightly-pika-e2e
nightly-pikachat:
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'nightly')
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: openclaw/openclaw
path: openclaw
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- run: OPENCLAW_DIR=openclaw nix develop .#default -c just nightly-pikachat
nightly-pika-ui-android:
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'nightly')
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-nix-v1-${{ runner.os }}
path: /nix
- name: Fix /nix ownership
run: |
if [ -d /nix ] && [ "$(stat -c %u /nix)" != "$(id -u)" ]; then
sudo chown -R "$(id -u):$(id -g)" /nix
fi
- uses: nixbuild/nix-quick-install-action@v30
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-home-v1-${{ runner.os }}
path: ~/.cargo
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-cargo-target-v1-${{ runner.os }}
path: target
- uses: useblacksmith/stickydisk@v1
with:
key: ${{ github.repository }}-gradle-v1-${{ runner.os }}
path: ~/.gradle
- run: |
nix develop .#default -c ./tools/android-avd-ensure
PIKA_ANDROID_FORCE_GUI=0 \
PIKA_ANDROID_EMULATOR_ARGS="-no-window" \
nix develop .#default -c just android-ui-e2e-local
nightly-pika-ui-ios:
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'nightly')
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- uses: nixbuild/nix-quick-install-action@v30
- run: nix develop .#default -c just ios-ui-test
nightly-primal-ios-interop:
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'nightly')
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- uses: nixbuild/nix-quick-install-action@v30
- run: nix develop .#default -c just ios-ui-test
- run: nix develop .#default -c just nightly-primal-ios-interop
nightly:
if: always() && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'nightly'))
needs: [nightly-linux, nightly-pika, nightly-pikachat, nightly-pika-ui-android, nightly-pika-ui-ios, nightly-primal-ios-interop]
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Check nightly results
id: check
run: |
failed=""
if [[ "${{ needs.nightly-linux.result }}" != "success" ]]; then
echo "nightly-linux failed"
failed="${failed}- **nightly-linux**: ${{ needs.nightly-linux.result }}\n"
fi
if [[ "${{ needs.nightly-pika.result }}" != "success" ]]; then
echo "nightly-pika failed"
failed="${failed}- **nightly-pika**: ${{ needs.nightly-pika.result }}\n"
fi
if [[ "${{ needs.nightly-pikachat.result }}" != "success" ]]; then
echo "nightly-pikachat failed"
failed="${failed}- **nightly-pikachat**: ${{ needs.nightly-pikachat.result }}\n"
fi
if [[ "${{ needs.nightly-pika-ui-android.result }}" != "success" ]]; then
echo "nightly-pika-ui-android failed"
failed="${failed}- **nightly-pika-ui-android**: ${{ needs.nightly-pika-ui-android.result }}\n"
fi
if [[ "${{ needs.nightly-pika-ui-ios.result }}" != "success" ]]; then
echo "nightly-pika-ui-ios failed"
failed="${failed}- **nightly-pika-ui-ios**: ${{ needs.nightly-pika-ui-ios.result }}\n"
fi
if [[ "${{ needs.nightly-primal-ios-interop.result }}" != "success" ]]; then
echo "nightly-primal-ios-interop failed"
failed="${failed}- **nightly-primal-ios-interop**: ${{ needs.nightly-primal-ios-interop.result }}\n"
fi
if [[ -n "$failed" ]]; then
{
echo "failed<<EOF"
echo -e "$failed"
echo "EOF"
echo "has_failures=true"
} >> "$GITHUB_OUTPUT"
fi
- name: Open issue on failure
if: steps.check.outputs.has_failures == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Skip creating a duplicate if an open nightly-failure issue already exists
existing=$(gh issue list \
--repo "${{ github.repository }}" \
--label "nightly-failure" \
--state open \
--limit 1 \
--json number \
--jq '.[0].number // empty')
run_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
date=$(date -u +%Y-%m-%d)
if [[ -n "$existing" ]]; then
# Append a comment to the existing issue instead of opening a new one
gh issue comment "$existing" \
--repo "${{ github.repository }}" \
--body "### Nightly still failing — ${date}
${{ steps.check.outputs.failed }}
[Run log](${run_url})"
else
gh issue create \
--repo "${{ github.repository }}" \
--title "Nightly failure — ${date}" \
--label "nightly-failure" \
--body "## Nightly CI failed
${{ steps.check.outputs.failed }}
**Run:** ${run_url}
This issue was auto-opened by CI. It will stop receiving comments once all nightly lanes pass again."
fi
- name: Fail the job
if: steps.check.outputs.has_failures == 'true'
run: exit 1