ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Renovate 的 scalafmt 管理器:从 .scalafmt.conf 提取并自动升级 Scalafmt 版本

Renovate 的 scalafmt 管理器:从 .scalafmt.conf 提取并自动升级 Scalafmt 版本 Renovate 的 scalafmt 管理器从 .scalafmt.conf 提取并自动升级 Scalafmt 版本【免费下载链接】renovateHome of the Renovate CLI: Cross-platform Dependency Automation by Mend.io项目地址: https://gitcode.com/GitHub_Trending/re/renovateRenovate 内置了scalafmt依赖管理器用于识别仓库中的.scalafmt.conf配置文件、提取其中的 Scalafmt 版本并通过 GitHub Releases 查找可升级的新版本。本文以该管理器的模块文档 lib/modules/manager/scalafmt/readme.md 为核心结合其源码与测试完整解析“文件匹配 → 版本提取 → 版本源查找 → v 前缀规范化”这条完整的更新链路帮助你理解这一管理器的实现细节与边界。管理器的定位与声明scalafmt管理器在 Renovate 中的模块入口是 lib/modules/manager/scalafmt/index.ts其中向框架声明了三项关键元信息数据源声明supportedDatasources仅包含GithubReleasesDatasource.id即github-releases。这与模块文档中“New versions of Scalafmt are looked up on Github Releases”的说明一一对应——Scalafmt 不发布到 Maven Central 等包仓库而是以 GitHub Release 的形式发布因此 Renovate 选择 GitHub Releases 数据源来发现新版本。分类categories: [java]将其归入 Java 生态分类。文档链接url字段指向 Scalafmt 官方配置文档中关于version字段说明的页面作为该管理器在文档站中展示的外部参考链接。入口文件同时通过export { extractPackageFile } from ./extract.ts将提取函数暴露给 Renovate 的通用 worker 流程。文件识别managerFilePatterns 如何命中 .scalafmt.conf该管理器能处理哪些文件由defaultConfig中的managerFilePatterns决定export const defaultConfig { managerFilePatterns: [/(^|/)\.scalafmt.conf$/], };这条正则/(^|/)\.scalafmt\.conf$/的含义是文件路径必须以.scalafmt.conf结尾且前面必须是路径开头^或目录分隔符/。由此可以得出两个行为特征仓库根目录下的.scalafmt.conf会被识别任意子目录如frontend/.scalafmt.conf中的同名文件也会被识别Renovate 会为每个命中的文件独立执行提取文件名相似但不完全匹配的如scalafmt.conf、.scalafmt.conf.bak不会命中。managerFilePatterns本身是 Renovate 的一个可配置项定义见 lib/config/options/index.ts用户也可以在仓库配置中覆盖它但对该管理器而言默认值已经覆盖了绝大多数 Scala 项目的布局。版本提取逻辑一个正则搞定有引号与无引号两种写法核心实现位于 lib/modules/manager/scalafmt/extract.ts全文只有 30 行逻辑非常聚焦const scalafmtVersionRegex regEx( version * *?(?version\\d\\.\\d\\.\\d)?, ); export function extractPackageFile(content: string): PackageFileContent | null { const regexResult scalafmtVersionRegex.exec(content); const scalafmtVersion regexResult?.groups?.version; if (!scalafmtVersion) { return null; } const scalafmtDependency: PackageDependency { datasource: GithubReleasesDatasource.id, depName: scalafmt, packageName: scalameta/scalafmt, versioning: semverVersioning.id, currentValue: scalafmtVersion, extractVersion: ^v(?version\\S), }; return { deps: [scalafmtDependency], }; }逐点解读这个提取器正则兼容性。version * *?(?version\d\.\d\.\d)?同时兼容 Scalafmt 配置中常见的两种写法version 3.8.0 # 无引号HOCON 标准写法 version 3.8.0 # 带引号正则中的?将双引号设为可选与版本号之间的空格也是可选的因此version3.8.0这种紧凑写法同样能命中。只提取三段式版本。捕获组固定为\d\.\d\.\d即必须是大版本.小版本.修订号的标准 semver 形态。如果配置文件中没有version行例如只配置了maxColumn 80extractPackageFile返回nullRenovate 会直接跳过该文件不会报解析错误。生成的依赖对象。提取成功后产出一个PackageDependency各字段的含义是字段取值作用datasourcegithub-releases声明用哪个数据源查找新版本depNamescalafmtPR 标题等展示用的依赖名packageNamescalameta/scalafmtGitHub 数据源所需的owner/repo形式的包名versioningsemver用标准语义化版本规则比较新旧版本currentValue提取到的版本号如3.8.0当前锁定/声明的版本extractVersion^v(?version\S)对数据源返回的 release tag 做前缀剥离见下文正则的底层实现。regEx工具来自 lib/util/regex.ts它优先使用 RE2 引擎构造正则带缓存、避免灾难性回溯RE2 不可用时回退到原生RegExp。这对 Renovate 处理任意仓库文件内容这类“不可信输入”场景尤为重要。测试用例印证lib/modules/manager/scalafmt/extract.spec.ts 中的四条用例与上述行为一一对应version 3.8.0→ 提取出currentValue: 3.8.0并断言datasource: github-releases、packageName: scalameta/scalafmt、versioning: semver、extractVersion: ^v(?version\\S)version 3.8.0→ 带引号写法同样提取成功仅有maxColumn 80的配置 → 返回null空字符串输入 → 返回null。新版本发现GitHub Releases 数据源如何工作提取阶段确定了packageName: scalameta/scalafmt后真正的版本查找发生在数据源层。lib/modules/datasource/github-releases/index.ts 中的GithubReleasesDatasource做了这些事情defaultRegistryUrls为https://github.com即默认在 GitHub 公共实例上查找getReleases通过queryReleasesGitHub GraphQL 查询拉取scalameta/scalafmt仓库的全部 Release逐条映射为{ version, gitRef, releaseTimestamp, isStable }形式的Release对象并附带由owner/repo推导出的sourceUrlreleaseTimestampSupport true说明该数据源提供发布时间戳这使得minimumReleaseAge等基于发布时间的配置可以生效getDigest则通过findCommitOfTag返回 release tag 对应的底层 commit SHA供需要摘要场景的调用方使用。extractVersion剥离 release tag 的 v 前缀Scalafmt 的 GitHub Release tag 形如v3.8.3带v前缀而.scalafmt.conf中书写的是裸版本号3.8.3。为了让数据源返回的版本能与currentValue在semver版本体系下正确比较提取时携带了extractVersion: ^v(?version\S)。这条规则的执行发生在数据源通用流程中lib/modules/datasource/index.ts 在拿到ReleaseResult后调用applyExtractVersion(res, config.extractVersion)而 lib/modules/datasource/common.ts 中的applyExtractVersion对每个 release 执行该正则命中^v(?version\S)的将v3.8.3重写为3.8.3同时把原始值保留在versionOrig字段中供 changelog、发布说明等场景还原真实 tag 使用未命中的 release 会被直接过滤掉。从源码结构看这种“数据源返回原始 tag、依赖项通过 extractVersion 规范化”的分工是 Renovate 数据源体系的通用做法scalafmt 管理器正是其中的一个典型样本.scalafmt.conf里写什么PR 中就改什么用户无需关心 release tag 的v前缀问题。一个端到端的例子假设仓库中存在如下文件# .scalafmt.conf version 3.8.0 runner.dialect scala213 maxColumn 100Renovate 的处理过程是managerFilePatterns命中该文件 → 正则提取出currentValue 3.8.0→ 通过github-releases数据源查询scalameta/scalafmt的所有 release → 用^v(?version\S)剥离v前缀 → 以semver比较找出大于3.8.0的最新稳定版本 → 生成将version 3.8.0改为version 3.8.3假设最新为v3.8.3的更新 PR。整个过程中只有version行被修改其余配置保持原样因为管理器只基于文本匹配做最小化替换。小结关注点实现位置模块元信息与文件匹配模式lib/modules/manager/scalafmt/index.ts版本正则与依赖对象构造lib/modules/manager/scalafmt/extract.ts提取行为验证lib/modules/manager/scalafmt/extract.spec.tsGitHub Releases 数据源lib/modules/datasource/github-releases/index.tsextractVersion 前缀剥离lib/modules/datasource/common.tsregExRE2 优先的正则工具lib/util/regex.tsscalafmt 管理器体现了 Renovate 处理“配置文件内嵌工具版本”类依赖的典型范式一个轻量的文件匹配规则 一个提取正则 一个通用数据源 一条版本规范化规则即可把.scalafmt.conf中的version纳入与任何包依赖相同的自动化升级体系。如果仓库中还存在其他以 GitHub Release 为发布渠道的 Scala 工具链组件参考这套实现或改用 custom manager 搭配extractVersion都是可行的扩展路径。【免费下载链接】renovateHome of the Renovate CLI: Cross-platform Dependency Automation by Mend.io项目地址: https://gitcode.com/GitHub_Trending/re/renovate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进