尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

【Bug已解决】Docs: add a first-contribution path for docs/examples-only contributors 解决方案

【Bug已解决】Docs: add a first-contribution path for docs/examples-only contributors 解决方案 【Bug已解决】Docs: add a first-contribution path for docs/examples-only contributors 解决方案一、现象长什么样许多想给langchain做首次贡献的人目标其实非常朴素只改文档或加一个示例比如修一个错别字、补一段 docstring、加一个 notebook 例子。但他们在 CONTRIBUTING 流程里会被劝退仓库的CONTRIBUTING.md一上来就要求配置完整的 monorepo 开发环境poetry install、pre-commit、make lint、make format、多个libs/*子包哪怕你只想改一个文档字符串文档站基于docusaurus 跨仓库引用本地构建极重新手为了改一句话要先下载几百 MB 依赖提 PR 时 CI 会跑全套单测、类型检查、lint纯文档 PR 也触发导致排队久、失败率高新手第一次贡献就卡在无关的检查上没有文档/示例专用的标签和模板维护者也不知道该快速放行还是按代码 PR 严格审结果大量潜在贡献者尤其是非英语母语、只想润色文档的人在第一步就放弃文档质量长期依赖少数核心成员。一句话贡献门槛与贡献类型不匹配——想改文档的人被当成了要改核心代码的人。二、背景langchain是一个典型的 Python monorepo用poetry管理 workspace拆成langchain-core、langchain-community、langchain-openai等多个子包文档站用 Docusaurus 构建示例大量以 Jupyter notebook.ipynb形式存在且通过nbfmt/codespell等工具校验。对代码贡献者这套流程合理改了langchain-core必须跑全量测试。但对只改docs/下一个 markdown、只给examples/加一个 notebook的人强制走同一套流程就是过度负担。开源项目的健康度高度依赖低门槛的首贡献而langchain当时缺的正是这条轻量路径。三、根因根因是贡献类型没有在流程层被分流CONTRIBUTING.md把开发环境搭建写成唯一路径没有区分docs-only与codeCI 的 workflow 没有按文件路径做条件触发所有 PR 跑同一套 job没有docs/documentationlabel也没有文档 PR 免跑核心单测的约定缺少好 first issue文档类的标注新手不知道从哪下手pre-commit 的codespell、notebook 格式化对纯文档改动也会触发制造噪音。# 问题所在所有 PR 都跑这套文档 PR 也被迫跑 jobs: unit-tests: runs-on: ubuntu-latest steps: - run: poetry install - run: make test四、最小可运行复现下面用一个最小例子模拟文档 PR 被无关 CI 拖垮。假设我们只改了一个 markdown# 只改了 docs/docs/how_to/chat.ipynb 的描述 git diff --stat # docs/docs/how_to/chat.ipynb | 2 -但 CI 仍然执行poetry install # 下载并安装全部依赖耗时 3 分钟 make test # 跑 langchain-core 全量单测耗时 10 分钟 make lint # 跑 ruff/mypy对文档无意义对只改一句话的贡献者这 13 分钟是纯浪费而且make test里任何别人的 flaky 测试都可能让你的 PR 红掉。用下面这段脚本可以判断一个 PR 是否仅涉及文档这正是分流的依据from pathlib import Path from typing import List def changed_paths(root: Path, base: str main) - List[Path]: # 示意用 git diff 拿到变更文件列表 import subprocess out subprocess.check_output( [git, diff, --name-only, forigin/{base}...HEAD], cwdroot, ) return [root / p for p in out.decode().splitlines() if p.strip()] def is_docs_only(root: Path, base: str main) - bool: paths changed_paths(root, base) if not paths: return False return all( any(part in (docs, examples, *.md, *.ipynb) for part in p.parts) or p.suffix in (.md, .ipynb) for p in paths ) if __name__ __main__: print(is_docs_only(Path(.)))五、解决方案第一层最小直接修复最小修复是在CONTRIBUTING.md顶部加一段我只想改文档/示例的精简路径让新手不必配全环境## 只想改文档或示例 如果你只改 docs/、examples/ 下的 .md / .ipynb可以跳过完整 poetry install 1. Fork 并 clone 仓库 2. 直接编辑对应文件markdown 用任意编辑器notebook 用 Jupyter Lab 3. 本地预览文档可选cd docs npm install npm run start 4. 提交 PR打上 docs 标签CI 会自动跳过核心单测。 你不需要运行 make test 或配置 Python 虚拟环境。同时给 PR 模板加上类型选择## 贡献类型 - [ ] 代码 - [ ] 文档/示例勾这个可跳过核心 CI六、解决方案第二层结构化改进把文档 PR 自动分流做成一个明确的策略对象并据此在 CI 里条件跳过重型 jobfrom dataclasses import dataclass from pathlib import Path from typing import List, Tuple dataclass(frozenTrue) class LangChainFirstContributionPolicy: 首贡献分流策略根据变更文件判定 PR 类型决定要走哪些 CI。 规则 - 仅涉及 docs/ examples/ 下 .md/.ipynb - docs_only跳过核心单测 - 其余 - full跑完整 lint/test/type-check repo_root: Path def classify(self, changed: List[Path]) - str: if not changed: return full docs_only all( any(seg in p.parts for seg in (docs, examples)) or p.suffix in (.md, .ipynb) for p in changed ) return docs_only if docs_only else full def ci_jobs(self, changed: List[Path]) - Tuple[bool, bool]: kind self.classify(changed) if kind docs_only: return (False, True) # (跑核心单测?, 跑文档校验?) return (True, True) def demo() - None: policy LangChainFirstContributionPolicy(repo_rootPath(.)) only_docs [Path(docs/docs/how_to/chat.md)] print(policy.ci_jobs(only_docs)) # (False, True) if __name__ __main__: demo()对应 CI 改造jobs: detect: outputs: docs_only: ${{ steps.classify.outputs.docs_only }} steps: - id: classify run: echo docs_only$(python ci/classify.py) $GITHUB_OUTPUT unit-tests: needs: detect if: needs.detect.outputs.docs_only ! true runs-on: ubuntu-latest steps: - run: poetry install make test docs-check: runs-on: ubuntu-latest steps: - run: npm ci npm run build # 仅文档站点校验七、解决方案第三层断言 / CI 守护把文档 PR 不应触发核心单测这条规则写进可验证的测试from pathlib import Path import pytest from your_ci import LangChainFirstContributionPolicy def test_docs_only_skips_core_tests(): policy LangChainFirstContributionPolicy(repo_rootPath(.)) changed [Path(docs/docs/get_started.ipynb)] run_core, run_docs policy.ci_jobs(changed) assert run_core is False assert run_docs is True def test_code_change_runs_full(): policy LangChainFirstContributionPolicy(repo_rootPath(.)) changed [Path(libs/core/langchain_core/runnables.py)] run_core, _ policy.ci_jobs(changed) assert run_core is True def test_mixed_change_runs_full(): policy LangChainFirstContributionPolicy(repo_rootPath(.)) changed [Path(docs/docs/x.md), Path(libs/core/x.py)] run_core, _ policy.ci_jobs(changed) assert run_core is True再配合 GitHub 的documentation/good first issue标签体系定期从文档区挑出易改项标注让首贡献者一眼找到入口。八、排查清单仓库是否有文档/示例专用贡献路径没有就补CONTRIBUTING.md段落。CI 是否按变更路径分流文档 PR 是否仍需跑核心单测PR 模板是否提供贡献类型勾选便于自动打标签文档站本地预览命令是否在文档里写明npm install npm start是否定期标注good first issuedocs吸引新手pre-commit 里codespell等是否对纯文档 PR 也制造噪音可酌情放宽九、小结这个问题的本质是贡献门槛与贡献类型错配想改文档的人被迫走核心代码贡献的完整流程导致首贡献流失。最小修复是补一段docs-only路径说明结构化做法是把变更文件分类成docs_only/full并据此在 CI 条件跳过核心单测最后用LangChainFirstContributionPolicy加测试守护确保文档 PR 永不被无关检查拖累。降低首贡献门槛是把社区规模做大的最低成本杠杆。
返回列表