搜索/维护一本所有代码示例都经过测试的文档书

维护一本所有代码示例都经过测试的文档书

在修改一本代码示例会被编译和测试的文档书时使用。说明构建和测试的命令、示例的两种存放方式、不升级共享库的版本而把示例移出去的方法,以及提交审查前的检查清单。

要使用这个AI规则
## 把书中的代码块当作要测试的代码,而不只是文字 这本书是一批实用示例的集合,写成带有内嵌代码块的 markdown 文件。一套文档测试框架会遍历源码树,抽取每一个代码块,编译它并运行它,因此一个坏掉的示例会像坏掉的应用代码一样让构建失败。 ### 这对每一次编辑意味着什么 无法编译的示例不算文档。散文部分可以自由改写措辞,但任何在代码块内部的改动都是对被测试源代码的改动,必须先用测试命令跑一遍,才能提出。 ### 让渲染出的书和测试面保持同步 同一份 markdown 既供给渲染出的书,也供给测试框架,因此格式上的选择带有语义。代码块上的注解决定框架如何处理它,而对读者隐藏的行仍然会被编译。绝不要仅仅为了让渲染出的页面看起来更整洁,就删掉某个注解或某行隐藏代码。 ## 用规定的命令构建、测试和本地预览这本书 每一项例行操作都要走已写入文档的命令,而不是临时自创调用方式,这样本地运行才能和持续集成保持一致。 ### 重要的命令 - 从 markdown 源文件构建这本书。 - 运行完整套件,也就是文档测试加上拼写检查这一轮。 - 当你只改了某个代码块、想要快速循环时,只运行文档测试这一目标。 - 在编辑散文时,以带实时重载的方式在本地预览这本书。 - 把构建与测试一起运行,作为送审前的默认动作。 - 运行链接检查器,它会依据一份签入仓库的配置文件校验内部链接和外部链接。 - 以交互方式运行拼写检查脚本,并把合理的新词加入仓库的词典文件,这样这次新增会随改动一起被评审。 ### 固定工具链版本 书籍生成器和链接检查器都通过同一条写入文档的安装命令,以精确固定的版本安装。不要为了绕过某个失败而在本地升级工具,因为版本漂移会把一个可复现的失败变成只有你才能看到的失败。 ## 了解示例的两种存放方式,不升级共享的依赖版本 示例会以两种方式之一被测试,而知道某个文件用的是哪种模式,就决定了它的代码和它的依赖应该放在哪里。 ### 模式一:就地测试的内联代码块 代码块直接写在源码树下的 markdown 里。一个构建脚本会遍历该树寻找 markdown 文件,并为每个代码块生成一个测试。这类示例所需要的每一项依赖,都必须已经存在于根清单文件中。代码块接受注解,用来指定语言版本,以及指定诸如仅编译、预期 panic、跳过之类的行为;读者不需要看到的样板代码写成以井号加空格为前缀的行,框架会编译它们,而渲染出的书会把它们隐藏。这是遗留模式,会保持可用,但不再扩展。 ### 模式二:被引入 markdown 的独立包 代码放在一个共享代码目录下属于自己的包里,带有独立的清单文件,而 markdown 通过一条 include 指令按相对路径指向源文件,把它拉进来。按行范围引入可以让页面只展示文件的一部分,测试脚手架正是这样被挡在渲染出的示例之外的。该路径会在构建脚本中被排除在文档测试框架之外,这样代码就不会被测试两次。对于新增示例和迁移后的示例,这是首选模式。 ### 依赖规则 不要修改根清单文件中的依赖版本。根清单文件被每一个内联示例共享,所以为了满足某一个页面而做的版本升级,可能会悄无声息地破坏其他几十个示例。当某个示例需要更新的依赖时,改为把该示例迁移成拥有自己固定版本的独立包。 ## 需要新版本库的示例,移到它自己的包里 当某个依赖版本必须变更时,把受影响的示例改造成独立包。按顺序执行以下步骤,因为每一步都会让仓库进入下一步所依赖的状态。 1. 在共享代码目录下创建这个包,放在先以其类别命名、再以示例命名的文件夹中,并带上自己的清单文件。尽可能从工作区继承共享依赖;如果这次的全部意义就在于分道扬镳,则独立固定版本。 2. 把代码从 markdown 代码块中移入包的源文件:每个可运行示例对应一个二进制目标,或者对库风格的示例使用一个库模块。 3. 在根清单文件的工作区成员列表中登记这个包。 4. 把 markdown 中的内联代码替换为一条 include 指令,其相对路径从该 markdown 文件自身所在位置指向包的源文件。 5. 在构建脚本中把已迁移的路径排除出文档测试框架。存在两份排除列表:一份接受目录前缀并移除其下的所有内容,另一份接受单个 markdown 文件。选用其中范围更窄且适用的那一份。 6. 两侧都要测试:运行这个新包自己的测试,并重新运行文档测试目标,以确认移除代码块没有破坏剩下的内联示例。 一次在第五步之前就停下的迁移,会让示例被编译两次;而一次在第六步之前就停下的迁移,可能会悄无声息地丢掉覆盖率。 ## 阅读决定构建和测试内容的那几个文件 少数几个文件决定了什么会被测试、什么会被渲染、以及存在哪些命令。在改变行为之前先读它们,并且要有意识地去改它们。 - 根清单文件保存着内联示例所使用的依赖,以及工作区成员列表。 - 构建脚本为文档测试框架发现 markdown 文件,并承载那两份排除列表,用来避免已迁移的示例被测试两次。 - 书籍配置文件控制 markdown 如何被渲染成书。 - 构建工具配置定义了那些写入文档的命令所依赖的任务运行器别名。 - 任务运行器包把构建、测试和链接检查实现为子命令,因此同一套逻辑既服务于贡献者,也服务于持续集成。 如果某个命令的行为与这里的描述不同,就把上述文件当作事实来源,并去修正描述,而不是绕开它。 ## 写出读者能直接复制运行的完整示例 评判一个示例的标准,是别人能不能把它复制进自己的项目并且跑得起来,而不是它在页面上看起来有多短。 ### 内容规则 - 示例要完整且可编译,而不是片段。 - 用该语言的错误传播运算符来向上传播错误,而不是在失败时 panic,并遵循项目中写入文档的错误处理模式。 - 避免通配符导入,这样读者能准确看出示例依赖了哪些 trait 和条目。 - 把需要外部服务或网络访问的示例标记为仅编译,这样整套测试在离线状态下仍然可以运行。 - 用隐藏行前缀来隐藏样板代码,而不是删掉它,这样示例仍然可以编译。 - 对于新示例,优先创建一个独立包,而不是往根清单文件里再加一项依赖。 ### 新增一个顶层章节 当你新增一个顶层章节页面时,也要在这本书的目录页里为它加上一条 include,并放在正确的字母顺序位置上。那个页面是读者的入口,一个没有被收录在那里的章节,即使能成功构建,实际上也是不可见的。 ## 请求审查前,跑完全部测试并过一遍检查清单 在提交或更新一项待评审的改动之前,以及在任何一次重写之后,都要核实以下全部事项。 - 完整测试套件在本地通过,使用的是那条写入文档的全量测试命令,而不是部分运行。 - 提交被压缩成一个,并已变基到最新的 main 分支之上。 - 描述中包含一条正确的关闭 issue 的声明;若不存在对应 issue,则把该声明整条删掉。写错 issue 编号比不写更糟。 - 不参与渲染的列表要保持排序:链接、引用、标识符和清单条目。保持排序才能让将来的差异保持很小。 - 文档中指向外部 API 参考页面的链接使用通配符版本段,而不是固定版本,这样链接不会在下一次发布时失效。 - 示例使用项目的标准错误处理方式,不走失败即 panic 的捷径。 - 描述中的代码标识符写成用反引号包裹的名称,并通过文件底部的链接定义超链接到其参考页面。 提交之后,要盯着持续集成的运行,并修复它报告的任何失败,而不是把一个红色的改动扔在那里让评审者去分诊。