From 001b22e7a6ebbdcbb1b30f5fb7264529f356c910 Mon Sep 17 00:00:00 2001 From: hs liu Date: Wed, 14 Oct 2026 21:20:31 +0800 Subject: [PATCH] ci: Compatibility nightly + local Mac CI (cost-reduced) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add .github/workflows/nightly.yml (Compatibility): daily ubuntu·Node22 and ubuntu·DSH-alpha; weekly windows·Node24; skip schedule when main had no commits in the window (24h/7d); workflow_dispatch always runs. No macOS in GHA — hs runs that locally. Tighten test.yml: cancel-in-progress only off main, paths-ignore docs on push only, job/step timeouts, persist-credentials: false. Add ds-bot/scripts/local-ci.sh and npm run ci:local for the Mac gate. Verifier: - ran: python3 yaml.safe_load on both workflows; bash -n local-ci.sh; Codex review → PASS (round 1) - not run: full npm test / GHA (workflow + script only); actionlint not installed on the box --- .github/workflows/nightly.yml | 156 ++++++++++++++++++++++++++++++++++ .github/workflows/test.yml | 16 +++- ds-bot/package.json | 3 +- ds-bot/scripts/local-ci.sh | 59 +++++++++++++ 4 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/nightly.yml create mode 100755 ds-bot/scripts/local-ci.sh diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 00000000..825ce88c --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,156 @@ +# Compatibility matrix behind the slim PR gate (#31): the PR gate ships one job, +# ubuntu · Node 24 · DSH 0.2.0-rc.2. This workflow restores Windows · Node 24 · +# DSH 0.2.0-rc.2, ubuntu · Node 22 · DSH 0.2.0-rc.2 and ubuntu · Node 24 · +# DSH 0.2.1-alpha.1 on schedule and dispatch, and supersedes the matrix/compat +# parts of #29. A window in which main had no commits is skipped; a schedule only +# fires on the default branch. macOS runs locally on a Mac with `npm run ci:local` +# (ds-bot/scripts/local-ci.sh), never on a GitHub-hosted runner. + +name: Compatibility + +on: + schedule: + - cron: "0 16 * * *" # daily 00:00 Asia/Shanghai + - cron: "0 17 * * 6" # weekly Sunday 01:00 Asia/Shanghai + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: compat-${{ github.ref }} + cancel-in-progress: false + +jobs: + changes: + name: Window check + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + run: ${{ steps.gate.outputs.run }} + steps: + - name: Check out main with full history + if: github.event_name == 'schedule' + uses: actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Decide whether the window has commits on main + id: gate + shell: bash + run: | + run=false + since="" + case "${{ github.event.schedule }}" in + "0 16 * * *") since="24 hours ago" ;; + "0 17 * * 6") since="7 days ago" ;; + esac + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + run=true + reason="manual dispatch always runs" + elif [ -n "$since" ] && [ -n "$(git log --since="$since" --pretty=oneline)" ]; then + run=true + reason="main had commits in the last ${since}" + else + reason="main had no commits in the window (since ${since})" + fi + echo "run=$run" >> "$GITHUB_OUTPUT" + { + echo "### Compatibility run decision" + echo "" + echo "- event: \`${{ github.event_name }}\`" + echo "- window: ${since:-n/a (dispatch)}" + echo "- run: \`${run}\`: ${reason}" + } >> "$GITHUB_STEP_SUMMARY" + + daily: + name: compat · ${{ matrix.os }} · Node ${{ matrix.node }} · DSH ${{ matrix.dsh }} + needs: changes + if: needs.changes.outputs.run == 'true' && (github.event_name == 'workflow_dispatch' || github.event.schedule == '0 16 * * *') + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-latest, node: 22, dsh: 0.2.0-rc.2 } + - { os: ubuntu-latest, node: 24, dsh: 0.2.1-alpha.1 } + defaults: + run: + shell: bash + working-directory: ds-bot + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: npm + cache-dependency-path: ds-bot/package-lock.json + - name: npm ci + run: npm ci --no-fund --no-audit + timeout-minutes: 5 + - name: Install DSH ${{ matrix.dsh }} + run: npm run harness -- --no-save "@deepseek-ai/dsh@$DSH" + timeout-minutes: 5 + env: + DSH: ${{ matrix.dsh }} + - name: Lint + run: npm run lint + - name: Build (client bundle is up to date) + run: node scripts/build-client.mjs --check + - name: Tests + run: npm test + - name: Plugin tests (social) + working-directory: ds-bot/plugins/social + run: node --import ../../test/harness-resolve.mjs --test "test/*.test.js" + - name: Plugin tests (tree) + working-directory: ds-bot/plugins/tree + run: node --test "test/*.test.js" + + weekly: + name: compat · ${{ matrix.os }} · Node ${{ matrix.node }} · DSH ${{ matrix.dsh }} + needs: changes + if: needs.changes.outputs.run == 'true' && (github.event_name == 'workflow_dispatch' || github.event.schedule == '0 17 * * 6') + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - { os: windows-latest, node: 24, dsh: 0.2.0-rc.2 } + defaults: + run: + shell: bash + working-directory: ds-bot + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: npm + cache-dependency-path: ds-bot/package-lock.json + - name: npm ci + run: npm ci --no-fund --no-audit + timeout-minutes: 5 + - name: Install DSH ${{ matrix.dsh }} + run: npm run harness -- --no-save "@deepseek-ai/dsh@$DSH" + timeout-minutes: 5 + env: + DSH: ${{ matrix.dsh }} + - name: Lint + run: npm run lint + - name: Build (client bundle is up to date) + run: node scripts/build-client.mjs --check + - name: Tests + run: npm test + - name: Plugin tests (social) + working-directory: ds-bot/plugins/social + run: node --import ../../test/harness-resolve.mjs --test "test/*.test.js" + - name: Plugin tests (tree) + working-directory: ds-bot/plugins/tree + run: node --test "test/*.test.js" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 12cf91c3..efe966a5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,6 +3,10 @@ name: Test on: push: branches: [main] + # Docs-only pushes do not need the shipgate. + # pull_request must NOT ignore docs: Test is a required check there, and a + # skipped required check would block docs-only pull requests. + paths-ignore: ['docs/**', '**/*.md'] pull_request: workflow_dispatch: @@ -11,17 +15,18 @@ permissions: concurrency: group: test-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: test: name: ${{ matrix.os }} · Node ${{ matrix.node }} · DSH ${{ matrix.dsh }} runs-on: ${{ matrix.os }} + timeout-minutes: 20 strategy: fail-fast: false matrix: # Slim PR/push shipgate: one cheap job. - # Dropped from the required matrix (restore later as nightly/manual if needed): + # The dropped legs run in the Compatibility workflow (nightly.yml): # - windows-latest · Node 24 · DSH 0.2.0-rc.2 # - ubuntu-latest · Node 22 · DSH 0.2.0-rc.2 # - ubuntu-latest · Node 24 · DSH 0.2.1-alpha.1 @@ -33,14 +38,19 @@ jobs: working-directory: ds-bot steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} cache: npm cache-dependency-path: ds-bot/package-lock.json - - run: npm ci --no-fund --no-audit + - name: npm ci + run: npm ci --no-fund --no-audit + timeout-minutes: 5 - name: Install DSH ${{ matrix.dsh }} run: npm run harness -- --no-save "@deepseek-ai/dsh@${{ matrix.dsh }}" + timeout-minutes: 5 - run: npm test - name: Build (client bundle is up to date) run: node scripts/build-client.mjs --check diff --git a/ds-bot/package.json b/ds-bot/package.json index f9ed3501..b4aa72f8 100644 --- a/ds-bot/package.json +++ b/ds-bot/package.json @@ -48,7 +48,8 @@ "test": "node --import ./test/harness-resolve.mjs --test \"test/*.test.js\"", "lint": "node scripts/lint.mjs", "harness": "npm install --prefix dev/harness --legacy-peer-deps=false --no-package-lock --no-fund --no-audit", - "check": "sh dev/check.sh" + "check": "sh dev/check.sh", + "ci:local": "bash scripts/local-ci.sh" }, "peerDependencies": { "@deepseek-ai/cordis": "*", diff --git a/ds-bot/scripts/local-ci.sh b/ds-bot/scripts/local-ci.sh new file mode 100755 index 00000000..443b74fe --- /dev/null +++ b/ds-bot/scripts/local-ci.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# Local compatibility CI for a Mac: the PR gate plus the plugin suites, with no +# GitHub-hosted runner. Run it from anywhere: ds-bot/scripts/local-ci.sh +set -euo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")/.." + +step="(start)" + +on_exit() { + local status=$? + if [ "$status" -eq 0 ]; then + echo "PASS: $(git rev-parse --short HEAD)" + else + echo "FAIL: $step (exit $status)" + fi +} +trap on_exit EXIT + +echo "FlyBot local CI" +echo "tip: $(git rev-parse --short HEAD) ($(git rev-parse HEAD))" +echo "branch: $(git branch --show-current)" + +step="node -v (require major >= 22)" +echo "=== $step ===" +node -v +node_version="$(node -v)" +node_version="${node_version#v}" +if [ "${node_version%%.*}" -lt 22 ]; then + exit 1 +fi + +step="npm ci" +echo "=== $step ===" +npm ci --no-fund --no-audit + +step="Install DSH 0.2.0-rc.2" +echo "=== $step ===" +npm run harness -- --no-save @deepseek-ai/dsh@0.2.0-rc.2 + +step="lint" +echo "=== $step ===" +npm run lint + +step="Build (client bundle is up to date)" +echo "=== $step ===" +node scripts/build-client.mjs --check + +step="tests" +echo "=== $step ===" +npm test + +step="plugin tests (social)" +echo "=== $step ===" +(cd plugins/social && node --import ../../test/harness-resolve.mjs --test "test/*.test.js") + +step="plugin tests (tree)" +echo "=== $step ===" +(cd plugins/tree && node --test "test/*.test.js")