Files
jubaoliangandCursor 51d5e49247 fix(ci): repair FnOS workflow parse error and stop re-running CI per release
The FnOS FPK workflow kept a stray env block when the rolling-release step was
removed, so GitHub rejected the whole file and Release's dispatch failed with
"'env' is already defined" — silently, because that job is continue-on-error.

CI also ran the full suite three times per release (release PR, main push, sync
PR) on identical trees. Drop the main push build, since PR checks already run on
the merge result, and skip the post-release sync PR, which is auto-merged before
its checks even start.

Release now passes the tag to the sync workflow so the branch is named after the
version instead of the constant "manual", which every release force-pushed over.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 10:29:31 +08:00

130 lines
5.0 KiB
YAML

name: CI
# Pull requests only. GitHub runs PR checks on the merge result, so a push
# build on main would re-test content that the release / feature PR already
# proved green.
on:
pull_request:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
quality:
name: "Python ${{ matrix.python-version }}"
runs-on: ubuntu-latest
# Post-release main → develop sync PRs carry main's already-tested tree and
# are auto-merged by the bot before checks finish. See sync-main-to-develop.
if: ${{ !startsWith(github.head_ref, 'chore/sync-develop-after-') }}
strategy:
fail-fast: false
matrix:
python-version: ["3.12"]
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: make install
- name: Lint
run: make lint
- name: Type check
run: make typecheck
- name: Test
run: make test
test-windows:
name: Windows / Python 3.12
runs-on: windows-latest
if: ${{ !startsWith(github.head_ref, 'chore/sync-develop-after-') }}
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
python-version: "3.12"
- name: Install dependencies
run: make install
- name: Lint
run: make lint
- name: Type check
run: make typecheck
- name: Test
run: make test
live-tests:
name: "Live tests (real credentials)"
runs-on: ubuntu-latest
# Only the main repo may access secrets; fork PRs get none and must skip.
if: >-
github.event.pull_request.head.repo.full_name == github.repository &&
!startsWith(github.head_ref, 'chore/sync-develop-after-')
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
python-version: "3.12"
- name: Install dependencies
run: make install
# Secrets are injected as env vars. Missing secrets => empty values =>
# the live tests auto-skip (CI stays green). Never `echo`/print secrets.
- name: Run live tests
env:
OPENAI_API_KEY: ${{ secrets.LIVE_OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.LIVE_OPENAI_BASE_URL }}
OPENAI_MODEL_NAME: ${{ secrets.LIVE_OPENAI_MODEL_NAME }}
OSS_KIND: ${{ secrets.LIVE_OSS_KIND }}
OSS_ENDPOINT: ${{ secrets.LIVE_OSS_ENDPOINT }}
OSS_ACCESS_KEY: ${{ secrets.LIVE_OSS_ACCESS_KEY }}
OSS_SECRET_KEY: ${{ secrets.LIVE_OSS_SECRET_KEY }}
OSS_BUCKET: ${{ secrets.LIVE_OSS_BUCKET }}
OSS_REGION: ${{ secrets.LIVE_OSS_REGION }}
OSS_PREFIX: ${{ secrets.LIVE_OSS_PREFIX }}
ALI_OSS_KIND: ${{ secrets.LIVE_ALI_OSS_KIND }}
ALI_OSS_ENDPOINT: ${{ secrets.LIVE_ALI_OSS_ENDPOINT }}
ALI_OSS_ACCESS_KEY: ${{ secrets.LIVE_ALI_OSS_ACCESS_KEY }}
ALI_OSS_SECRET_KEY: ${{ secrets.LIVE_ALI_OSS_SECRET_KEY }}
ALI_OSS_BUCKET: ${{ secrets.LIVE_ALI_OSS_BUCKET }}
ALI_OSS_REGION: ${{ secrets.LIVE_ALI_OSS_REGION }}
ALI_OSS_PREFIX: ${{ secrets.LIVE_ALI_OSS_PREFIX }}
CONNECTOR_TENCENT_DOCS_TOKEN: ${{ secrets.LIVE_CONNECTOR_TENCENT_DOCS_TOKEN }}
CONNECTOR_TENCENT_MEETING_TOKEN: ${{ secrets.LIVE_CONNECTOR_TENCENT_MEETING_TOKEN }}
CONNECTOR_TENCENT_WEIYUN_TOKEN: ${{ secrets.LIVE_CONNECTOR_TENCENT_WEIYUN_TOKEN }}
CONNECTOR_YOUDAO_NOTE_TOKEN: ${{ secrets.LIVE_CONNECTOR_YOUDAO_NOTE_TOKEN }}
CONNECTOR_TENCENT_NEWS_TOKEN: ${{ secrets.LIVE_CONNECTOR_TENCENT_NEWS_TOKEN }}
CONNECTOR_WECHAT_READING_TOKEN: ${{ secrets.LIVE_CONNECTOR_WECHAT_READING_TOKEN }}
CONNECTOR_QQ_MUSIC_TOKEN: ${{ secrets.LIVE_CONNECTOR_QQ_MUSIC_TOKEN }}
CONNECTOR_FLIGGY_TOKEN: ${{ secrets.LIVE_CONNECTOR_FLIGGY_TOKEN }}
CONNECTOR_BAIDU_MAP_TOKEN: ${{ secrets.LIVE_CONNECTOR_BAIDU_MAP_TOKEN }}
CONNECTOR_CTRIP_WENDAO_TOKEN: ${{ secrets.LIVE_CONNECTOR_CTRIP_WENDAO_TOKEN }}
CONNECTOR_TENCENT_IMA_TOKEN: ${{ secrets.LIVE_CONNECTOR_TENCENT_IMA_TOKEN }}
CONNECTOR_TENCENT_IMA_CLIENT_ID: ${{ secrets.LIVE_CONNECTOR_TENCENT_IMA_CLIENT_ID }}
CONNECTOR_TENCENT_LEXIANG_TOKEN: ${{ secrets.LIVE_CONNECTOR_TENCENT_LEXIANG_TOKEN }}
CONNECTOR_TENCENT_LEXIANG_COMPANY_FROM: ${{ secrets.LIVE_CONNECTOR_TENCENT_LEXIANG_COMPANY_FROM }}
CONNECTOR_MEITUAN_TRAVEL_TOKEN: ${{ secrets.LIVE_CONNECTOR_MEITUAN_TRAVEL_TOKEN }}
CONNECTOR_YUANDIAN_TOKEN: ${{ secrets.LIVE_CONNECTOR_YUANDIAN_TOKEN }}
# Channel probes (WeChat iLink + Feishu)
WEIXIN_BOT_UIN: ${{ secrets.LIVE_WEIXIN_BOT_UIN }}
WEIXIN_TOKEN: ${{ secrets.LIVE_WEIXIN_TOKEN }}
WEIXIN_BASE_URL: ${{ secrets.LIVE_WEIXIN_BASE_URL }}
FEISHU_APP_ID: ${{ secrets.LIVE_FEISHU_APP_ID }}
FEISHU_APP_SECRET: ${{ secrets.LIVE_FEISHU_APP_SECRET }}
run: make test-live