首页
/ 解读 EbookFoundation/free-programming-books 贡献指南:书单数据格式规范、自动化校验与 RTL/LTR 排版修复

解读 EbookFoundation/free-programming-books 贡献指南:书单数据格式规范、自动化校验与 RTL/LTR 排版修复

2026-09-06 18:53:23作者:凤尚柏Louis

本篇技术指南以本项目官方贡献指南(即 docs/CONTRIBUTING-ta.md,内容与 docs/CONTRIBUTING.md 英文版一致)为主体,系统讲解 EbookFoundation/free-programming-books 这类「纯数据驱动的开源书单仓库」如何维护目录数据:从条目分类、链接选取原则、Markdown 排版规则,到 fpb-lint、awesome_bot、RTL/LTR linter 等自动化质量门的完整工作方式。读完你将能够:按规范新增/修改书单条目并一次性通过仓库的 CI 校验,理解仓库内各目录文件(books/courses/casts/more/)的组织逻辑,并能根据 linter 报错信息手工修复双向文本(BIDI)排版问题。

一、这个仓库的本质:一份需要被持续「编目」的数据集

free-programming-books 的核心产物并不是可运行的程序,而是分布在 bookscoursescastsmore 四个目录下、按语言分文件组织的 Markdown 清单——例如 free-programming-books-en.mdfree-programming-books-zh.mdfree-courses-en.md 等。正因如此,贡献指南(CONTRIBUTING)在本项目中不是「附赠文档」,而是决定数据能否入库的规格说明书:它定义了六类资源的收录口径、链接质量准则、精确到空行数的排版格式、元数据规范,以及三道自动化检查(格式 lint、URL 校验、RTL/LTR 排版 lint)。

整份指南的结构如下:

  1. 贡献者许可协议(CLA)与行为准则;
  2. 快速上手指南(In a nutshell);
  3. 链接与收录准则(Guidelines);
  4. Markdown 排版规范(Formatting)与元数据规则(Notes);
  5. 自动化与流水线(Automation);
  6. RTL/LTR linter 报错修复专题。

下文按此脉络逐一展开。

二、贡献前必读:许可协议、行为准则与总体流程

2.1 两份前置约定

  • 贡献者许可协议(CLA):向本仓库提交任何内容,即表示你同意仓库根目录 LICENSE 的授权条款。
  • 行为准则(Code of Conduct):参与贡献即表示你同意遵守 CODE_OF_CONDUCT.md(及其在 docs 目录下的各语言翻译版,如 CODE_OF_CONDUCT-zh.md)。

这两份文件对所有语言版本的贡献者一视同仁,是提交 PR 的先决条件。

2.2 快速上手的五个要点

指南用五句话概括了新人最需要知道的规则:

  1. 只收录真正免费的内容。请注意:「一个可以轻易下载书的链接」未必是「一本免费书的链接」。必须确认资源本身免费;凡要求必须填写可用邮箱才能获取书籍的页面一律不接受(但「建议提供但不强制」的页面可以收录)。
  2. 不会 Git 也能贡献。发现仓库中尚不存在且感兴趣的资源时,直接开一个 Issue 附上链接建议即可;熟悉 Git 的贡献者则 Fork 仓库并提交 Pull Request。
  3. 选对六类清单中的一类(详见第三章)。
  4. 遵守 GuidelinesFormatting 两套规则
  5. GitHub Actions 会自动执行检查:验证清单是否按字母排序、排版规则是否被遵守。提交前务必确保自己的改动能通过全部测试。

三、六类资源清单与收录口径

仓库并非只有一个「书目」文件,而是按资源形态拆分成六类清单,贡献时首先要判断新资源属于哪一类:

类别 对应仓库目录/文件 定义与判断要点
Books(书籍) books 下的 free-programming-books-*.md PDF、HTML、ePub、基于 gitbook.io 的站点、Git 仓库等
Courses(课程) courses 下的 free-courses-*.md 非书籍形态的学习材料,如 MIT OCW 的算法公开课
Interactive Tutorials(交互式教程) more/free-programming-interactive-tutorials-en.md 允许用户输入代码/命令并即时评估结果的网站(此处的 "evaluate" 不是「打分」)
Playgrounds(编程游乐场) more/free-programming-playgrounds.md 在线/交互式网站、游戏或桌面软件,可编写、编译(运行)并分享代码片段,通常支持 fork 后上手实操
Podcasts and Screencasts(播客与录屏) casts 下的 free-podcasts-screencasts-*.md 播客与录屏资源
Problem Sets & Competitive Programming(题库与竞赛) more/problem-sets-competitive-programming.md 通过解决简单或复杂问题来评估编程技能的网站或软件(可含/不含代码审查、可含/不含与他人结果对比)

