From f7e5818fefb5a6f857fc1c0237b03d15958449fe Mon Sep 17 00:00:00 2001 From: linsamtw Date: Tue, 26 May 2026 01:00:16 +0800 Subject: [PATCH] ci: add GitHub Actions CI + PyPI trusted-publishing workflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ci.yml: on push(master)/PR, run pytest + smoke + the ChatGPT instructions build (8000-char guard) across Python 3.10/3.11/3.12. All offline — the live-API regression runner stays manual (needs FINMIND_TOKEN). - publish.yml: pushing a version tag (vX.Y.Z) builds with `uv build`, runs `twine check`, then uploads via PyPI Trusted Publishing (OIDC, pypa/gh-action-pypi-publish) — no API token stored. Guards that the pushed tag matches the pyproject version. Also runnable via workflow_dispatch. One-time PyPI-side setup (documented in publish.yml header): add a pending trusted publisher (project finmind-mcp, repo FinMind/FinMind-MCP, workflow publish.yml, environment pypi) + create the `pypi` GitHub environment. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 37 +++++++++++++++++ .github/workflows/publish.yml | 77 +++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..82503a9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + +# 只跑離線檢查(pytest 全 mock、smoke 用假 token、build_instructions 純本地)。 +# regression/runner.py 會打 live API、需要 FINMIND_TOKEN,故不放 CI,由發版前人工跑。 + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + python-version: ${{ matrix.python-version }} + enable-cache: true + + - name: Install dependencies + run: uv sync --extra dev + + - name: Unit tests (mocked, offline) + run: uv run pytest -q + + - name: Stdio smoke test + run: uv run python smoke.py + + - name: ChatGPT instructions build (must stay under the 8000-char Action limit) + run: uv run python chatgpt/build_instructions.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..a4cf2b5 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,77 @@ +name: Publish to PyPI + +# 推一個新的版本 tag(vX.Y.Z)就自動 build + 上傳 PyPI(也可手動 workflow_dispatch)。 +# 用 PyPI Trusted Publishing(OIDC)—— 不需要存任何 API token / secret。 +# +# 一次性設定(使用者在 PyPI 端做,我做不了): +# 1. https://pypi.org/manage/account/publishing/ → Add a new pending publisher +# PyPI Project Name: finmind-mcp +# Owner: FinMind +# Repository name: FinMind-MCP +# Workflow name: publish.yml +# Environment name: pypi +# (專案還沒上 PyPI 沒關係,用 "pending publisher",第一次發版會自動建立專案) +# 2. GitHub repo → Settings → Environments → 新增名為 `pypi` 的 environment +# (名稱要跟上面 PyPI 設定一致;可另設保護規則,例如限定 reviewer 才能發版) +# +# 發版流程(tag 驅動): +# - 先把 pyproject.toml 的 version bump 好(PyPI 版本號不可重複) +# - git tag vX.Y.Z(要跟 version 一致,下方 job 會檢查) +# - git push origin vX.Y.Z ← 推 tag 就觸發本 workflow,自動 build → 上傳 PyPI + +on: + push: + tags: + - "v[0-9]*" # vX.Y.Z + - "[0-9]*" # 也接受沒有 v 前綴的 X.Y.Z + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Verify pushed tag matches pyproject version + if: startsWith(github.ref, 'refs/tags/') + run: | + VERSION=$(grep -m1 '^version' pyproject.toml | sed -E 's/.*"(.*)".*/\1/') + TAG="${GITHUB_REF_NAME#v}" + echo "pyproject version: $VERSION pushed tag: $TAG" + if [ "$VERSION" != "$TAG" ]; then + echo "::error::pushed tag ($TAG) does not match pyproject version ($VERSION). Bump the version or fix the tag." + exit 1 + fi + + - name: Build sdist + wheel + run: uv build + + - name: Check distribution metadata + run: uvx twine check dist/* + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + pypi-publish: + needs: build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/project/finmind-mcp/ + permissions: + id-token: write # OIDC token for PyPI Trusted Publishing — no password needed + steps: + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: dist + path: dist/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1