ci: replace the long-dead Travis config with a GitHub Actions gate - #349
Merged
Conversation
test_client_try_import used `isinstance(x, collections.Callable)`.
`collections.Callable` has been an alias for `collections.abc.Callable`
since 3.3 and was removed in 3.10, so the test raises:
AttributeError: module 'collections' has no attribute 'Callable'
The suite therefore only passes on Python <= 3.9. .travis.yml tests
3.5/3.6/3.7, which is why this was never noticed -- and Travis has not
run on this repo for a long time either.
Uses the builtin `callable()` instead of `collections.abc.Callable`:
same semantics (collections.abc.Callable.__subclasshook__ just checks
for __call__), and it drops the now-unused `collections` import rather
than keeping one around for a single predicate.
Verified on Python 3.11.9:
before 1 failed, 47 passed, 37 skipped
after 48 passed, 37 skipped
本仓此前 .github/ 下只有 PR 模板,唯一的 CI 是 .travis.yml(travis-ci.org 已下线, 且只测 3.5/3.6/3.7)——等于 ucloud/services 下全部生成代码从来没有过闸门。 codegen PR 要能自动合并,前提是先有一个「会红」的门禁;但这个门禁必须只对本轮 产物负责,否则它自己就成了自动合并的阻塞源。 - 新增 .github/workflows/ci.yml:触发限 pull_request/push 到 master(不用裸 [push, pull_request]),显式 permissions: contents: read;ci-syntax / lint / test-cov 三个 job 汇总成恒名的 ci-gate(needs + if: always(),任一 failure/cancelled 即 exit 1),分支保护只需把 ci-gate 配成 required check。 codecov 上传是 test job 内的 step 且 continue-on-error,不进 ci-gate 的 needs ——外部服务抖动不该拦下合并。所有语言命令都经 Makefile target,yml 里不写裸命令。 - 新增 scripts/ci-syntax.sh,Makefile 的 ci-syntax 改为调它。两条闸都只用 stdlib: G1 `compileall -q ucloud` 覆盖全部生成代码(现有 lint 显式 --exclude=ucloud/services,恰好把生成代码排除在外,这层一直是空的)。 G2 `scripts/dup-check.py` 用 ast 补编译器抓不住的重复声明——python 里重复的 def/class 不是语法错误,后者静默覆盖前者,compileall 一律 exit 0。 - 判定边界:**全量扫描整棵 ucloud/,但只对本轮变更的文件阻断**,其余命中打印成 告警、不计入退出码。原因是 G2 在本仓存量就有一处命中——uphost 的 get_phost_disk_upgrade_price 被生成了两遍,后者是已删除 API 的旧快照(publish 集合追加式存储,保留了 API 改名前的形态),根因在数据侧、改 SDK 仓库无效。 整棵树一律阻断的话,发**任何一个**产品(UDisk、UNet……)的 codegen PR 都会被 这处与本次发布毫无关系的问题判红,mergeable_state 变 unstable,自动合并永久 失效——那正是这套门禁要解决的问题本身。 同源决策见 ucloud-sdk-release/scripts/python-fatal-check.sh(2026-07-31), 已被 pipeline 2507836 实证:那次发的是 UHost+UAI-Modelverse,根本没重新生成 uphost,那处重复照样被扫了出来。 变更集取环境变量 CI_BASE_SHA:`git diff --name-only $CI_BASE_SHA...HEAD` 里 ucloud/ 下的 .py(三点式取 merge-base→HEAD,正好等于本 PR 引入的改动; --diff-filter=d 排除删除项)。yml 里 PR 事件给 base.sha、push 事件给 before, checkout 配 fetch-depth: 0(浅克隆下 base sha 不在本地对象库,必然解析不出)。 未设置或解析不出(force push、全零 sha、无共同祖先)→ fail-closed 退回整棵树 严格判定并打印退回原因。本地不设该变量看到的就是整棵树严格判定,与退回路径 一致,不存在「本地绿 / CI 红」的分叉。 dup-check.py 因此加了 --strict-list(仍全量扫描,只有清单内文件的命中才阻断), 原有的 `dup-check.py <目录>...` 用法不变,本地与退回路径都走它。 - ci-syntax 里**不放** `black --check`,与 go 的 ci-syntax 带 gofmtcheck.sh 不对称, 是有意为之:生成侧 ucloud-sdk-release 的 python:format job 用 `pip install -U black` + `make fmt`,永远拿当天最新版格式化后提交;而 black 每年改一次稳定风格(实测本仓 392 个文件在 24.8.0/24.10.0 下全过,25.1.0 起有 211 个被判需重排)。校验端无论钉哪个版本,迟早与生成侧偏斜、把每个 codegen PR 恒判为红——同样是自动合并要解决的问题本身。格式化归生成侧,门禁只管代码能不能 用:非法标识符这类真缺陷 compileall 已经拦得住(实测 `def uai-modelverse(self):` → exit 1,而纯格式的 `def foo( a,b ):` → exit 0)。理由写在 Makefile 注释里。 - Makefile test-cov 补 --cov-report=term --cov-report=xml:codecov-action 只上传 现成的报告文件,不像 Travis 时代的 codecov bash uploader 会顺手跑 coverage xml; 不出 xml 的话 README 上那个 Codecov 徽章就再也不会更新。 - 新增 .github/workflows/compat.yml:只挂 schedule + workflow_dispatch,不挂 pull_request/push——它问的是「SDK 今天还能跑在哪些 python 上」,与单个 PR 改了 什么无关,挂到 PR 上只会在每个 codegen PR 上多出一排无关 check、干扰门禁判读。 矩阵 3.8–3.14、fail-fast: false。下界 3.8 是实测结论,不是 setup.py 声明的 3.5: actions/python-versions 对 3.7 最后只出到 3.7.17 且只有 linux-20.04/22.04 产物, 而 ubuntu-latest 现指向 Ubuntu 24.04,setup-python 根本装不出 3.7;3.8.18 有 linux-24.04 产物,且本地 3.8.20 上 pip install -e .[ci]、make lint、make test-cov 均 exit 0(48 passed / 37 skipped)。 - 删 .travis.yml:服务已下线,留着只会让人误以为还有 CI 在跑。 setup.py 不动:CI 不跑 black,[ci] 就不需要它;在 [ci] 里钉 black 版本反而会把 生成侧 python:format 那步的 `pip install -e ".[ci]"` 降级,干扰生成端。 本地实跑(macOS bash 3.2 + python 3.11.9): 不设 CI_BASE_SHA → exit 1,G2 报出 uphost 那处存量 CI_BASE_SHA=父提交、只改干净的 udisk → exit 0,uphost 那处降为告警仍打印 同上但 udisk 注入语法错 / 重复方法 → exit 1(对本轮变更文件仍然阻断) CI_BASE_SHA 给不存在的 sha / 全零 sha → 退回整棵树严格判定,exit 1,打印退回原因 make lint / make test-cov → exit 0,未受影响
兼容矩阵是纯巡检,不参与门禁判定,也没人会盯一个非阻断的定时任务。 声明下界还成不成立是另一个问题,要验的时候手工跑一次即可, 不必为它常驻一条每天运行的 workflow。
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




