4b9b9a3962
Build and Publish Patched OpenClaw / sync-upstream (push) Has been skipped
minimal-validate baseline hygiene OK
Build and Publish Patched OpenClaw / test (push) Successful in 36m0s
CI / Patch overlay integrity (push) Successful in 13s
minimal-ci / minimal-validate (push) Successful in 25s
CI / all-required (push) Successful in 12s
187 lines
7.7 KiB
YAML
187 lines
7.7 KiB
YAML
name: Build and Publish Patched OpenClaw
|
|
|
|
# This repo stores ONLY the patched files on top of upstream openclaw.
|
|
# CI clones upstream, overlays our patches, then tests/builds/publishes.
|
|
#
|
|
# This is a PUBLISH pipeline: its `test`/build/publish jobs clone upstream from
|
|
# github.com and `pnpm install` from registry.npmjs.org. The self-hosted Gitea
|
|
# runner pool is air-gapped from the public internet, so those steps hard-fail
|
|
# with ENOTFOUND — a pipeline/network condition, not a code defect. Running it on
|
|
# `pull_request` made every PR red and (post require-all/['*']) would block ALL
|
|
# merges. PR correctness is gated by ci.yml (Patch overlay integrity +
|
|
# CI/all-required), which is hermetic. Keep push/schedule so the pipeline still
|
|
# runs where outbound network is available; drop the pull_request trigger.
|
|
on:
|
|
push:
|
|
branches: [main, feature/*]
|
|
schedule:
|
|
- cron: '0 9 * * *'
|
|
|
|
env:
|
|
NODE_VERSION: '22'
|
|
UPSTREAM_REPO: https://github.com/openclaw/openclaw.git
|
|
REGISTRY: git.moleculesai.app
|
|
IMAGE_NAME: molecule-ai/openclaw
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
path: patches
|
|
|
|
- name: Clone upstream openclaw
|
|
run: |
|
|
UPSTREAM_REF=$(awk '/^Upstream:/ {print $2; exit}' patches/PATCHED_VERSION.md)
|
|
test -n "$UPSTREAM_REF"
|
|
git init upstream
|
|
git -C upstream remote add origin ${{ env.UPSTREAM_REPO }}
|
|
git -C upstream fetch --depth 1 origin "$UPSTREAM_REF"
|
|
git -C upstream checkout --detach FETCH_HEAD
|
|
|
|
- name: Apply patches over upstream
|
|
run: |
|
|
cp -r patches/src/. upstream/src/
|
|
cp patches/Dockerfile upstream/Dockerfile 2>/dev/null || true
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
|
|
- name: Install pnpm
|
|
run: npm install -g pnpm@9
|
|
|
|
- name: Install dependencies
|
|
working-directory: upstream
|
|
run: pnpm install --no-frozen-lockfile
|
|
|
|
- name: Run MCP patch tests
|
|
working-directory: upstream
|
|
run: |
|
|
pnpm exec vitest run \
|
|
src/agents/pi-bundle-mcp-runtime.test.ts \
|
|
src/agents/pi-bundle-mcp-push-notification.test.ts \
|
|
src/agents/pi-bundle-mcp-optimizations.test.ts
|
|
|
|
- name: Build patched upstream
|
|
working-directory: upstream
|
|
run: pnpm build
|
|
|
|
- name: Upload build artifact
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: openclaw-dist
|
|
path: upstream/dist/
|
|
retention-days: 7
|
|
|
|
sync-upstream:
|
|
runs-on: ubuntu-latest
|
|
if: github.event_name == 'schedule'
|
|
# The version bump must go through review like every other change.
|
|
# `main` is branch-protected (the pre-receive hook declines direct
|
|
# pushes), so this job pushes the bump to a `sync/upstream-<sha>` branch
|
|
# and opens a PR — it must NEVER `git push origin main`. The old direct
|
|
# push failed on every scheduled run ("pre-receive hook declined") and
|
|
# turned main's combined status red.
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Configure Git
|
|
run: |
|
|
git config user.name "gitea-actions[bot]"
|
|
git config user.email "gitea-actions[bot]@git.moleculesai.app"
|
|
|
|
- name: Add upstream remote
|
|
run: git remote add upstream ${{ env.UPSTREAM_REPO }}
|
|
|
|
- name: Fetch upstream
|
|
run: git fetch upstream main
|
|
|
|
- name: Check if upstream has new commits
|
|
id: check
|
|
run: |
|
|
# Compare latest upstream commit with what our patches were based on
|
|
UPSTREAM_SHA=$(git rev-parse upstream/main)
|
|
PATCHED_VERSION=$(cat PATCHED_VERSION.md 2>/dev/null | grep "^Upstream:" | cut -d' ' -f2 || echo "")
|
|
if [ "$UPSTREAM_SHA" = "$PATCHED_VERSION" ]; then
|
|
echo "sync_needed=false" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "sync_needed=true" >> $GITHUB_OUTPUT
|
|
echo "upstream_sha=$UPSTREAM_SHA" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Run tests on new upstream (smoke check before reporting)
|
|
id: smoke
|
|
if: steps.check.outputs.sync_needed == 'true'
|
|
run: |
|
|
git clone --depth 1 ${{ env.UPSTREAM_REPO }} /tmp/upstream-new
|
|
cp -r src/. /tmp/upstream-new/src/
|
|
cd /tmp/upstream-new
|
|
npm install -g pnpm@9
|
|
pnpm install --no-frozen-lockfile
|
|
if pnpm exec vitest run src/agents/pi-bundle-mcp-runtime.test.ts; then
|
|
echo "smoke=pass" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "smoke=fail" >> $GITHUB_OUTPUT
|
|
echo "::warning::MCP patch tests failed against new upstream — the sync PR needs a manual rebase of the patch overlay before merge."
|
|
fi
|
|
|
|
# Open a PR with the version bump instead of pushing to the
|
|
# branch-protected `main` (the old `git push origin main` was declined
|
|
# by the pre-receive hook on every scheduled run).
|
|
- name: Open upstream-sync PR
|
|
if: steps.check.outputs.sync_needed == 'true'
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.AUTO_SYNC_TOKEN || secrets.GITHUB_TOKEN }}
|
|
UPSTREAM_SHA: ${{ steps.check.outputs.upstream_sha }}
|
|
SMOKE: ${{ steps.smoke.outputs.smoke }}
|
|
REPO: ${{ github.repository }}
|
|
# Talk to the SAME Gitea instance the runner already uses for
|
|
# checkout/push (`github.server_url`), not the hardcoded public
|
|
# CF-fronted host — the self-hosted runner reaches Gitea on its
|
|
# internal address and egress to the CF edge is blocked.
|
|
API_BASE: ${{ github.server_url }}/api/v1
|
|
run: |
|
|
set -euo pipefail
|
|
BRANCH="sync/upstream-${UPSTREAM_SHA}"
|
|
|
|
# Idempotent: if the sync branch already exists upstream, an earlier
|
|
# run already opened the PR — nothing to do.
|
|
if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then
|
|
echo "Branch $BRANCH already exists — sync PR already open, skipping."
|
|
exit 0
|
|
fi
|
|
|
|
printf 'Upstream: %s\nUpdated: %s\n' \
|
|
"$UPSTREAM_SHA" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > PATCHED_VERSION.md
|
|
git add PATCHED_VERSION.md
|
|
git commit -m "chore: note upstream sync to ${UPSTREAM_SHA}"
|
|
git push origin "HEAD:${BRANCH}"
|
|
|
|
if [ "$SMOKE" = "fail" ]; then
|
|
BODY="Scheduled upstream sync to \`${UPSTREAM_SHA}\`.\n\n⚠️ MCP patch smoke tests FAILED against the new upstream — the patch overlay needs a manual rebase before this can merge. Do not merge until \`test\` is green."
|
|
else
|
|
BODY="Scheduled upstream sync to \`${UPSTREAM_SHA}\`.\n\nMCP patch smoke tests passed against the new upstream. Review + let \`test\` run before merge."
|
|
fi
|
|
|
|
# Create the PR via the Gitea API. 201 = created.
|
|
HTTP=$(curl -s -o /tmp/pr_resp.json -w '%{http_code}' \
|
|
-X POST "${API_BASE}/repos/${REPO}/pulls" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"head\":\"${BRANCH}\",\"base\":\"main\",\"title\":\"chore: sync upstream openclaw to ${UPSTREAM_SHA}\",\"body\":\"${BODY}\"}")
|
|
echo "PR create HTTP ${HTTP}"
|
|
cat /tmp/pr_resp.json
|
|
# 201 created; 409 = a PR for this head already exists (idempotent OK).
|
|
if [ "$HTTP" != "201" ] && [ "$HTTP" != "409" ]; then
|
|
echo "::error::Failed to open upstream-sync PR (HTTP ${HTTP})"
|
|
exit 1
|
|
fi
|