仓库 README.md 与各清单文件开头的「目录(Index)」相互印证了这套分类:每个 .md 文件都以目录开头,按字母顺序列出全部章节与子章节。

四、链接与收录准则(Guidelines)

贡献者需要逐条遵守以下链接质量规则,这些规则决定了清单的长期可用性:

  • 免费性核查:确认书籍免费,必要时二次核验;在 PR 中说明「为何认为该书免费」会显著帮助管理员审核。
  • 禁用文件托管平台:不接受托管在 Google Drive、Dropbox、Mega、Scribd、Issuu 等类似文件上传平台的条目。
  • 按字母顺序插入:新增链接必须插入到正确位置(规则详见「字母排序」小节)。
  • 优先权威来源:链接应指向最权威的来源——作者官网优于出版社官网,出版社官网优于第三方网站;禁止指向文件托管服务。
  • 协议偏好:同一域名、内容一致时,https 永远优于 http;根域名去掉尾斜杠(http://example.com 而非 http://example.com/)。
  • 链接最短化http://example.com/dir/ 优于 http://example.com/dir/index.html禁止使用 URL 缩短器
  • “当前版”优于“版本号”http://example.com/dir/book/current/ 优于 http://example.com/dir/book/v1.0.0/index.html
  • SSL 问题处理三步走:链接若存在过期/自签名证书等 SSL 问题——① 可行时替换为 http 版本(移动设备上接受证书例外很麻烦);② 若无 http 版本、但浏览器添加例外后仍可通过 https 访问,则保留;③ 否则删除
  • 多格式多链接:同一资源存在多种格式时,为每种格式单独添加一条链接并注明格式。
  • 多版本并存:资源在互联网多处存在时,选权威来源;若指向不同版本且差异足够大、值得保留,则分别加链接并注明版本(参见 Issue #2353 的格式讨论)。
  • 提交粒度:倾向「原子提交」(一次增/删/改对应一个 commit),但不强制在提交 PR 前 squash。
  • 旧书标注年份:书籍年代较早时,在标题中附加出版年份。
  • 作者署名:适当位置补充作者姓名,可用 "et al." 缩写超长作者列表。
  • 未完成书籍:标记 "in process" 符号(格式见后)。
  • 归档资源:凡经 Wayback Machine 等恢复的链接,标记 "archived" 符号,优先选用最新且完整的存档版本。
  • 需要邮箱/账号才能下载:在括号中追加语言匹配的说明,例如 (email address *requested*, not required)(泰米尔语文档中写作 (மின்னஞ்சல் முகவரி *கோரப்பட்டது*, தேவையில்லை))。

五、Markdown 排版规范(Formatting)

5.1 结构性规则

  • 所有清单均为 .md 文件,需遵循标准 Markdown 语法。
  • 每个清单文件以目录(Index)开头,列出并链接所有章节与子章节,且保持字母顺序。
  • 章节用三级标题 ###,子章节用四级标题 ####——这一点可在各清单文件中直接观察到,例如 books/free-programming-books-en.md 内的 ### Index 与各 ###/#### 标题。
  • 空行数量有硬性规定:
    • 最后一条链接与下一章节标题之间:2 个空行
    • 章节标题与本章节第一条链接之间:1 个空行
    • 两条相邻链接之间:0 个空行
    • 每个 .md 文件末尾:1 个空行

以指南中的示例来说明这个「呼吸节奏」:

[...]
* [அற்புதமான புத்தகம்](http://example.com/example.html)


### உதாரணம்

* [மற்றொரு அற்புதமான புத்தகம்](http://example.com/book.html)
* [வேறு ஒரு புத்தகம்](http://example.com/other.html)

(中文语义为:示例书条目之后空两行 → ### 示例 → 空一行 → 连续无空行地罗列两个条目。)

5.2 条目格式的正反例

指南给出了一组「错误 vs 正确」的对照,每条都是仓库维护者真实踩过的坑:

  • 链接语法不要留空格]( 之间不能有空格。
    错误:* [மற்றொரு அற்புதமான புத்தகம்] (http://example.com/book.html)
    正确:* [மற்றொரு அற்புதமான புத்தகம்](http://example.com/book.html)
    
  • 作者用短横线分隔:作者名前使用两侧各空一格的 -
    错误:* [மற்றொரு அற்புதமான புத்தகம்](http://example.com/book.html)- ஜான் டோ
    正确:* [மற்றொரு அற்புதமான புத்தகம்](http://example.com/book.html) - ஜான் டோ
    
  • 格式标注前留一个空格
    错误:* [மிக அற்புதமான புத்தகம்](https://example.org/book.pdf)(PDF)
    正确:* [மிக அற்புதமான புத்தகம்](https://example.org/book.pdf) (PDF)
    
  • 作者在格式之前
    错误:* [மிக அற்புதமான புத்தகம்](https://example.org/book.pdf)- (PDF) ஜேன் ரோ
    正确:* [மிக அற்புதமான புத்தகம்](https://example.org/book.pdf) - ஜேன் ரோ (PDF)
    
  • 多格式优先单链接:每个来源尽量只留一条链接;只有当确实不存在能同时覆盖多格式的便捷入口时,才追加格式链接。
    错误:* [மற்றொரு அற்புதமான புத்தகம்](http://example.com/) - ஜான் டோ (HTML)
    错误:* [மற்றொரு அற்புதமான புத்தகம்](https://downloads.example.org/book.html) - ஜான் டோ (பதிவிறக்க தளம்)
    正确:* [மற்றொரு அற்புதமான புத்தகம்](http://example.com/) - ஜான் டோ (HTML) [(PDF, EPUB)](https://downloads.example.org/book.html)
    
  • 旧书把年份放进标题(而非放在作者之后):
    错误:* [மிக அற்புதமான புத்தகம்](https://example.org/book.html) - ஜேன் ரோ - 1970
    正确:* [மிக அற்புதமான புத்தகம் (1970)](https://example.org/book.html) - ஜேன் ரோ
    

5.3 特殊标记语法

  • 进行中的书籍(in process)
    * [விரைவில் ஒரு அற்புதமான புத்தகமாக இருக்கும்](http://example.com/book2.html) - ஜான் டோ (HTML) *(:construction: செயலில் உள்ளது)*
    
  • 归档链接(archived)
    * [பழைய சுவாரஸ்யமான புத்தகம்](https://web.archive.org/web/20211016123456/http://example.com/) - ஜான் டோ (HTML) *(:card_file_box: காப்பகப்படுத்தப்பட்டது)*
    
  • 自由许可证标注(license):在鼓励 CC 等自由许可证的同时,也接受「保留所有权利但可免费阅读」的资源。标注格式为格式说明后追加括号简写,例如 (PDF) (CC BY-SA)

5.4 支持的许可证缩写清单

许可证标注不带版本号,只允许以下受支持缩写之一:

缩写 全称
CC BY Creative Commons attribution
CC BY-NC Creative Commons non-commercial
CC BY-SA Creative Commons share-alike
CC BY-NC-SA Creative Commons non-commercial, share-alike
CC BY-ND Creative Commons no-derivatives
CC BY-NC-ND Creative Commons non-commercial, no-derivatives
GFDL GNU Free Documentation License

添加许可证标注的分步指南

  1. 到资源页面确认许可证——查看站点页脚、「关于」页或许可证/法律区块;为自由/开放内容许可证添加标注,不要添加「保留所有权利」之类的说明。
  2. 将许可证字符串标准化为上述无版本号的缩写。例如 "Creative Commons Attribution 4.0" → CC BY;"CC BY-SA 3.0" → CC BY-SA;"GNU Free Documentation License" → GFDL
  3. 把许可证放在格式标注与其他注释之间。单格式写作 * [மிக அற்புதமான புத்தகம்](https://example.org/book.pdf) - ஜேன் ரோ (PDF) (CC BY-SA);多格式写作 * [அருமையான வழிகாட்டி](https://example.org/) - ஜேன் ரோ (HTML, PDF) (CC BY);附带 archived/in process 时放在最后,如 * [...] - ஜான் டோ (HTML) (CC BY) *(:card_file_box: காப்பகப்படுத்தப்பட்டது)*
  4. 若不同版本/格式的许可证不同,就拆成独立条目并在各自条目中标注正确许可证。
  5. 不确定时,在 PR 中留言说明你认为该资源处于自由许可证下的理由及信息来源。

六、字母排序规则

  • 多条标题首字母相同时,依次比较第二个、第三个……字母;例如 aa 排在 ab 之前。
  • 含空格的标题按直观规则比较:one two 排在 onetwo 之前。
  • 若怀疑自己把链接插错位置,可先运行 linter,依据报错信息判断应交换哪些行(仓库内 bookscoursescasts 的实际文件即为最直观的范例)。

七、元数据与分类细则(Notes)

7.1 元数据

清单只承载最小元数据集:标题、URL、创作者、平台(site)与访问注释。

标题(Titles)

  • 不要自拟标题:尽量沿用资源自身标题;贡献者不应自行发明标题或充当「作者」。
  • 例外是年代久远、主要以历史价值存在的作品,可把年份以括号形式缀在标题后帮助读者判断。
  • 禁止全大写(ALLCAPS)标题;通常沿用资源原样大小写,不确定时遵从源。
  • 标题中不出现 emoji

URL

  • 禁止缩短 URL;应从 URL 中剔除跟踪参数。
  • 国际化 URL 应做百分号编码(浏览器地址栏通常显示为 Unicode,但复制粘贴时请使用编码形态)。
  • 已启用 HTTPS 的站点上,安全(https)URL 永远优于不安全(http)URL。
  • 不收录那种只是「指路」到别处、自身并不承载所列资源的页面。

创作者(Creators)

  • 乐于在合适位置为自由资源的创作者(含译者)署名。
  • 对翻译作品,原作者必须署名;建议用 MARC relators 为作者以外的贡献者署名,格式如 * [A Translated Book](http://example.com/book.html) - John Doe, trl.: Mike The Translator,其中 trl.: 是「translator」的 MARC 代码。
  • 作者列表用逗号 , 分隔各项;可用 "et al." 缩写。
  • 不允许给创作者加超链接;不收录「Prof.」「Dr.」等头衔。
  • 对汇编/混编类作品应注明性质,例如 GoalKicker、RIP Tutorial 的书需标注「由 StackOverflow documentation 汇编而成」。

7.2 时限性课程与测验

  • 不收录六个月内会被要求移除的内容。
  • 有固定报名期或期限的课程不收录;仅在限定期限内免费的资源一律不收录——因为这份清单的目标是长期稳定可用。

7.3 平台与访问注释

  • 课程平台:对课程类清单而言,「平台」是资源描述的关键部分,因为不同平台有不同的 affordance 与访问模式。虽然通常不收录需要注册才能阅读的书,但许多课程平台(如 Coursera、EdX、Udacity、Udemy)的某些功能离开账号就无法使用——当课程依赖某平台时,须把平台名放进括号列出。
  • YouTube:不把 YouTube 本身当作平台列出来,而是尽量列出承载课程的 YouTube 创作者(其作为子平台)。
  • 单个 YouTube 视频:一般不给单个视频加链接,除非时长超过一小时且编排得像课程或教程——若是这种情况,务必在 PR 描述中注明。
  • 禁用缩短链接(如 youtu.be/xxxx)。
  • Leanpub:其书籍访问模式多样(有的无需注册可读、有的免费访问需要 Leanpub 账号)。鉴于质量与访问模式混杂且易变,允许用 *(Leanpub கணக்கு அல்லது செல்லுபடியாகும் மின்னஞ்சல் கோரப்பட்டது)* 这种访问注释收录后者。

7.4 分类边界:什么不该列、什么算什么

不收录的类别:博客、博客文章、文章、网站(承载我们所列资源的宿主站点除外)、非课程/录屏的视频、书籍章节、书籍节选样本、IRC 或 Telegram 频道、Slack 或邮件列表。其中「竞赛编程清单」对这些豁免不那么严格——仓库范围由社区决定,想扩范围就去开 Issue。

Books vs 其他:判断「书性」时视角并不狭窄,下列特征有助于判断:拥有 ISBN;拥有目录(ToC);提供可下载版本(尤其 ePub);有版本号;不依赖交互内容或视频;试图深入覆盖某一主题;自包含。不过也收录很多不具备上述全部特征的书——是否收录取决于上下文。

Books vs Courses:两者有时难以区分。课程通常配有被收入书籍清单的配套教材;课程包含讲座、练习、测验、讲义或其他教学辅助。只有讲座或视频不成其为课程;一份 PowerPoint 也不是课程。

Interactive Tutorials vs 其他:很直白的判据——如果你能把页面打印下来且内容精华不丢失,它就不是交互式教程

八、自动化与质量流水线(Automation)

8.1 三道检查的职责划分

贡献指南明确指出两件事由自动化完成:

  1. 格式规则强制:通过 fpb-lint 在 GitHub Actions 中执行,对应工作流文件为 .github/workflows/fpb-lint.yml。该工作流在 pull_request 触发后安装 free-programming-books-lint 并运行 fpb-lint books casts courses more,对全部清单做字母排序与格式校验,随后把清洗后的错误日志作为 artifact 上传——这正是指南中「GitHub Actions 会检查列表是否按字母排序、格式是否合规」的落地实现。
  2. URL 校验:使用 awesome_bot 完成,对应 .github/workflows/check-urls.yml。它对本次 PR/推送改动过的每个 .md/.yml 文件运行 awesome_bot "${{ matrix.file }}" --allow-redirect --allow-dupe --allow-ssl,再把 JSON 结果交由仓库自带的 awesomebot-gh-summary-action 汇总成 GitHub 报告。

此外,仓库还单独维护了一个针对阿拉伯语、希伯来语、波斯语等 RTL(从右到左)书写系统清单的排版检查器,对应工作流 .github/workflows/rtl-ltr-linter.yml(详见第九章)。

8.2 用 commit message 触发 URL 校验

URL 校验默认只针对改动文件执行。若要主动触发对指定文件的完整校验,提交一条 commit message 为 check_urls=file_to_check 的提交即可:

check_urls=free-programming-books.md free-programming-books-en.md
  • 多个待检查文件用单个空格分隔。
  • 注意陷阱:指定多个文件时,构建结果以最后一个被检查文件的结果为准——因此即使某个文件挂了,你也可能看到绿色构建。务必点击 PR 末尾构建日志中的 "Show all checks" → "Details" 仔细确认每个文件的真实结果。

九、专题:修复 RTL/LTR linter 报错

这是本仓库贡献流程中最「工程化」也最容易困惑的一环,指南用了整节讲解。先交代背景:当 Markdown 书写方向为 RTL 的语言(清单文件名如 *-ar.md*-he.md*-fa_IR.md 等,即阿拉伯语、希伯来语、波斯语清单)内部混入 HTML、JavaScript 这类 LTR 词汇或 C#、C++ 这类 LTR 符号时,Unicode 双向算法(BIDI)可能把字符渲染成与逻辑顺序不符的视觉顺序,导致读者看到乱序文字。

9.1 触发条件与修复口诀

  • 运行 *-ar.md*-he.md*-fa_IR.md*-ur.md 等文件的 RTL/LTR 检查并发现错误/警告时:
    • LTR 词汇(如 "HTML"、"JavaScript" 出现在 RTL 文本中):在该 LTR 片段之后紧跟追加 ‏
    • LTR 符号(如 "C#"、"C++"):在该符号之后紧跟追加 ‎

‏(Right-to-Left Mark)与 ‎(Left-to-Right Mark)是不可见的 Unicode 方向控制字符,作用是向 BIDI 算法「声明」其前方内容的正确方向,避免发生重排错乱。

9.2 仓库源码层的判定逻辑

scripts/rtl_ltr_linter.py 完整实现了这套检查,可作为理解报错的权威依据:

  • 文件名判定方向语境:is_rtl_filename() 依据文件名是否以 -ar.md/_ar.md-he.md/_he.md-fa.md/_fa.md-ur.md/_ur.md 结尾来决定该文件的基准方向是 rtl 还是 ltr
  • 配置驱动规则:词表与严重级别全部来自 scripts/rtl_ltr_linter_config.yml。其中 ltr_keywords 收录了 100+ 个常见 LTR 关键词(HTML、JavaScript、Python、Docker、Kubernetes、Git……),ltr_symbols 收录了 C#、C++、.NET、Node.js、CI/CD 等符号类条目;severity 定义了四档问题的级别——bidi_mismatch 为 error、keyword/symbol 为 warning、pure_ltrauthor_meta 为 notice。
  • 逐行解析:对 Markdown 列表项用 BOOK_ITEM_RE 拆出「标题—作者—元数据」三段,再分别检查是否缺 &rlm;/&lrm;;同时用正则跟踪 HTML dir 属性与嵌套 <span> 标签建立的方向上下文栈,还专门检测「RTL 作者后紧跟纯 LTR 元数据」(如阿拉伯语作者名后接 (PDF))这类需要补 &rlm; 的场景。
  • 增量报错:get_changed_lines_for_file() 借助 git diff 只把本次 PR 改动行上的问题以 GitHub Actions annotation 形式打印出来,未改动行的历史问题只写入 rtl-linter-output.log artifact;退出码仅取决于改动行上是否存在 error/warning。这解释了为何主流程中该步骤配合 continue-on-error: true 并同时产出日志 artifact。

9.3 正误对照示例

指南原文以阿拉伯语清单条目演示(泰米尔语版本原样保留这些示例),下面逐例说明。

例一:书名中的 LTR 词汇 "R" 需要 &rlm;

错误:
<div dir="rtl" markdown="1">
* كتاب الأمثلة في R - John Doe (PDF)
</div>

正确:
<div dir="rtl" markdown="1">
* كتاب الأمثلة في R&rlm; - John Doe&rlm; (PDF)
</div>

例二:作者列表里两个 RTL 人名夹着 LTR 站名/标题,需要在 LTR 片段后补 &rlm;

错误:
<div dir="rtl" markdown="1">
* Tech Podcast - بودكاست المثال – Ahmad Hasan, محمد علي
</div>

正确:
<div dir="rtl" markdown="1">
* Tech Podcast - بودكاست المثال – Ahmad Hasan,&rlm; محمد علي
</div>

例三:LTR 符号 "C#" 需要 &lrm;

错误:
<div dir="rtl" markdown="1">
* أساسيات C#
</div>

正确:
<div dir="rtl" markdown="1">
* أساسيات C#&lrm;
</div>

结合 free-programming-books-ar.md 这类真实文件可见,该约定已在存量数据中得到执行——例如 * تعلم JavaScript&rlm; - Cody Lindley,&rlm; ...* أساسيات C# 式的条目都在 LTR 词/符号后正确携带了方向标记,其中括号内的纯 LTR 元数据(如 (PDF))由于括号隔离了 BIDI 影响通常无需标记,这与 rtl_ltr_linter.py 中「完全被括号包裹且内部纯 LTR/纯 RTL 的片段可跳过检查」的逻辑完全一致。

十、一次标准贡献的完整落地路径

将上述全部规则串起来,一次符合规范的贡献流程是:

  1. 阅读根 README.md 了解仓库全貌,选对清单语言文件与资源类别(六类之一);
  2. 按第三章规则判断资源确属免费、合法且值得收录,规避文件托管平台与缩短链接;
  3. 用第四、五、六章的口径确定链接、作者、格式、许可证、年份与字母序位置,保持空行数与 Markdown 语法精确无误;
  4. 对 RTL 语言文件,对照第九章修复 BIDI 方向标记并留意括号/行内代码的豁免场景;
  5. 提交 PR;若只想对特定文件全量验链接,可用 check_urls=xxx.md 的 commit message 触发 .github/workflows/check-urls.yml 中的 awesome_bot 校验,并在多文件场景下逐条查看 build 详情;
  6. 观察三道流水线(fpb-lint.yml 的格式/排序检查、check-urls.yml 的 URL 检查、rtl-ltr-linter.yml 的方向排版检查)的结论,有报错则依据 linter 输出定位到具体文件与行号并修正,直到改动行上的 error/warning 清零。

十一、结语

free-programming-books 之所以能在几十年语言与主题跨度上保持高质量,靠的不是事后的人工校对,而是贡献指南把「收录标准—排版规格—元数据口径—自动化校验」拧成了一整套可执行、可复现、可被 CI 强制执行的规范。对于任何希望维护大规模众包知识清单的开发者而言,docs/CONTRIBUTING-ta.md(及英文母版 docs/CONTRIBUTING.md)连同 scripts/rtl_ltr_linter.py 等配套脚本,本身就是一份关于「如何为纯数据仓库建立工程化质量控制」的高质量参考实现。

登录后查看全文
热门项目推荐
相关项目推荐