What
.github/workflows/ci.yml—ci-syntax/lint/test, aggregated byci-gate.github/workflows/compat.yml— Python 3.8 → 3.14, scheduled onlyscripts/ci-syntax.sh+scripts/dup-check.py— the two gatesMakefile:ci-syntaxtarget;test-covalso emitscoverage.xml.travis.yml— it only ever tested 3.5/3.6/3.7 and has not run in yearsThe two gates
python -m compileall -q ucloud— the code can actually be importedscripts/dup-check.py— duplicate top-level defs, duplicate methods in a class, duplicate importsG2 exists because
compileallexits 0 on duplicates (later definition silently wins, which is legal Python, not a syntax error). That is exactly how a generated client can lose a method: two APIs whose names differ only in case both become onesnake_casemethod, and the surviving one is the wrong one.Only this PR's files block
ci-syntaxscans the whole tree but only fails on files changed in this PR; hits in untouched files are printed as warnings and don't affect the exit code.Without this, one pre-existing defect anywhere in
ucloud/services/would red-flag every product's codegen PR forever. That isn't hypothetical — it has been observed: a release of UHost + UAI-Modelverse, which did not regenerateuphostat all, was still flagged by a stale finding inuphost/client.py.The changed set comes from
git diff --name-only --diff-filter=d "$CI_BASE_SHA...HEAD" -- ucloud(three-dot, so a moving base branch doesn't drag unrelated commits in).CI_BASE_SHAis supplied by the workflow andactions/checkoutusesfetch-depth: 0so the base commit is present. Fail-closed: if the variable is unset, unresolvable, or the diff fails, it falls back to strict whole-tree and prints why. Runningmake ci-syntaxlocally with no variable set gives the strict whole-tree result, so local and CI never disagree silently.No
black --checkin the gate — deliberateFormatting is the generator's job (its pipeline runs
make fmt), not the gate's, and the two ends cannot be pinned to the same version: the generation pipeline installs black with-U(always latest), so any pin here would drift apart immediately. Measured: 392 files pass under black 24.8.0/24.10.0, while 25.1.0 onward wants 211 of them reformatted (25.x changed docstring edge whitespace).It also adds nothing to correctness. The historical failure this might be expected to catch — a hyphenated product name backfilled into an invalid Python identifier — is caught by
compileallon its own:Also fixed
tests/test_unit/test_core/test_client.pyusedcollections.Callable, removed in Python 3.10 — the reasonmake test-covcould not run on any modern interpreter. (Already merged separately as #347.)Verified locally
Clean venv, Python 3.12.12,
pip install -e '.[ci]'exit 0:CI_BASE_SHA(strict whole tree)CI_BASE_SHAmake lint/make test-covExpected:
ci-gatewill be red on mergeOne pre-existing duplicate remains —
ucloud/services/uphost/client.py:417,499, both namedget_phost_disk_upgrade_price. Its root cause was in the data source and has already been fixed upstream, but the file in this repo only gets corrected when UPHost is next regenerated. Until then it is reported as a warning and does not block anything.