code-complexity-stats-pr
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCode complexity / cost stats on every PR
每个PR上的代码复杂度/成本统计
A GitHub Actions workflow that runs
(Sloc, Cloc and Code) over the repo on each pull request and posts the results —
including a COCOMO estimated cost/effort to build the codebase — as a single
sticky comment that updates in place on every push. Drop-in workflow:
.
scctemplates/code-complexity.yml一个GitHub Actions工作流,会在每次Pull Request时对仓库运行
(Sloc, Cloc and Code)工具,并将结果——包括COCOMO模型估算的代码库构建成本/工作量——发布为单个固定评论,每次推送时会原地更新。可直接使用的工作流模板:
。
scctemplates/code-complexity.ymlWhat you get
你将获得的内容
scc--avg-wageIt reports the whole codebase at the PR's head, not the diff — it's a
"what's this project worth / how big it is" signal, not a per-PR delta.
scc--avg-wage它会报告PR头部对应的完整代码库数据,而非代码差异——这是一个「该项目价值多少/规模多大」的参考信号,而非单个PR的增量数据。
Install
安装步骤
Copy to
. It works as-is on ; the
only thing you'll likely change is the / workflow env (see Customise).
templates/code-complexity.yml.github/workflows/code-complexity.ymlubuntu-latestAVG_WAGEWAGE_LABEL将复制到
。在环境下可直接运行;你可能需要修改的唯一内容是工作流环境变量/(详见自定义配置部分)。
templates/code-complexity.yml.github/workflows/code-complexity.ymlubuntu-latestAVG_WAGEWAGE_LABELHow it works (the parts that matter)
核心工作原理
- Trigger: — runs on open and every push. Kept as its own workflow so it always runs even when other workflows honour a
pull_request: [opened, synchronize, reopened]-style marker; these stats are informational.[skip ci] - Permissions: a PR comment is posted via the Issues API, so
is what actually authorises the create/update;
pull-requests: writeis included belt-and-suspenders. (Both are in the template.)issues: write - Sticky comment: the body starts with a hidden marker
. The script lists existing comments, finds the one with that marker, and updates it (else creates one) — so a PR keeps exactly one stats comment that refreshes instead of stacking new ones each push.
<!-- code-complexity --> - Concurrency: keyed on the PR number (
cancel-in-progress: true) — a new push kills the in-flight run so you don't race two comment updates. Keyed on the number, notgithub.event.pull_request.number, so two forks sharing a branch name can't cancel each other.head_ref - COCOMO cost: drives the cost figure. The number is unitless to scc — it's read in your currency. The template defines
scc --avg-wage <annual>(AVG_WAGE, HKD 30,000/month) and360000once as workflowWAGE_LABEL, so the number scc uses and the label in the comment can't drift — change the salary in one place.env
- 触发条件: ——在PR打开和每次推送时运行。作为独立工作流存在,因此即使其他工作流遵循
pull_request: [opened, synchronize, reopened]类标记,该统计工作仍会执行;这些统计信息仅作参考用途。[skip ci] - 权限: PR评论通过Issues API发布,因此是实际授权创建/更新评论的权限;同时包含
pull-requests: write作为双重保障。(这两个权限已在模板中配置。)issues: write - 固定评论: 评论正文以隐藏标记开头。脚本会列出所有现有评论,找到带有该标记的评论并更新它(如果不存在则创建新评论)——因此每个PR始终只有一条统计评论,每次推送时会刷新内容而非新增评论。
<!-- code-complexity --> - 并发控制: ,以PR编号(
cancel-in-progress: true)作为标识——新推送会终止正在运行的任务,避免出现两条评论更新的竞争情况。使用PR编号而非github.event.pull_request.number作为标识,可防止两个共享分支名称的Fork仓库互相取消任务。head_ref - COCOMO成本计算: 参数驱动成本计算。该数值对scc来说是无单位的——它会使用你指定的货币单位。模板中通过工作流
scc --avg-wage <annual>定义了env(AVG_WAGE,即港币30,000/月)和360000,因此scc使用的数值和评论中的标签不会出现偏差——只需在一处修改薪资即可。WAGE_LABEL
Customise
自定义配置
| Want to… | Change |
|---|---|
| Use a different currency / salary | the |
| Exclude more build/generated dirs | |
| Pin / upgrade scc | |
| Run on ARM runners | swap the tarball to |
| Count only part of a monorepo | add a path arg to |
| 需求 | 修改内容 |
|---|---|
| 使用不同货币/薪资 | 工作流环境变量 |
| 排除更多构建/生成目录 | |
| 固定/升级scc版本 | 安装步骤中的 |
| 在ARM运行器上执行 | 将压缩包替换为 |
| 仅统计单体仓库的部分内容 | 为 |
Gotchas
注意事项
- Fork PRs can't post the comment. For PRs from forks, runs with a read-only token and no repo secrets, so the comment API call would 403. Declaring
pull_requestdoes not override this — GitHub enforces read-only on the token itself for fork-triggered runs. The template guards the whole job withpull-requests: write, so on fork PRs the job skips cleanly (green check) instead of failing red — and no compute is wasted running scc for a comment that can't post. Options: (a) accept that stats only post for same-repo branches (fine for solo/team repos — the common case; this is the template default); or (b) split into two workflows — compute onif: github.event.pull_request.head.repo.full_name == github.repository(no secrets, untrusted code), uploadpull_requestas an artifact, then comment from a separatescc-output.txtjob that has write access. Do not just switch this workflow toworkflow_run: that runs with a write token in the base repo context, and checking out + running fork code there is a token-exfiltration footgun.pull_request_target - Long output is truncated, not failed. GitHub caps a comment body at 65,536
characters. Default scc output (a per-language table) is tiny, but on a big repo could blow past it, which would 422 the step — so the template trims to ~64k with a "truncated" note and the comment still posts.
--by-file - Pin scc; don't track . A
latestdownload can change scc's output format and silently reshape every PR comment. The template pinslatestand verifies the tarball against a pinnedSCC_VERSION(SCC_SHA256) before running it, so a swapped/compromised release asset fails the run instead of executing in CI. When you bump the version — or switch to the arm64 asset — update the checksum from that release'ssha256sum -c.checksums.txt - Match the tarball to the runner arch. The release asset is arch-specific
(vs
scc_Linux_x86_64.tar.gz). The wrong one fails to run._arm64 - Paginate when finding the sticky comment. A busy PR can have more comments
than one API page; without pagination, the marker comment on a later page is
missed, and you get duplicates. The template uses and matches the marker with
github.paginate(...)(notstartsWith) so a human comment that merely quotes the marker isn't mistaken for the bot's and overwritten.includes - Token: . The template prefers a
GH_TOKEN || github.tokensecret (a PAT/bot you already use) and falls back toGH_TOKEN— the canonical reference to the built-ingithub.token. PreferGITHUB_TOKENovergithub.token; the built-in token is enough for same-repo comments given the permissions above.secrets.GITHUB_TOKEN - COCOMO is illustrative. It's the basic COCOMO model (COCOMO I, Organic mode) on LOC — a fun, relative signal of size/effort, not a real valuation. Don't quote it as the literal worth of the code.
- Fork PR无法发布评论。 对于来自Fork仓库的PR,触发的任务使用只读令牌,且无法访问仓库密钥,因此评论API调用会返回403错误。声明
pull_request权限无法覆盖此限制——GitHub会强制对Fork触发的任务使用只读令牌。模板通过pull-requests: write条件来跳过整个任务(显示绿色对勾),而非失败(显示红色叉号)——避免浪费计算资源去运行scc却无法发布评论。可选方案:(a) 接受仅在同仓库分支的PR上发布统计信息(适用于个人/团队仓库——这是常见场景,也是模板默认设置);或(b) 拆分为两个工作流——在if: github.event.pull_request.head.repo.full_name == github.repository中执行计算(无密钥,处理不受信任的代码),将pull_request作为产物上传,然后通过单独的scc-output.txt任务发布评论(该任务拥有写入权限)。请勿直接将工作流切换为workflow_run:这会在基础仓库环境中使用写入令牌,若在此环境下检出并运行Fork代码,会存在令牌泄露的风险。pull_request_target - 过长输出会被截断,而非失败。 GitHub限制评论正文最多65,536字符。默认的scc输出(按语言分类的表格)很小,但在大型仓库上使用参数可能会超出限制,导致步骤返回422错误——因此模板会将内容截断至约64k字符,并添加「已截断」提示,确保评论仍能发布。
--by-file - 固定scc版本;不要使用。 下载
latest版本可能会改变scc的输出格式,导致所有PR评论无声无息地发生变化。模板会固定latest并在运行前通过固定的SCC_VERSION验证压缩包(SCC_SHA256),因此若发布资产被替换/篡改,任务会失败而非在CI中执行。当你升级版本——或切换到arm64资产时——请从对应版本的sha256sum -c中更新校验和。checksums.txt - 压缩包需与运行器架构匹配。 发布资产是特定架构的(vs
scc_Linux_x86_64.tar.gz)。使用错误的压缩包会导致无法运行。_arm64 - 查找固定评论时需分页。 活跃的PR可能有超过一页的评论;若不分页,位于后续页面的标记评论会被遗漏,导致出现重复评论。模板使用并通过
github.paginate(...)匹配标记(而非startsWith),避免将仅引用该标记的人工评论误判为机器人评论并覆盖。includes - 令牌:。 模板优先使用
GH_TOKEN || github.token密钥(你已在使用的PAT/机器人令牌),若不存在则回退到**GH_TOKEN**——这是内置github.token的标准引用方式。在上述权限配置下,内置令牌已足够用于同仓库的评论发布,因此优先使用GITHUB_TOKEN而非github.token。secrets.GITHUB_TOKEN - COCOMO仅作参考。 它是基于LOC的基础COCOMO模型(COCOMO I,有机模式)——是一个有趣的、相对的规模/工作量信号,而非真实估值。请勿将其作为代码的实际价值引用。
Provenance
来源说明
Generalised from the working used in production repos
(a production app, a production monorepo): same scc + COCOMO + sticky-comment approach, hardened
here with version pinning + checksum verification, ,
comment pagination, a portable runner, and the fork-PR security
note.
code-complexity.ymlpersist-credentials: falseubuntu-latest本方案从生产仓库(一个生产应用、一个生产单体仓库)中正在使用的通用化而来:采用相同的scc + COCOMO + 固定评论方案,并在此基础上进行了强化,包括版本固定+校验和验证、、评论分页、可移植的运行器,以及Fork PR的安全提示。
code-complexity.ymlpersist-credentials: falseubuntu-latest