ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Plane 仓库版权合规机制解析:基于 addlicense 的自动化 Copyright 检查与批量修复实践

2026/9/7 9:11:10 拓冰建站 浏览量
Plane 仓库版权合规机制解析:基于 addlicense 的自动化 Copyright 检查与批量修复实践 Plane 仓库版权合规机制解析:基于 addlicense 的自动化 Copyright 检查与批量修复实践【免费下载链接】plane Open-source Jira, Linear, Monday, and ClickUp alternative. Plane is a modern project management platform to manage tasks, sprints, docs, and triage.项目地址: https://gitcode.com/GitHub_Trending/pl/plane本文基于 Plane 仓库根目录的 COPYRIGHT_CHECK.md 展开,完整讲解 Plane 如何借助 Google 开源的addlicense工具,对数千个 Python/TypeScript 源文件统一施加 AGPL-3.0 版权头、如何在本地执行“检查”与“批量补写”两类操作,以及该流程在 CI 流水线中的落地方式。读完本文,你可以独立在本地复现 Plane 的版权头校验,并理解各命令行参数、忽略规则与仓库实际文件结构之间的对应关系。背景:为什么 Plane 要对每个源文件施加统一的版权头Plane 是一个以 AGPL-3.0 协议开源的项目管理工具(见 LICENSE.txt)。对多语言(monorepo)仓库而言,仅靠根目录的 LICENSE 文件声明协议是不够的——AGPL 的分发与衍生作品要求明确标识每个文件的版权归属与许可条款。为此,Plane 建立了一套“版权头检查”机制:所有被 Git 追踪的 Python 与 TypeScript 源文件,必须包含指向Plane Software, Inc.且年份标记为2023-present的标准版权头;版权头模板集中存放在仓库根目录的 COPYRIGHT.txt,检查与写入操作都以它为唯一事实来源(single source of truth)。模板内容非常精简,分三行:Copyright (c) 2023-present Plane Software, Inc. and contributors SPDX-License-Identifier: AGPL-3.0-only See the LICENSE file for details.addlicense会根据目标文件的语言自动选择合适的注释语法。从仓库实际文件可以看到两种落地形态:Python 文件使用#行注释,例如 apps/api/plane/urls.py:# Copyright (c) 2023-present Plane Software, Inc. and contributors # SPDX-License-Identifier: AGPL-3.0-only # See the LICENSE file for details.TypeScript 文件使用块注释,例如 packages/utils/src/array.ts:/** * Copyright (c) 2023-present Plane Software, Inc. and contributors * SPDX-License-Identifier: AGPL-3.0-only * See the LICENSE file for details. */核心操作一:检查(check)所有 Python 文件的版权头COPYRIGHT_CHECK.md 给出的检查命令是:addlicense --check -f COPYRIGHT.txt -ignore **/migrations/** $(git ls-files *.py)该命令必须在仓库根目录执行,各部分含义如下:组成部分作用--check进入只读检查模式:不修改任何文件,只要存在缺失或版权头不正确的文件,命令即以失败退出码结束-f COPYRIGHT.txt指定版权头模板文件,即仓库根目录的 COPYRIGHT.txt-ignore **/migrations/**忽略所有migrations/目录下的文件,即 Django 自动生成的迁移文件$(git ls-files *.py)只把 Git 追踪的.py文件传给addlicense,避免扫描未提交的临时文件或构建产物为什么必须忽略 migrations 目录-ignore **/migrations/**不是随意加上的,而是由 Django 项目的实际结构决定的。Plane 的 API 是 Django 应用,迁移文件位于 apps/api/plane/db/migrations 与 apps/api/plane/license/migrations 等目录,例如0002_rename_version_instance_current_version_and_more.py。这些文件由makemigrations自动生成、频繁变动,若在文件头部插入任意注释,既会污染自动生成的产物,也会让后续自动工具的处理变复杂。因此检查规则明确将它们排除在外——这也是阅读 Plane 贡献规范时应注意的一个细节:你新增的 Django 迁移文件不需要手工添加版权头。核心操作二:批量写入(apply)版权头当 check 发现缺失项后,需要批量补写。COPYRIGHT_CHECK.md 提供了两套“应用”命令。1. 对 Python 文件批量写入addlicense -v -f COPYRIGHT.txt -ignore **/migrations/** $(git ls-files *.py)与 check 命令相比,这里去掉了--check参数——addlicense默认行为即为“确保头部存在,缺失则写入”,并新增-v(verbose)让工具输出每次实际修改的文件清单,方便提交前复核 diff。2. 对指定 app/package 下的 ts、tsx 文件写入addlicense -v -f COPYRIGHT.txt \ -ignore **/*.config.ts \ -ignore **/*.d.ts \ $(git ls-files packages/*.ts)这条命令有两个值得注意的设计:排除构建配置与类型声明文件:-ignore **/*.config.ts排除的是各包的构建配置文件,例如 packages/editor/tsdown.config.ts、packages/shared-state/tsdown.config.ts 等;-ignore **/*.d.ts排除手写/生成的类型声明。这类文件要么由工具链维护,要么并非真正的“源码”,因此不纳入版权头管理。必须在特定目录下执行:$(git ls-files packages/*.ts)是相对当前工作目录的路径查询。文档特别警告:“请确保 ts 命令在特定文件夹下运行,对整个 monorepo 执行会压垮 OS 进程”——即在仓库根目录对海量 TS 文件一次性跑addlicense可能因进程/文件句柄压力导致系统异常。实操上建议进入目标packages/name或apps/name目录后再执行。参数速查:addlicense 常用选项COPYRIGHT_CHECK.md 的 “Other Options” 一节列出了该工具的其他关键参数,整理如下:参数说明addlicense -check只读检查模式,发现缺失或错误的头部即失败(常用于 CI 门禁)-c Plane Software Inc.显式设置版权持有者名称-f LICENSE.txt使用指定文件(此处为LICENSE.txt)的内容与格式作为头部模板;Plane 实际使用的是 COPYRIGHT.txt-y 2023显式设置头部中年份字段为 2023$(git ls-files *.py)借助 shell 命令替换,将待检查范围限制在 Git 追踪的 Python 文件需要说明的是:Plane 的实际流程中,版权持有者与年份都由模板文件 COPYRIGHT.txt 中的2023-present字面量提供,-c/-y属于工具的通用能力,在 Plane 的现有命令中并未直接用到——模板即事实来源,这比在命令行里散落硬编码参数更可维护。CI 落地:pull request 上的自动版权门禁本地命令的“云端版本”是仓库中的 copyright-check.yml。从该 workflow 可以确认几件事:触发时机:手动workflow_dispatch触发,或 PR 指向preview分支且事件为opened、synchronize、ready_for_review、review_requested、reopened——即每次 PR 更新都会重跑检查。工具安装:addlicense是 Go 语言编写的工具,CI 先安装 Go 1.22,再执行:go install github.com/google/addlicenselatest echo $(go env GOPATH)/bin $GITHUB_PATH本地复现时同样可以用go install github.com/google/addlicenselatest安装,无需 Node 或 Python 环境。两条检查任务,均带set -e保证任一失败立即终止:Python 文件(与文档中的 check 命令完全一致):addlicense -check -f COPYRIGHT.txt -ignore **/migrations/** $(git ls-files *.py)TypeScript 文件(注意:CI 是全仓范围,而非文档建议的“特定目录”,并额外覆盖.tsx):addlicense -check -f COPYRIGHT.txt -ignore **/*.config.ts -ignore **/*.d.ts $(git ls-files *.ts *.tsx)从源码结构看,文档中的 ts 命令(限定packages/*.ts且建议逐包执行)与 CI 中的全仓 ts 命令是互补关系:CI 只做只读检查(开销可控),而写入修改操作因性能原因建议缩小到单个包目录执行。本地复现步骤汇总在克隆仓库后(例如git clone https://gitcode.com/GitHub_Trending/pl/plane),按以下步骤可完整走一遍 Plane 的版权合规流程:# 1. 安装工具(需要 Go 环境,CI 使用 Go 1.22) go install github.com/google/addlicenselatest # 2. 在仓库根目录检查 Python 文件 addlicense --check -f COPYRIGHT.txt -ignore **/migrations/** $(git ls-files *.py) # 3. 如需修复,去掉 --check 并加 -v 批量写入 addlicense -v -f COPYRIGHT.txt -ignore **/migrations/** $(git ls-files *.py) # 4. 对某个 TypeScript 包(建议 cd 进该包目录)单独执行 cd packages/utils # 示例:进入具体包目录 addlicense -v -f COPYRIGHT.txt \ -ignore **/*.config.ts \ -ignore **/*.d.ts \ $(git ls-files *.ts *.tsx)排错提示:若命令报addlicense: command not found,检查go env GOPATH/bin是否已在PATH中(CI 通过$GITHUB_PATH解决,本地同理);若 TS 检查在仓库根目录执行异常缓慢或系统资源吃紧,遵循文档提示,改为进入具体apps/或packages/子目录执行;检查失败时,addlicense会列出具体缺失或格式不符的文件,对照 COPYRIGHT.txt 的三行模板即可定位差异(常见差异是年份写成2023而非2023-present,或持有者名称不精确匹配)。小结Plane 的版权合规体系由三个要素构成:以 COPYRIGHT.txt 为唯一模板(含 AGPL-3.0-only 的 SPDX 标识)、以addlicense的 check/apply 双模式覆盖“验证—修复”闭环、以 copyright-check.yml 作为 PR 级自动门禁。围绕这一机制,通过-ignore规则精确豁免 Django migrations、构建配置与类型声明文件,再配合“TS 写入操作须限定目录”的性能约束,使得这套检查既能守住 AGPL 归属声明的底线,又不会对 monorepo 的日常开发流程造成额外负担。【免费下载链接】plane Open-source Jira, Linear, Monday, and ClickUp alternative. Plane is a modern project management platform to manage tasks, sprints, docs, and triage.项目地址: https://gitcode.com/GitHub_Trending/pl/plane创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考