ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Gotenberg 贡献指南:模块架构、代码规范与集成测试实战

Gotenberg 贡献指南:模块架构、代码规范与集成测试实战 后端开发工具【免费下载链接】gotenbergA developer-friendly API for converting many document formats into PDF files, and more!项目地址https://gitcode.com/gh_mirrors/go/gotenberg点击查看免费下载Gotenberg 是一个基于 Docker 的文档转 PDF API 服务本指南以其仓库内的 CONTRIBUTING.md 为骨架结合源码与测试基础设施完整讲解贡献者需要掌握的两条铁律、模块系统架构、Makefile 工作流、编码与文档规范以及 Gherkin 驱动的集成测试实战。读完本文你将具备向 Gotenberg 提交高质量 Pull Request 的完整方法论从提出 issue、编写 feature 文件、实现模块到通过make lint与make test-integration TAGS...的完整闭环。两条覆盖一切的最高原则无论改动多小以下两条规则凌驾于其他所有约定之上向后兼容Backward compatibility未经讨论绝不重命名或删除 CLI 标志、环境变量、API 表单字段或 HTTP 端点。Gotenberg 是面向开发者的 API 服务任何破坏现有调用方式的改动都会波及所有下游用户。防御性编程Defensive programming假设输入永远是畸形的显式处理每个错误生产代码路径中绝不 panic。这两条原则在仓库中贯穿始终错误处理、日志、遥测与文档规范都围绕它们展开。工具链要求参与开发前请确认环境满足以下要求工具要求Go 模块github.com/gotenberg/gotenberg/v8Go 版本以 go.mod 为准当前仓库为go 1.27.1Docker构建镜像与运行集成测试必需Node.js版本见.node-version用于 Prettier 非 Go 代码格式化golangci-lintv2 及以上go.mod中还值得注意Chromium 依赖chromedp被显式固定在 v0.14.2并附注释说明 v0.15.x 会破坏 headless 打印模式的绘制管线rAF / ResizeObserver / IntersectionObserver 停止触发导致图表空白这是向后兼容原则在依赖层面的直接体现。动手之前先讨论再编码对于非平凡的改动Gotenberg 要求先打开一个 issue 或草稿 PRdraft PR在其中说明需要改变什么提议的解决方案涉及哪些文件、哪些接口变更、哪些表单字段会受影响的集成测试标签integration test tags。同时遵循两条协作纪律一个 PR 只做一件事。特性、缺陷修复、重构必须拆分为独立的 PR便于审查与回滚。先写场景后写代码。新增功能或路由时先编写 Gherkin 场景.feature文件再写 Go 实现如果路由有变化还要同步更新 Bruno API 集合.bruno/。这种测试先行的节奏保证了每个端点都有可验证的行为定义。项目布局五层结构一目了然cmd/gotenberg/ - 入口点装配/启动。不含业务逻辑。 pkg/gotenberg/ - 核心模块系统、接口、工具、mocks。 pkg/modules/ - 功能模块api、chromium、libreoffice、pdfengines 等。 pkg/standard/ - 通过 import 装配所有标准模块。 test/integration/ - Gherkin feature 文件 Go 测试基础设施。 build/ - Dockerfile、字体、Chromium 配置。 .bruno/ - Bruno API 集合镜像每一个路由。关键接口都位于pkg/gotenberg/Module、Provisioner、Validator、Debuggable。每个模块实现Descriptor()并通过init()自注册。模块系统Caddy 风格的自注册架构Gotenberg 的模块架构借鉴了 CaddyServer 的自注册模式这是理解整个代码库的钥匙。Module 接口与 Descriptor每个模块最少实现gotenberg.Module接口即一个Descriptor()方法。Descriptor()返回ModuleDescriptor包含三个字段见 pkg/gotenberg/modules.goID模块唯一标识snake_case必填FlagSet模块的 pflag 定义可选New返回模块新实例的构造函数必填。典型的模块声明方式如下摘自Module接口的文档注释type YourModule struct { property string } func (YourModule) Descriptor() gotenberg.ModuleDescriptor { return gotenberg.ModuleDescriptor{ ID: your_module, FlagSet: func() *flag.FlagSet { fs : flag.NewFlagSet(your_module, flag.ExitOnError) fs.String(your_module-property, default value, flag description) return fs }(), New: func() gotenberg.Module { return new(YourModule) }, } }通过 init() 自注册模块在其主 Go 文件中通过init()调用gotenberg.MustRegisterModule(...)完成注册。注册时会做三项校验ID非空、New非 nil、New()返回非 nil 实例重复 ID 会直接 panic见 pkg/gotenberg/modules.go。所有已注册模块的描述符存放在包级 map 中通过GetModuleDescriptors()按 ID 排序返回。生命周期Provision 与 Validate注册之外模块可选择性实现两个生命周期接口ProvisionerProvision(*Context) error根据标志、环境变量、上下文初始化模块ValidatorValidate() error在 Provision 之后校验配置合法性。Context见 pkg/gotenberg/context.go提供了ParsedFlags()获取解析后的标志以及Module(kind any)/Modules(kind any)按接口类型获取依赖的其他模块实例。当通过Context.Modules()请求某个接口时尚未初始化的模块会被惰性加载先调用其Provision再调用Validate最后缓存实例见loadModulepkg/gotenberg/context.go。装配入口pkg/standard业务模块本身不直接依赖彼此装配发生在 pkg/standard/imports.go 中通过空导入_ github.com/gotenberg/gotenberg/v8/pkg/modules/...触发各模块的init()完成注册覆盖 api、chromium、exiftool、libreoffice含 api 与 pdfengine 子模块、pdfcpu、pdfengines、pdftk、prometheus、qpdf、webhook 等标准模块。最终入口是 cmd/gotenberg/main.go它只做两件事导入pkg/standard触发模块注册然后调用gotenbergcmd.Run()。这就是入口点不含业务逻辑原则的落地。何时新建模块先判断功能是否属于既有模块只有在确实是独立关注点时genuinely separate concern才创建新模块。cmd/gotenberg/严格用于装配与启动。Setup 与 Makefile所有构建验证任务的总入口Gotenberg 规定所有构建和验证任务都通过 Makefile 完成除非是调试特定包否则不要直接运行go命令。常用命令速查表命令用途使用时机make build构建 Gotenberg Docker 镜像集成测试前或手动测试前make run通过docker compose启动 Gotenberg 容器手动测试。标志通过 Makefile 变量与 compose.yaml 配置make telemetry启动 OpenTelemetry collector 与 OpenObserve本地测试遥测时make down停止所有 compose 容器手动测试之后make godoc在localhost:6060提供 GoDoc验证文档make fmt格式化 Go 代码提交前make lint检查 Go 代码零错误容忍提交前make prettify格式化非 Go 文件Markdown、YAML、JSON提交前make lint-prettier检查非 Go 文件提交前make test-unit运行单元测试提交前make test-integration运行全部集成测试40 分钟超时提交前在 Makefile 中可以看到实现细节make build支持TARGETgotenberg-chromium或TARGETgotenberg-libreoffice变体make test-unit实际执行go test -race ./...make lint调用golangci-lint runmake prettify执行npx prettier --write .make fmt组合了go fix、golangci-lint fmt与go mod tidy。此外 Makefile 顶部还维护着全套环境变量默认值如API_PORT3000、CHROMIUM_MAX_CONCURRENCY6、LIBREOFFICE_RESTART_AFTER10等它们通过export导出给 Compose 使用。只跑与改动相关的集成测试标签完整集成测试套件有 40 分钟超时因此应只运行与本次改动相关的标签make test-integration TAGShealth make test-integration TAGSchromium-convert-html make test-integration TAGSmerge,split集成测试命令本身会自动重试失败的场景最多 3 次。可用标签的完整清单维护在 Makefile 的TAGS变量注释块中并按 Chromium、LibreOffice、PDF Engines、Infra 等分组详见下文测试章节。代码规范Code conventions向后兼容的处理方式CLI 标志、环境变量、API 表单字段、HTTP 端点以及任何会改变既有行为的默认值未经讨论不得更改。需要废弃旧名称时用fs.MarkDeprecated()标记并让新旧两个名称并排注册。如果改动确实违反向后兼容必须在 PR 描述中明确标注为破坏性变更breaking change。错误处理每个错误都用上下文包装fmt.Errorf(description: %w, err)绝不静默吞掉错误用errors.Is匹配错误绝不用strings.Contains生产代码路径禁止 panic防御性地校验输入。从源码看这套约定在 pkg/gotenberg/cmd.go 中体现得淋漓尽致Start、Wait、Exec、Kill每个方法都返回带%w包装的错误如start unix process: %w、context done: %w子进程通过SetpgidSIGKILL整组杀死以避免孤儿进程且执行外部二进制soffice、pdftk、qpdf、exiftool、pdfcpu失败时会映射为有限的 semconverror.type值context_deadline_exceeded、context_canceled、process_error。错误消息规范面向客户端和运维人员的错误消息要说明什么失败了、何时不明显时说明原因、存在修复方案时说明如何修复而只出现在日志中的内部包装错误链不受此限保持精准和技术化即可。具体分三类客户端HTTP 响应体点名出错的表单字段及其合法取值。绝不返回裸的http.StatusText()运维人员启动、Provision、Validate点名需要设置的环境变量或标志以及被检查的路径或值安全与过滤类错误对客户端保持通用措辞不泄露 allow/deny 列表或私有 IP 策略具体原因记入运维日志。禁止使用推诿性措辞while others may have failed也不要在面向人的修复建议中塞入原始os.Stat或 exec 输出。日志规范在Provision()阶段使用gotenberg.Logger(mod)获取模块的 slog logger。所有日志调用必须上下文感知使用*Context变体logger.DebugContext(ctx, msg) logger.InfoContext(ctx, msg) logger.ErrorContext(ctx, msg)这样在 OpenTelemetry 生效时trace/span ID 才能传播进结构化日志。事实上Cmd的子进程输出管道pipeOutput只有在 debug 级别才启用且统一走DebugContext见 pkg/gotenberg/cmd.go。遥测规范所有外部工具调用Chromium、LibreOffice、PDF 引擎、webhook、下载都必须创建trace.SpanKindClient类型的 OTEL span并用semconv.ServerAddress(toolname)标注工具名trace 与 metrics 分别通过gotenberg.Tracer()和gotenberg.Meter()获取。这与Cmd.Exec()中的实现一致当 context 携带活跃 span 时Exec会记录一个process.exec客户端 span携带process.executable.name属性、进程退出码失败时记录错误与error.type无父 span 时跳过避免在请求路径之外产生孤儿根 spanpkg/gotenberg/cmd.go。Import 排序由gci强制标准库 → 第三方库 →github.com/gotenberg/gotenberg/v8内部包三组之间以空行分隔。文档规范Documentation conventions语气Tone短句、陈述句先说它做什么然后打住以动作开头Validates font embedding而不是This function validates font embedding主动语态Gotenberg checks the profile而不是The profile is checked by Gotenberg不用 em dash改用句号、冒号或逗号不用we式推诿Dont..., 而不是We do not recommend...。Godoc每个导出的类型和函数都要有以标识符名字开头的 Godoc 注释// OutboundDecision is the result of validating an outbound URL via // [DecideOutbound]. ... type OutboundDecision struct { ... } // DialPinned dials each addr in turn until one connects, returning the // first successful connection or the last error. ... func DialPinned(ctx context.Context, network string, addrs []netip.Addr, port string) (net.Conn, error)每个包应有doc.go内含// Package foo ...注释// Package api manages a LibreOffice instance via the UNO API. package api引用其他标识符时用[Name]方括号语法以便 pkg.go.dev 自动链接// Callers pass the Pinned slice from [OutboundDecision] so that the dial // targets exactly the IPs that [DecideOutbound] resolved, preventing DNS // rebinding between validation and connect.这一约定与仓库中大量包级doc.go文件如pkg/modules/chromium/doc.go、pkg/modules/pdfengines/doc.go一一对应。代码注释解释为什么而非是什么不用编号步骤注释// 1. Do X不用带编号的分节线// --- 8. Foo ---纯分隔线用于明显边界可以不写复述代码的噪音注释如// Check if err is nil涉及规范条款时引用出处如// Per ISO 32000-2, Table 116...技术债标记为// TODO: [context]。测试单元测试 Gherkin 集成测试双轨单元测试单元测试写在同包*_test.go文件中采用表驱动table-driven风格。应优先复用 pkg/gotenberg/mocks.go 中现成的综合 mock 实现而不是自己新造轮子。仓库中大量*_test.go如allowlist_test.go、flags_test.go、pattern_test.go都是表驱动范式的范例。集成测试Godog testcontainers集成测试采用 GherkinBDD语法由 Godog 驱动配合testcontainers-go做 Docker 编排。关键路径Feature 文件test/integration/features/*.feature每个端点或能力一个文件Step 定义test/integration/scenario/容器管理、HTTP 辅助、PDF 校验入口test/integration/main_test.gobuild tagintegration测试数据test/integration/testdata/基础设施每个场景通过 testcontainers 拉起全新的 Gotenberg Docker 容器另有一个gotenberg/integration-tools容器提供 PDF 校验工具verapdf、pdfinfo、pdftotext。运行make test-integration前必须先执行make build因为集成测试依赖本地构建的 Docker 镜像。完整套件有 40 分钟超时因此务必只跑与改动相关的标签。以 test/integration/features/health.feature 为例一个典型的 Gherkin 场景长这样health Feature: /health Scenario: GET /health Given I have a Gotenberg container with the following environment variable(s): | API_DISABLE_HEALTH_CHECK_ROUTE_TELEMETRY | false | When I make a GET request to Gotenberg at the /health endpoint Then the response status code should be 200 Then the response body should match JSON: { status: up, details: { chromium: { status: up, timestamp: ignore }, libreoffice: { status: up, timestamp: ignore } } } 可用标签分组集成测试标签按功能域分组完整清单见 test/integration/README.md分组标签Chromiumchromium、chromium-concurrent、chromium-convert-html、chromium-convert-markdown、chromium-convert-url、chromium-screenshot-html、chromium-screenshot-markdown、chromium-screenshot-url、chromium-ssrfLibreOfficelibreoffice、libreoffice-convert、libreoffice-ssrfPDF Enginespdfengines、pdfengines-convert、pdfengines-merge、merge、pdfengines-split、split、pdfengines-flatten、flatten、pdfengines-optimize、optimize、pdfengines-rotate、rotate、pdfengines-embed、embed、pdfengines-encrypt、encrypt、pdfengines-watermark、watermark、pdfengines-stamp、stamp、pdfengines-metadata、metadata、pdfengines-bookmarks、bookmarksInfrahealth、debug、root、version、output-filename、prometheus-metrics、webhook、download-from编写新集成测试的步骤在test/integration/features/创建或更新.feature文件打上合适的标签如chromium chromium-convert-html新增标签要同时加入 Makefile 的TAGS注释块和上表新增 step 定义时把函数加到scenario/scenario.go在InitializeScenario注册并把 step 模式补充到 step 参考文档测试数据放入test/integration/testdata/。写新测试前务必先读scenario.go和containers.go了解既有 step 与容器编排方式。测试中还支持make test-integration NO_CONCURRENCYtrue关闭并行场景以及PLATFORMlinux/arm64指定平台。step 参考覆盖了从给定容器环境变量到断言 PDF 页数、方向、内容、PDF/A 合规verapdf校验支持 PDF/A-1b/2b/3b、PDF/UA-1、PDF/UA-2、加密、扁平化、嵌入式文件等丰富断言。Pull Request 规范提交信息Conventional Commits提交信息遵循 Conventional Commits 格式type(scope): description。常用类型feat、fix、refactor、test、docs、chore、ci、build。scope 对应改动所属的模块或领域例如chromium、pdfengines、api。提交时必须分阶段暂存具体文件stage specific files绝不使用git add -A或git add .。提交前检查清单打开 PR 之前逐项确认无向后兼容性回归见 Backward compatibility 一节满足代码规范错误包装、日志、遥测、import 排序、无 panic、cmd/下无业务逻辑满足文档规范每个导出标识符都有 Godoc、新包有doc.go、语气合规make fmt make lint make prettify make lint-prettier零警告通过make test-unit通过相关的make test-integration TAGS...通过路由有增删改时Bruno 集合已同步更新。延伸阅读test/integration/README.mdGherkin step 参考、可用标签、编写新测试的方法.bruno/README.md.bru文件格式、约定、路由更新检查清单pkg/modules/pdfengines/README.md为 PDF 引擎新增功能Makefile 变量与标志。赞分享后端开发工具【免费下载链接】gotenbergA developer-friendly API for converting many document formats into PDF files, and more!项目地址https://gitcode.com/gh_mirrors/go/gotenberg点击查看免费下载相关推荐Gotenberg 开发者贡献指南模块架构、代码规范、测试体系与 Makefile 工作流全解Gotenberg 开发者贡献指南模块架构、代码规范、测试体系与 Makefile 工作流全解 Gotenberg 是一个基于 Docker 的文档转 PDF后端开发工具为 watermarks-remover 贡献代码分层架构、测试门禁与协作规范实战指南为 watermarks remover 贡献代码分层架构、测试门禁与协作规范实战指南 watermarks remover 是一个以隐私为中心的开源项目它AI 技能人工智能内容安全Mirai Console 开发与贡献指南模块架构、构建流程与代码规范Mirai Console 开发与贡献指南模块架构、构建流程与代码规范 Mirai Console 是 mirai 生态中高效率 QQ 机器人框架基于 mi即时通讯创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表