Renovate 的 endoflife-date 数据源:基于软件生命周期自动化更新版本
【免费下载链接】renovateHome of the Renovate CLI: Cross-platform Dependency Automation by Mend.io项目地址: https://gitcode.com/GitHub_Trending/re/renovate
本篇技术指南讲解 Renovate 中endoflife-date数据源(lib/modules/datasource/endoflife-date/)的完整用法:它借助 endoflife.date 提供的软件版本与生命周期终止(End-of-Life)信息,为那些没有传统包仓库的软件(如 Amazon EKS、操作系统发行版等)提供版本追踪能力。读完本文,你将掌握如何用自定义正则 Manager 把任意.tfvars等配置文件中的版本字段接入 Renovate 更新流程,并理解该数据源的底层请求、数据解析与废弃标记机制。
一、数据源是什么:用 EOL 信息驱动的版本追踪
endoflife-date数据源的核心思路很简单:很多软件并不发布在 npm、Maven 或 Docker Hub 这类传统注册表里,它们的版本演进与支持周期信息反而被整理在 endoflife.date 这个公开网站上。Renovate 通过该网站的公开 API 读取某个软件(如amazon-eks)的版本列表,从而把版本更新自动化能力延伸到这些"没有包管理器"的场景。
在仓库中,该数据源的标识与默认注册表地址定义在 lib/modules/datasource/endoflife-date/common.ts:
export const registryUrl = 'https://endoflife.date/api'; export const datasource = 'endoflife-date';这意味着在配置中只需写datasource=endoflife-date,Renovate 就会向该 API 发起查询。对应的数据源实现类是EndoflifeDateDatasource(lib/modules/datasource/endoflife-date/index.ts),它继承了统一的Datasource抽象基类(lib/modules/datasource/datasource.ts),对外暴露标准的getReleases()接口。
二、底层工作原理:请求、解析与缓存
1. 请求路径构造
当 Renovate 需要查询某个软件时,会调用_getReleases(),通过joinUrlParts拼接出最终的 API 路径:
const url = joinUrlParts(registryUrl, `${packageName}.json`);也就是说,depName=amazon-eks最终会被解析为对https://endoflife.date/api/amazon-eks.json的 GET 请求。因此,depName 必须与 endoflife.date 站内登记的软件名称(package 名称)完全一致。如果你不确定某个软件在 endoflife.date 上的确切名称,可以使用该网站 API 文档中提供的 "All packages"(全部软件包)端点来查询可用清单。
2. 响应数据解析:Zod Schema 与废弃标记
API 返回的是 JSON 数组,每一项代表一个版本周期(cycle)。数据源用 Zod schema(lib/modules/datasource/endoflife-date/schema.ts)进行校验和转换:
const ExpireableField = z.union([ UtcDate.transform((x) => { const now = DateTime.now().toUTC(); return x <= now; // 日期型 EOL:若已过期则视为废弃 }), z.boolean(), // 布尔型 EOL / discontinued ]); export const EndoflifeDateVersions = z .object({ cycle: z.string(), latest: z.optional(z.string()), releaseDate: MaybeTimestamp, eol: z.optional(ExpireableField), discontinued: z.optional(ExpireableField), }) .transform(({ cycle, latest, releaseDate, eol, discontinued }): Release => { const version = latest ?? cycle; const isDeprecated = eol === true || discontinued === true; return { version, releaseTimestamp, isDeprecated }; }) .array();从这段源码可以提炼出几个关键事实:
- 版本号取值:优先取
latest字段;若不存在,则回退到cycle(版本周期名)。例如 Amazon EKS 数据中cycle为1.26、latest为1.26-eks-1,最终版本号取1.26-eks-1。 - 发布时间的来源:
releaseDate字段被映射为releaseTimestamp。数据源在类声明中标注了releaseTimestampSupport = true,并在releaseTimestampNote中说明:"发布时间的确定来自结果中的releaseDate字段"。这意味着 Renovate 可以基于该时间戳应用"最小发布时间"(minimum release age)等策略。 - 废弃判断:
eol与discontinued字段既可能是布尔值,也可能是日期字符串。日期会被与当前 UTC 时间比较:若 EOL 日期已过,该版本被视为已废弃(deprecated)。这一逻辑在测试中得到了充分验证(详见下文第五节)。
3. 默认行为与缓存
EndoflifeDateDatasource还声明了这些默认行为(lib/modules/datasource/endoflife-date/index.ts):
| 属性 | 值 | 含义 |
|---|---|---|
defaultRegistryUrls | [https://endoflife.date/api] | 默认注册表地址 |
defaultVersioning | loose | 默认使用宽松版本控制 |
caching | true | 结果可被包缓存复用 |
releaseTimestampSupport | true | 支持基于发布日期的时间策略 |
getReleases()外层还套了一层withCache包缓存,缓存键为registryUrl:packageName的组合;这保证了同一仓库中多次查询同一个软件时不会重复请求 API。而错误处理走的是基类handleGenericErrors(lib/modules/datasource/datasource.ts):遇到 429 限流或 5xx 服务端错误会包装成ExternalHostError抛出,404 与空结果则直接返回null(表示查无此包)。
三、版本控制:默认 loose,推荐 semver
原文档明确提醒:该数据源默认使用loose版本控制。loose是 Renovate 中最宽松的版本方案,几乎任何字符串形式都能被解析,适合像1.26-eks-1、3+这类非标准版本号。
但宽松也意味着排序和比较规则简单粗暴。因此官方文档建议:只要可能,就改用更严格的版本方案(如semver),以获得更准确的升级判断。你可以在renovate.json的packageRules中用matchVersioning(或在自定义 Manager 的versioningTemplate中)为特定包指定更严格的版本控制。仓库中endoflife-date的测试(lib/modules/datasource/endoflife-date/index.spec.ts)使用的也是默认的 loose 解析。
四、实战配置:用自定义 Manager 更新 Terraform.tfvars中的版本
原文档给出了一个完整的端到端示例,这是本数据源最典型的应用场景:使用 Amazon EKS 时,让 Renovate 自动更新 Terraform.tfvars文件里的 Kubernetes 版本号。
1. 在.tfvars文件中标记要更新的变量
假设你的仓库里有这样一个.tfvars文件,其中kubernetes_version定义了 EKS 使用的 Kubernetes 版本:
# renovate: datasource=endoflife-date depName=amazon-eks versioning=loose kubernetes_version = "1.26"注意紧挨着变量的这行注释:# renovate: datasource=endoflife-date depName=amazon-eks versioning=loose。它相当于给 Renovate 下达指令——用endoflife-date数据源、查询amazon-eks这个软件、按loose版本方案来更新下一行的版本值。注释中的depName必须与 endoflife.date 上登记的软件名称一致。
2. 在renovate.json中注册自定义 Manager
接下来在renovate.json中配置一个customType: "regex"的自定义 Manager,让 Renovate 去扫描并解析所有.tfvars文件:
{ "customManagers": [ { "customType": "regex", "description": "Update Kubernetes version for Amazon EKS in tfvars files", "managerFilePatterns": ["/.+\\.tfvars$/"], "matchStrings": [ "#\\s*renovate:\\s*datasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s.*?_version\\s*=\\s*\"(?<currentValue>.*)\"" ], "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{/if}}" } ], "packageRules": [ { "matchDatasources": ["endoflife-date"], "matchPackageNames": ["amazon-eks"], "extractVersion": "^(?<version>.*)-eks.+$" } ] }这份配置各部分的职责如下:
managerFilePatterns:限定只处理仓库中匹配/.+\.tfvars$/的文件。matchStrings:一个正则表达式,负责从注释行与赋值行中捕获四个命名组:datasource、depName、versioning、currentValue。其中versioning组是可选的(( ... )?),体现"注释里可以不写versioning"的容错设计。versioningTemplate:使用 Handlebars 模板语法,把注释中捕获到的versioning值动态注入;若注释未写versioning,则回退到数据源默认的loose。packageRules.extractVersion:对amazon-eks的版本号做归一化,详见下文。
3. 执行效果
启用以上配置后,Renovate 会:
- 解析仓库中所有
*.tfvars文件; - 定位以
# renovate: datasource=endoflife-date depName=dependency-name versioning=versioning注释开头、且变量名以_version结尾的赋值行; - 调用 endoflife.date 数据源查询新版本;
- 有新版本时,自动将
currentValue更新为最新版本并提交 PR。
针对amazon-eks的packageRule还会额外做一步清洗:通过extractVersion正则^(?<version>.*)-eks.+$把类似1.26-eks-1的完整版本号中-eks-${eks-release-version}后缀剥掉,只保留 Kubernetes 主次版本号(如1.26),从而让升级判断聚焦在 Kubernetes 主版本层面。
五、extractVersion 的源码级解释
extractVersion是 Renovate 在获取版本列表后、进入版本比较前执行的一层预处理。在 lib/modules/datasource/common.ts 的applyExtractVersion中可以看到它的实现:
const extractVersionRegEx = regEx(extractVersion); releaseResult.releases = filterMap(releaseResult.releases, (release) => { const version = extractVersionRegEx.exec(release.version)?.groups?.version; if (!version) { return null; // 无法匹配的版本会被剔除 } release.versionOrig = release.version; // 原始版本号被保留到 versionOrig release.version = version; return release; });也就是说:extractVersion通过具名捕获组(?<version>...)从 API 返回的版本号中提取出"真正参与比较的版本";原版本号保存在versionOrig中不会丢失。这一处理发生在 lib/modules/datasource/index.ts 的applyDatasourceFilters调用链中(先applyExtractVersion,再做过滤、排序去重与约束筛选),因此如果某个版本的原始字符串无法被extractVersion匹配,它会被直接过滤掉——这提醒我们在编写该正则时要覆盖数据源可能返回的所有版本形态。
六、测试用例验证:数据解析与异常处理的可靠保证
仓库为该数据源提供了完整的单元测试(lib/modules/datasource/endoflife-date/index.spec.ts),可以作为理解其行为最直观的参考:
- 真实数据处理:使用
eks.json夹具(lib/modules/datasource/endoflife-date/fixtures/eks.json)模拟 API 响应,断言amazon-eks返回 9 个版本,其中1.18到1.21等已过 EOL 的版本isDeprecated: true,1.22及之后的版本为false,且每个版本都带上了releaseTimestamp。 - 布尔型废弃标记:使用
apache-cassandra.json夹具,验证discontinued: true字段(布尔型)会被正确识别为已废弃。 - 日期型废弃标记:使用
fairphone.json夹具,验证eol为日期字符串时,测试中把系统时间固定为2023-06-03(通过 luxon 的Settings.now注入),早于该时间的eol日期被判定为废弃。 - 边界与异常:
registryUrl为空时返回null;API 返回 404 时返回null;返回空数组时返回null;返回 5xx 时抛出EXTERNAL_HOST_ERROR。
这些测试同时覆盖了 schema 解析、废弃判断、错误处理三个维度,说明该数据源在"数据不完美"(缺字段、废弃字段类型不一)的情况下也能稳定工作。
七、使用建议与注意事项
- 先确认 package 名称:
depName必须是 endoflife.date 已登记的软件名,建议通过其 API 文档中的 "All packages" 端点核对,避免因名称不符导致 404(404 时数据源返回null,Renovate 会静默跳过该依赖)。 - 版本方案按需收紧:默认
loose能覆盖大多数情况,但如果你的软件版本符合 SemVer 规范,优先显式指定versioning=semver以获得更精确的升级判断。 extractVersion要写全:正则需覆盖该软件 API 可能返回的所有版本形态,否则无法匹配的版本会被过滤,可能导致漏更新。- 该数据源适合的软件:EKS、Kubernetes 发行版、操作系统版本、语言运行时等没有传统包仓库、但有明确版本与支持周期的软件。它不适用于已有专门 datasource 的生态(如 npm 包应使用 npm 数据源)。
八、相关文件索引
- 数据源实现:lib/modules/datasource/endoflife-date/index.ts
- 常量定义:lib/modules/datasource/endoflife-date/common.ts
- 响应 Schema:lib/modules/datasource/endoflife-date/schema.ts
- 单元测试:lib/modules/datasource/endoflife-date/index.spec.ts
- 测试夹具:lib/modules/datasource/endoflife-date/fixtures/(
eks.json、apache-cassandra.json、fairphone.json) - 数据源基类:lib/modules/datasource/datasource.ts
- 版本获取与过滤管线:lib/modules/datasource/index.ts、lib/modules/datasource/common.ts
【免费下载链接】renovateHome of the Renovate CLI: Cross-platform Dependency Automation by Mend.io项目地址: https://gitcode.com/GitHub_Trending/re/renovate
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考