MagmaMoose/diatreme

GitHub: MagmaMoose/diatreme

Diatreme 是一个发布/部署编排器,通过单一 GitHub Action 调用统一管理语义化版本控制、Docker 构建、镜像提升和多生态包发布的完整流程。

Stars: 0 | Forks: 0

# Diatreme [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/magmamoose/diatreme/actions/workflows/ci.yaml) [![Release](https://static.pigsec.cn/wp-content/uploads/repos/cas/42/42ba98a60a0bb3b0ad908f024db145f9c5b831eb7df822f56ac578ee7d7215b3.svg)](https://github.com/magmamoose/diatreme/actions/workflows/release.yaml) [![GitHub Marketplace](https://img.shields.io/badge/Marketplace-Diatreme-purple?logo=github)](https://github.com/marketplace/actions/diatreme) [![License](https://img.shields.io/github/license/magmamoose/diatreme)](https://github.com/magmamoose/diatreme/blob/main/LICENSE) Diatreme 是一个**发布/部署编排器**:一个用于跨 TBD 和 BBD 工作流进行 semantic-release 的复合 GitHub Action。它运行发布流程,构建 PR Docker 镜像,扫描组装好的镜像并将其 SBOM 发送到 Dependency-Track(以及可选的 findings 发送到 DefectDojo),通过重新打标签来提升已构建的 GHCR 镜像,开启提升 PR,发布语言包(npm/maven/gradle/rubygems/containers),并规范化跨多种版本控制工具的发布输出。 此存储库包含 Diatreme 的**两个交互面**: | 交互面 | 路径 | 说明 | | --- | --- | --- | | **Composite Action** | [`action.yml`](action.yml) + [`scripts/`](scripts) | 您的工作流通过 `uses: magmamoose/diatreme@v1` 调用的 GitHub Marketplace action。 | | **Cloudflare Worker** | [`worker/`](worker) | 托管的 GitHub App 后端,Action 会在 `api.diatreme.magmamoose.com` 调用它 —— 它是 OIDC **token broker**,也是负责进行 App/bot 身份标识发布提交的 **commit/tag signer**。 | Action 是您从 Marketplace 安装的内容;Worker 是 GitHub App 后端,它允许 `auth-mode: public-app` 在您不注册自己的 App 的情况下生成发布 token 并签署发布提交。**大多数用户只需要 Action** —— 请从[快速开始](#quickstart)开始。如需自托管或开发后端,请参阅 [Diatreme Worker](#the-diatreme-worker)。 ## 快速开始 仅限从 `main` 进行生产环境发布,使用托管的 Diatreme GitHub App token broker: ``` name: Release on: push: branches: [main] jobs: release: runs-on: ubuntu-latest permissions: contents: read id-token: write steps: - uses: magmamoose/diatreme@v1 with: environment: prod environments: '["prod"]' prerelease-identifiers: '{}' ``` 在存储库或组织上安装 [Diatreme GitHub App](https://github.com/apps/diatreme/installations/new)。添加版本控制工具的配置 —— 例如上述示例中的 `pyproject.toml` `[tool.semantic_release]` 部分 —— 并合并约定式提交。Diatreme 会负责写入 tag、GitHub Release、changelog 以及规范化输出。 默认情况下(`versioning-tool: auto`),Diatreme 会根据存储库标记来选择版本控制工具,因此无论存储库是使用 python-semantic-release、semantic-release (npm)、GitVersion 还是 release-please 进行版本控制,同一个工作流都能正常工作 —— 无需为每个存储库单独指定 `versioning-tool`。请参阅[版本控制工具检测](#versioning-tool-detection)。 ## 所需权限 对于默认的 `auth-mode: public-app`,工作流需要 `id-token: write`,以便 Diatreme 可以将 GitHub OIDC 交换为短期的 installation token。在进行 checkout 时保留 `contents: read`。仅需添加所选功能所需的权限: | 功能 | 额外的工作流权限 | | --- | --- | | Docker PR 镜像推送或发布提升 | `packages: write` | | 将包发布到 GitHub Packages feed (`publish-package`) | `packages: write` | | 公共 npm 溯源 (`npm-provenance`) 或 PyPI Trusted Publishing (`pypi-trusted-publishing`) | `id-token: write`(默认的 `auth-mode: public-app` 已要求此权限) | | 提升 PR 创建 | 由 Diatreme App token 处理;仅在使用 `auth-mode: github-token` 时使用 `pull-requests: write` | | `auth-mode: github-token` 发布写入 | `contents: write`,创建 PR 时还需 `pull-requests: write` | ## 示例 PR Docker 镜像构建: ``` name: CI on: pull_request: jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write pull-requests: read steps: - uses: magmamoose/diatreme@v1 with: mode: ci image_name: my-app ``` 带有提升 PR 的多环境 TBD: ``` name: Release on: push: branches: [main] pull_request: types: [closed] jobs: release: if: github.event_name == 'push' || github.event.pull_request.merged == true runs-on: ubuntu-latest permissions: contents: read id-token: write packages: write steps: - uses: magmamoose/diatreme@v1 with: mode: release deployment-model: tbd-pr environment: dev environments: '["dev", "staging", "prod"]' prerelease-identifiers: '{"dev": "dev", "staging": "rc"}' create-promotion-pr: 'true' image_name: my-app ``` 基于分支的开发: ``` steps: - uses: magmamoose/diatreme@v1 with: deployment-model: bbd branch-map: '{"develop": "dev", "release/*": "staging", "main": "prod"}' ``` ## 发布语言包 设置 `publish-package: true` 并选择一个 `package-ecosystem`,以使用 Diatreme 刚刚计算出的版本来打包并推送 库包 —— 而不是在您的发布工作流中额外拼接一个单独的 `pack`/`push` 步骤。发布是可选的(opt-in), 仅在新版本已发布(`released == true`)时运行,并继承与版本控制相同的环境门控:dev/staging 运行会发布预发布 版本(例如 `1.2.3-rc.1`),prod 运行会发布稳定版本。该包 会在 GitHub Release 发布之前被推送,因此 `release:published` 监听器会发现它已经存在于 feed 中。 ### 选择发布位置 `package-feed-url` 是**上传/发布 endpoint**。有两个问题决定了它的指向。 **1. 您使用的是哪个 GitHub 主机?** Registry 的主机名与您所在的 host 相对应: | Host | 语言包主机 | Container 主机 | | --- | --- | --- | | github.com / 标准 Enterprise Cloud | `.pkg.github.com` | `ghcr.io` | | Enterprise Server (例如 `github.example.com`) | `.HOSTNAME` | `containers.HOSTNAME` | | 具有数据驻留的 Enterprise Cloud (`SUBDOMAIN.ghe.com`) | `.SUBDOMAIN.ghe.com` | `containers.SUBDOMAIN.ghe.com` | 对于语言生态系统,Diatreme 是与具体 host 无关的 —— `package-feed-url` 是一个 输入项,因此请将其指向适用的任意 host。下面列出的各生态系统默认值 假定环境为 github.com。有关确切的 host 形式和注意事项,请参阅 [GitHub Enterprise](#github-enterprise)(特别是:Container registry 在 Enterprise Server 上需要启用子域名隔离,并且 Apache Maven registry 不适用于启用数据驻留的租户)。 **2. 公共还是内部?**(github.com / Enterprise Cloud 的区别) - **Containers** → GitHub Packages (`ghcr.io`) 在任何可见性级别下都可正常工作:公共 镜像可以通过 `docker pull` 匿名拉取,因此对于内部和公共镜像来说,ghcr 都是一个很好的默认选择。 - **内部/私有语言包** —— 使用者是经过身份验证的组织 成员 → GitHub Packages (`*.pkg.github.com`) 是一个不错的默认选择,这就是为什么 Diatreme 在此默认使用 GitHub Packages 生态系统。 - **公共语言包** —— 您希望允许匿名安装 → 请将 `package-feed-url` 指向标准的公共 registry(如 npmjs、 nuget.org、rubygems.org、Maven Central、PyPI)。**除 Container registry 外,每个 GitHub Packages registry 都需要 token 才能*使用*,即使对于公共包也是如此** ([GitHub 文档](https://docs.github.com/en/packages/learn-github-packages/about-permissions-for-github-packages)), 因此无法匿名安装位于 `*.pkg.github.com` 上的包。 在 GitHub Enterprise 上,这两个维度合而为一。私有的 Enterprise Server 或 数据驻留实例在 github.com 的意义上没有“公共”层 —— 一切都处于企业的身份验证边界之后。在那里,“内部”意味着企业*自己的* registry host,而公共/上游依赖项 通常通过企业的 artifact 管理器(Nexus、Artifactory、 ……)进行代理,而不是直接从标准的公共 registry 拉取。上面关于“使用标准公共 registry”的建议仅适用于 github.com / Enterprise Cloud 概念。 支持的生态系统。`nuget`、`maven`、`gradle`、`rubygems` 和 `container` 默认指向**此存储库自身的 GitHub Packages feed**(在 github.com 上为 `*.pkg.github.com` / `ghcr.io`),因此在进行*内部*分发时,可以省略 `package-feed-url` / `package-token`。`npm` 和 `pip` 默认指向**公共** registry (`registry.npmjs.org` / PyPI)。如果要对 GitHub Packages 生态系统进行公共 分发,或者用于任何 GitHub Enterprise host(见上文),请覆盖 `package-feed-url`: - `nuget` — `dotnet pack` + `dotnet nuget push`。 - `npm` — `npm publish`(预发布版本会指向一个以环境的预发布标识符命名的非 `latest` dist-tag)。 - `maven` — `mvn versions:set` + `mvn deploy`(凭证位于每次运行的 `settings.xml` 中,保留在项目树之外)。 - `gradle` — 通过项目的 `maven-publish` 块执行 `gradle publish`;对于 `GitHubPackages` repository,会传入版本号以及常规的 `GITHUB_ACTOR`/`GITHUB_TOKEN` 凭证。 - `rubygems` — `gem build` + `gem push`。 - `container` — `docker build` + `docker push` 到 `ghcr.io//:`(使用 `package-feed-url` 覆盖 registry 主机 —— 例如企业的 `containers.HOSTNAME` —— 并使用 `package-name` 覆盖镜像名称)。这是对现有镜像*提升*的补充 —— 这将构建并发布发布版本。 - `pip` — `python -m build` + `twine upload`(PyPI 或任何 index;不属于 GitHub Packages 生态系统,仅为方便起见保留)。 将内部共享组件库发布到私有的 GitHub Enterprise NuGet feed —— 这是 Diatreme 的起源用例 —— 只需一次调用即可完成版本控制和发布: ``` name: Release on: push: branches: [main] jobs: release: runs-on: ubuntu-latest permissions: contents: read id-token: write packages: write steps: - uses: magmamoose/diatreme@v1 with: versioning-tool: gitversion environment: prod environments: '["prod"]' prerelease-identifiers: '{}' publish-package: 'true' package-ecosystem: nuget package-path: src/SharedComponents/SharedComponents.csproj package-feed-url: https://nuget.example.ghe.com/my-org/index.json package-token: ${{ secrets.NUGET_FEED_TOKEN }} ``` 对于存储库所有者的 GitHub Packages NuGet feed,请省略 `package-feed-url` 和 `package-token` —— 它们默认为 `https://nuget.pkg.github.com//index.json` 以及工作流的 `GITHUB_TOKEN`(需要 `packages: write`)。 相同的默认设置也适用于其他 GitHub Packages 生态系统(Maven、Gradle、 RubyGems 和 Container → `ghcr.io`)。对于 `container`,`package-path` 是 Docker 构建上下文,而 `package-name` 默认为 `/`。 ### GitHub Enterprise 发布在 GitHub Enterprise 上的工作方式相同 —— 身份验证模型保持不变 (Actions 的 `GITHUB_TOKEN`,或者您传入的 `package-token`,只是会针对 企业实例而不是 github.com 进行身份验证)。只有 **host** 发生了变化,因此请将 `package-feed-url` 设置为匹配的 registry 主机。(上面的 NuGet 示例已经指向了企业主机。) **Enterprise Server**(自托管,已启用子域名隔离)—— 主机名 源自实例主机名(`HOSTNAME`): | 生态系统 | `package-feed-url` | | --- | --- | | `nuget` | `https://nuget.HOSTNAME//index.json` | | `npm` | `https://npm.HOSTNAME` | | `maven` / `gradle` | `https://maven.HOSTNAME//` | | `rubygems` | `https://rubygems.HOSTNAME` | | `container` | `containers.HOSTNAME` | Container registry **要求在实例上启用子域名隔离** —— 否则将没有 container 主机。(旧版本在 `docker.HOSTNAME` 暴露了传统的 Docker registry;在实例迁移到 `containers.HOSTNAME` 后,使用它的镜像引用仍然可以继续工作。) **具有数据驻留的 Enterprise Cloud** —— 即 `SUBDOMAIN.ghe.com` 租户,其中 `SUBDOMAIN` 是您企业的唯一子域名: | 生态系统 | `package-feed-url` | | --- | --- | | `nuget` | `https://nuget.SUBDOMAIN.ghe.com//index.json` | | `npm` | `https://npm.SUBDOMAIN.ghe.com` | | `rubygems` | `https://rubygems.SUBDOMAIN.ghe.com` | | `container` | `containers.SUBDOMAIN.ghe.com` | 标准的 Enterprise Cloud 组织(在 github.com 上访问,无数据 驻留)使用公共的 `*.pkg.github.com` / `ghcr.io` 主机 —— 与 github.com 上的默认设置 相同。 ### Maven 和 Gradle:这不是 Maven Central 发布 `maven` 和 `gradle` 路径针对 **Maven 风格的 repository** 运行 `mvn deploy` / `gradle publish` —— 默认为 GitHub Packages,或者是您的企业 Maven 主机。这*不*是 Maven Central 发布流程:Central 要求进行 GPG 签名,并通过 staging / Central Portal(以前称为 OSSRH)进行部署,而此 action 并不执行这些操作。要发布到 Maven Central,请使用专为该流程构建的工具来驱动 —— 例如 [JReleaser](https://jreleaser.org/) 或 [`central-publishing-maven-plugin`](https://central.sonatype.org/publish/publish-portal-maven/) —— 而不是使用 `publish-package`。 ### 私有 Python index (pip) GitHub Packages **没有 Python registry**(在 github.com 或 Enterprise 上都没有),因此 `pip` 不是 Packages 生态系统 —— 它始终指向 PyPI 或独立的 index。这涉及到两个 endpoint,并且它们是相互独立的: - **Upload** — `package-feed-url` 是 twine 的 `--repository-url`。留空则会发布到 PyPI。 - **Install** — 使用者设置 `pip install --index-url`;这是 Diatreme 不会去配置的另一个 独立的问题。 私有上传目标的选项: - [pypiserver](https://github.com/pypiserver/pypiserver) — 极简方案;提供一个存放 wheel 的目录。 - [devpi](https://www.devpi.net/) — 具有 staging 和 PyPI 拉取镜像的私有 index。 - [Nexus](https://www.sonatype.com/products/sonatype-nexus-repository) / [Artifactory](https://jfrog.com/artifactory/) — 多格式的 artifact 管理器 (常见的企业级方案)。 - 托管云服务:AWS CodeArtifact、GCP Artifact Registry、Azure Artifacts、Cloudsmith、 Gemfury。 在企业环境中,pip 目标通常是组织*现有的*内部 index(Nexus / Artifactory / CodeArtifact),因为 GitHub Enterprise 也没有 Python registry。 对于托管的云服务,上传 token 通常是短期的 —— 请在前面的步骤中生成它,并将其作为 `package-token` 传入。例如 AWS CodeArtifact: ``` - name: CodeArtifact token id: ca run: | echo "token=$(aws codeartifact get-authorization-token \ --domain my-domain --query authorizationToken --output text)" >> "$GITHUB_OUTPUT" - uses: magmamoose/diatreme@v1 with: # …versioning inputs… publish-package: 'true' package-ecosystem: pip package-feed-url: https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/pypi/my-repo/ package-username: aws package-token: ${{ steps.ca.outputs.token }} ``` 通过 Trusted Publishing 发布到公共 PyPI(无需 `package-token`): ``` # Needs id-token: write on the job — granted by default `auth-mode: # public-app`; add it explicitly under `auth-mode: github-token`. permissions: id-token: write steps: - uses: magmamoose/diatreme@v1 with: # …versioning inputs… publish-package: 'true' package-ecosystem: pip pypi-trusted-publishing: 'true' # package-feed-url omitted → public PyPI; for TestPyPI set it to # https://test.pypi.org/legacy/ ``` ## Docker 镜像名称 `image_name` 是**可选的**。正如 Diatreme 会根据您的部署模型和 branch-map 推断发布环境一样,当您不传入该参数时,它会从您的 Docker Bake 配置中推断出镜像名称 —— 因此平台存储库不需要一个专门的前置步骤来计算它。 解析顺序: 1. **显式的 `image_name`** 始终优先,并按原样使用(与以前一样)。它 会为使用该变量的 bake 文件设置 `IMAGE_NAME=/`。 2. **从 Docker Bake 自动检测。** 当 `image_name` 为空且 存在 `bake_file` 时,Diatreme 会运行 `docker buildx bake -f --print`,获取**第一个非空的目标 tag**,并去除 digest、tag、registry 主机和 owner/org 前缀,仅保留基础名称: | 第一个 bake tag | 检测到的 `image_name` | | --- | --- | | `ghcr.io/platform1-systems/backend:latest` | `backend` | | `ghcr.io/platform1-systems/camera-probe-propagator:v1` | `camera-probe-propagator` | | `platform1-systems/admin-frontend:latest` | `admin-frontend` | 3. **没有 `image_name` 且没有 bake 文件** → 名称保持为空,并且会跳过镜像 相关步骤(CI 构建、镜像扫描、发布提升)。仅版本控制工作流不受影响。 如果 bake 文件存在但未生成**任何 tag**,这是一个严重的错误 —— Diatreme 绝不会悄悄退回到使用存储库名称;请修复 bake target 或显式传入 `image_name`。 检测结果的作用方式与显式传入值对于每个镜像路径完全相同,因此只要 `docker-bake.hcl` 具有带 tag 的目标,**`mode: ci` 镜像构建和 BBD 发布镜像提升无需传入 `image_name`** 即可正常工作: ``` steps: - uses: magmamoose/diatreme@v1 with: deployment-model: bbd branch-map: '{"staging": "staging", "main": "prod"}' # image_name omitted — detected from docker-bake.hcl tags. ``` Diatreme 使用的值会作为 `resolved-image-name` 输出公开。 **退出检测。** 如果某个存储库保留了带 tag 的 `docker-bake.hcl`,但仅将 Diatreme 用于 **版本控制**,请设置 `detect-image-name: false`,这样单纯的 `mode: ci` / `release` 运行就不会开始构建或提升镜像。关闭检测后, `image_name` 的行为将恢复原样 —— 为空时关闭镜像工作流;显式的 `image_name` 仍会开启它们。 对于具有不同镜像的多目标 bake **groups**,检测会解析出一个单一的基础名称(`bake --print` 发出的第一个目标)—— 这与单一 `IMAGE_NAME` 模型保持一致。它仅控制镜像步骤并设置 `IMAGE_NAME` bake 变量;扫描和提升步骤仍然会从 bake tag 中枚举每个 target,因此多镜像构建不会坍缩为一个。 ## 镜像扫描和 SBOM 在 `mode: ci` 中,当 `pr-` 镜像构建完成后,Diatreme 可以扫描 **组装好的**镜像并将结果路由到两个目的地。这是镜像 对世界的视角 —— 基础镜像包以及 Dockerfile 添加的任何内容 —— 而源代码依赖扫描是无法看到这些的。 - **CycloneDX SBOM → Dependency-Track.** 镜像的组件清单会 作为其自身独立的 Dependency-Track 项目上传(与同一存储库的任何源代码依赖 SBOM 项目区分开来)。Dependency-Track 会从 SBOM 中推导出组件 CVE,并在出现新的安全公告时重新检查它们。 - **Findings → DefectDojo** *(可选)*。导入 Trivy 报告是为了发现 SBOM 匹配可能遗漏的问题 —— 操作系统级别的 CVE、镜像配置错误以及固化在层中的敏感信息。 报告采用**可见性优先**原则:除非您使用 `image-scan-gate: true` 主动开启,否则成功的扫描绝不会阻塞 PR。完全无法运行的扫描器会被视为构建错误,而绝不会报告为“无发现”。这两个目的地都是 **故障隔离**的 —— Dependency-Track 或 DefectDojo 的故障只会记录警告,而不会导致构建失败。每个目的地仅当设置了其 URL 时才会激活。 被扫描的 `pr-` 镜像就是 `mode: release` 稍后通过 digest 提升的确切 artifact,因此在 PR 上扫描的内容就是最终发布的内容。 ``` name: CI on: pull_request: jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write pull-requests: read steps: - uses: magmamoose/diatreme@v1 with: mode: ci image_name: my-app image-scan: 'true' dependency-track-url: https://dtrack.example.com dependency-track-api-key: ${{ secrets.DEPENDENCY_TRACK_API_KEY }} # Optional findings feed: defectdojo-url: https://defectdojo.example.com defectdojo-api-key: ${{ secrets.DEFECTDOJO_API_KEY }} defectdojo-product-name: my-app # Stay non-blocking at first; flip on once the signal is trusted: # image-scan-gate: 'true' ``` ## 版本控制工具检测 `versioning-tool` 默认为 `auto`,它会根据 `working-directory` 中的标记检测工具。这使得一个共享的发布工作流可以服务于使用不同版本控制工具的存储库 —— 设置显式工具仅是为了覆盖检测结果。 检测分两个层级运行: **第一层级 — 工具自身的发布配置**(权威来源;每个标记精确映射到 一个工具): | 标记 | 解析为 | | --- | --- | | 包含 `[tool.semantic_release]` 表的 `pyproject.toml` | `semantic-release-python` | | `.releaserc*` / `release.config.*` | `semantic-release-npm` | | `GitVersion.yml` / `GitVersion.yaml` (或自定义的 `gitversion-config`) | `gitversion` | | `release-please-config.json` / `.release-please-manifest.json` (或自定义的 `release-please-config-file`) | `release-please` | 如果有两个或更多不同的第一层级工具匹配,说明该存储库存在冲突的 发布配置,运行会**报错** —— 显式设置 `versioning-tool` 以消除歧义。 **第二层级 — 生态系统清单**(仅当未找到第一层级配置时 才会查阅): | 标记 | 解析为 | | --- | --- | | `pyproject.toml` / `setup.py` / `setup.cfg` | `semantic-release-python` | | `package.json` | `semantic-release-npm` | | `*.csproj` / `*.sln` | `gitversion` | 当多个第二层级清单同时存在时,固定的优先级 (`semantic-release-python` → `semantic-release-npm` → `gitversion`)会打破 平局,因此同时包含 `package.json` 的 Python 服务仍然会解析为 `semantic-release-python`。如果根本没有任何匹配项,运行将**报错**并 显示完整的标记列表。 第二层级的匹配解析的是*工具*,而不是配置文件:仅包含 `.csproj` 的 存储库会使用 GitVersion 的内置默认值运行,并且不需要 `GitVersion.yml`。其他工具也是如此 —— 每个工具在其配置文件缺失时都会回退到各自的默认值。 ## 输入项 除非另有说明,所有输入项均为可选。默认值与 `action.yml` 中一致。 | 输入项 | 默认值 | 用途 | | --- | --- | --- | | `mode` | `release` | `ci`、`release` 或 `enable-auto-merge`。 | | `auth-mode` | `public-app` | token 来源:托管的公共 App、私有 App、工作流 token 或 auto。 | | `token-broker-url` | `https://api.diatreme.magmamoose.com` | 托管 broker 基础 URL 覆盖。 | | `oidc-audience` | `diatreme` | 用于公共 App 身份验证的 OIDC audience。 | | `versioning-tool` | `auto` | `auto`(从存储库标记检测 —— 参见[版本控制工具检测](#versioning-tool-detection))、`semantic-release-python`、`semantic-release-npm`、`gitversion` 或 `release-please`。 | | `deployment-model` | `tbd` | `tbd`、`bbd` 或 `tbd-pr`。 | | `branch-map` | `''` | 用于 BBD 的 JSON 分支到环境的映射。 | | `promote-branch-prefix` | `promote` | 用于 `tbd-pr` 提升 PR 的分支前缀。 | | `promote-target-branch` | `main` | 提升 PR 的目标分支。 | | `create-promotion-pr` | `false` | 在预发布后打开或刷新下一个环境的提升 PR。 | | `environment` | `''` | 目标环境,对于普通的 `tbd` 是必填项。 | | `environments` | `["dev", "staging", "prod"]` | 有序的环境列表;最后一个条目是稳定的生产环境。 | | `prerelease-identifiers` | `{"dev": "dev", "staging": "rc"}` | 环境到预发布后缀的映射。 | | `tag-prefix` | `v` | 版本 tag 前缀。 | | `github-token` | `''` | 覆盖用于 GHCR 登录和 github-token 身份验证模式的 token。 | | `app-id` | `''` | 私有 GitHub App ID。 | | `app-private-key` | `''` | 私有 GitHub App PEM。 | | `submodules` | `false` | 直接传递给 checkout:`false`、`true` 或 `recursive`。 | | `image_name` | `''` | 不含 registry 或 owner 的基础镜像名称。可选 —— 省略时会从 Docker Bake 配置(`bake_file`/`bake_target`)自动检测;显式传入的值优先。请参阅 [Docker 镜像名称](#docker-image-name)。 | | `bake_file` | `docker-bake.hcl` | Docker Bake 文件。 | | `bake_target` | `default` | Docker Bake 目标或组。 | | `detect-image-name` | `true` | 当为空时从 Docker Bake 配置自动检测 `image_name`。设置为 `false` 以禁用(适用于具有带 tag 的 bake 文件但仅需版本控制的存储库)。显式传入的 `image_name` 始终优先。 | | `registry` | `ghcr.io` | Container registry。 | | `registry-username` | `''` | 显式的 registry 登录用户名。 | | `registry-password` | `''` | 显式的 registry 登录密码或 token。 | | `platforms` | `''` (空) | 平台覆盖项,例如 `linux/amd64,linux/arm64`。留空则遵循存储库 `docker-bake.hcl` 的 `PLATFORMS` 默认设置(不会覆盖它)。 | | `build-github-token` | `''` | 用于私有包安装的 Docker Bake 密钥 `github_token`。 | | `image-scan` | `false` | 在 `mode: ci` 中扫描组装好的 `pr-` 镜像并输出 SBOM + findings。需主动开启。需要解析出镜像名称(显式的 `image_name` 或通过 bake 检测到的)。 | | `image-scan-severity` | `CRITICAL,HIGH` | 用于 findings 和门控的 Trivy 严重性过滤器。SBOM 仍会清点所有组件。 | | `image-scan-scanners` | `vuln,secret,misconfig` | 用于 findings 报告的 Trivy 扫描器。 | | `image-scan-gate` | `false` | 当存在达到或超过 `image-scan-severity` 的 findings 时使构建失败。默认为非阻塞。 | | `image-scan-strict` | `false` | 将 Dependency-Track / DefectDojo 目的地的故障视为致命错误。默认将目的地保持为故障隔离状态。 | | `dependency-track-url` | `''` | Dependency-Track 基础 URL。设置后,将上传镜像的 CycloneDX SBOM。故障为非。 | | `dependency-track-api-key` | `''` | 具有 BOM 上传权限的 Dependency-Track API key。 | | `dependency-track-project-name` | `''` | DT 项目名称。默认为镜像存储库路径加上 `(image)` 后缀(例如 `owner/app (image)`),与同一存储库的源代码 SBOM 项目区分开来。 | | `dependency-track-project-version` | `''` | DT 项目版本。默认为镜像 tag(例如 `pr-12`)。 | | `dependency-track-auto-create` | `true` | 首次上传时自动创建 DT 项目/版本(需要密钥具备 `PROJECT_CREATION_UPLOAD` 权限)。 | | `defectdojo-url` | `''` | DefectDojo 基础 URL。设置后,将导入 Trivy findings 报告。可选;故障为非阻塞。 | | `defectdojo-api-key` | `''` | DefectDojo API v2 token。 | | `defectdojo-engagement` | `''` | 要导入到的 DefectDojo engagement ID。或者设置 `defectdojo-product-name` 以用于自动创建的上下文。如果两者均未设置(但设置了 URL),导入将被跳过并发出警告。 | | `defectdojo-product-name` | `''` | 用于自动创建上下文导入路径的 DefectDojo 产品名称。 | | `defectdojo-product-type` | `''` | 用于自动创建上下文路径的 DefectDojo 产品类型。 | | `defectdojo-engagement-name` | `''` | 用于自动创建上下文的 DefectDojo engagement 名称。默认为 `Diatreme image scan`。 | | `defectdojo-close-old` | `true` | 在重新导入时关闭不再存在的 findings(Diatreme 通过 `reimport-scan` 导入)。 | | `publish-package` | `false` | 版本控制后将语言包打包并推送到 `package-feed-url`。需主动开启。 | | `package-ecosystem` | `''` | `nuget`、`npm`、`maven`、`gradle`、`rubygems`、`container` 或 `pip`。当 `publish-package` 为 true 时必填。 | | `package-path` | `''` | 要打包/构建/发布的项目/路径。默认为 `working-directory`。 | | `package-feed-url` | `''` | Feed/registry URL。留空 → 按生态系统指向存储库的 GitHub Packages feed(container 为 `ghcr.io`;npm/pip 为公共 registry)。 | | `package-token` | `''` | Feed 身份验证 token。默认为工作流的 `GITHUB_TOKEN` (GitHub Packages)。 | | `package-username` | `''` | 登录用户名。默认为 `__token__` (pip) / `x-access-token` (maven、gradle、rubygems、container)。被 nuget/npm 忽略。 | | `dotnet-version` | `8.0.x` | 用于 `package-ecosystem: nuget` 的 .NET SDK 版本。 | | `python-version` | `3.x` | 用于 `package-ecosystem: pip` 的 Python 版本。 | | `node-version` | `20` | 用于 `package-ecosystem: npm` 的 Node.js 版本。 | | `java-version` | `17` | 用于 `package-ecosystem: maven`/`gradle` 的 JDK 版本。 | | `java-distribution` | `temurin` | 用于 `maven`/`gradle` 的 JDK 发行版 (setup-java)。 | | `ruby-version` | `3.3` | 用于 `package-ecosystem: rubygems` 的 Ruby 版本。 | | `package-name` | `''` | 用于 `package-ecosystem: container` 的镜像名称。默认为 `/`。 | | `npm-provenance` | `false` | 使用 `npm publish --provenance` 发布到 npmjs。仅限 npmjs;需要 `id-token: write`。 | | `pypi-trusted-publishing` | `false` | 通过 GitHub OIDC 上传到公共 PyPI/TestPyPI,而不是使用 `package-token`。需要 `id-token: write`。 | | `enforce_branch_naming` | `true` | 在 `mode: ci` 中强制执行 TBD PR 分支命名。允许的前缀:`feat`、`fix`、`chore`、`hotfix`、`docs`、`refactor`、`perf`、`test`、`ci`、`style`、`build`、`revert`、`deploy`、`release`(以及提升前缀)。 | | `extra-branch-prefixes` | `''` | 除了内置集合之外还可接受的额外分支前缀(以逗号/空格/竖线分隔),例如 `spike wip`。仅限字母、数字、`_` 和 `-`;其他任何字符都将被拒绝。 | | `aggregate-github-projects` | `false` | 将关联的 Projects v2 条目附加到发布文档中。 | | `move-github-projects-on-release` | `false` | 在发布后移动关联的 Projects v2 条目。 | | `github-projects-target-status` | `Released` | 目标 Projects v2 状态。 | | `github-projects-move-on-environments` | `@last` | 运行 Projects 移动的环境。 | | `admin-required-from` | `@last` | 手动生产环境发布需要存储库管理员权限的环境。 | | `working-directory` | `.` | 运行版本控制的存储库子目录。 | | `create-release` | `true` | 当后端支持时创建 GitHub Release。 | | `changelog` | `true` | 允许支持的后端更新 changelog。 | | `force-bump` | `''` | 强制指定提升级别(`patch`/`minor`/`major`),而不是从提交中推导(适用于 semantic-release-python、semantic-release-npm、gitversion;被 release-please 忽略)。 | | `version-override` | `''` | 创建此确切版本,而不是推导版本。 | | `version-file` | `''` | 需要使用发布的版本进行更新的受跟踪文件。 | | `version-file-json-path` | `.Application.Version` | 用于注入 version-file 的 JSON 路径。 | | `version-file-yaml-path` | `.appVersion` | 用于注入 version-file 的 YAML 路径。 | | `aggregate-clickup-tickets` | `false` | 将发布范围内的 ClickUp 工单链接追加到文档中。 | | `gitversion-spec` | `6.x` | GitVersion action 版本规范。 | | `gitversion-config` | `''` | GitVersion 配置文件。留空可让 GitVersion 自动识别根目录的 `GitVersion.yml`/`GitVersion.yaml`,或者在两者都不存在时按其内置默认值运行。 | | `gitversion-appsettings-file` | `''` | 已弃用;请使用 `version-file`。 | | `gitversion-appsettings-version-path` | `''` | 已弃用;请使用 `version-file-json-path`。 | | `release-please-release-type` | `simple` | release-please 发布类型。 | | `release-please-config-file` | `release-please-config.json` | release-please 配置文件。 | | `pr-number` | `''` | 用于 `mode: enable-auto-merge` 的 PR 编号。 | | `auto-merge-method` | `squash` | 自动合并方法:`squash`、`merge` 或 `rebase`。 | ## 输出项 | 输出项 | 描述 | | --- | --- | | `version` | 不带前缀的 Semver 版本字符串,例如 `1.2.3` 或 `1.2.3-rc.1`。 | | `tag` | 带有前缀的完整 git tag,例如 `v1.2.3`。 | | `is-prerelease` | 当此环境生成预发布时为 `true`。 | | `released` | 当新版本已创建并发布时为 `true`。 | | `prerelease-identifier` | 预发布标识符,对于生产环境则为空。 | | `resolved-environment` | 解析出的环境名称。 | | `package-published` | 当语言包已打包并推送到配置的 feed 时为 `true`。 | | `image-scanned` | 当组装好的 `pr-` 镜像已被扫描时为 `true`(`mode: ci` 且开启 `image-scan`)。 | | `image-findings` | 在所有扫描的镜像中,达到或超过 `image-scan-severity` 的镜像扫描 findings 数量。 | | `resolved-image-name` | 用于镜像工作流的基础镜像名称 —— 显式传入的 `image_name`,或从 Docker Bake 自动检测到的值。在仅进行版本控制的运行中为空。 | ## Diatreme Worker [`worker/`](worker) 目录是 Cloudflare Worker —— 即位于 `https://api.diatreme.magmamoose.com` 的托管 broker 背后的 GitHub App 后端。Action 默认的 `auth-mode: public-app` 会调用它,因此您永远不必注册和运行自己的 GitHub App。您也可以自托管它,并通过 `token-broker-url` 输入项将 Action 指向您自己的部署。 | Endpoint | 用途 | | --- | --- | | `POST /token` | 将 GitHub Actions OIDC token 交换为短期的 App installation token。 | | `POST /sign` | 通过 `createCommitOnBranch` 创建由 GitHub 签名的、**由 App/bot 身份标识的**发布提交(版本提升 / tag)。 | | `GET /releases` | 聚合的发布历史(用于仪表板)。 | 使用 [Wrangler](https://developers.cloudflare.com/workers/wrangler/) 进行开发和部署: ``` cd worker npm install npm run check # typecheck + tests + wrangler dry-run deploy npm test # vitest only wrangler dev # run locally wrangler deploy # ship to Cloudflare ``` 配置(secrets 和 vars)记录在 [`worker/README.md`](worker/README.md) 和 [`worker/.dev.vars.example`](worker/.dev.vars.example) 中。此 worker 的内部可观测性仪表板是独立的 [`MagmaMoose/diatreme-pro`](https://github.com/MagmaMoose/diatreme-pro) 存储库。 ## 发行说明 使用不可变的 tag 或 SHA 以实现严格的可重现性。`@v1` 是此存储库在每次稳定发布后更新的浮动主版本 tag。根目录的发布工作流会进行“吃自己的狗粮”(内部测试),使用 `uses: ./`,然后在 semantic-release 发布稳定版本后强制更新匹配的主版本 tag。 Docker 提升首选使用 `docker buildx imagetools create`,以便保留多架构 manifest。对于已知的 GitHub Enterprise Packages referrers-index 解析错误,Diatreme 会针对单架构镜像回退到 pull/tag/push,如果重新打标签不起作用,则会回退到全新的 Docker Bake 构建。 在提升 `pr-` 镜像之前,Diatreme 会验证它确实是由正在发布的代码构建而成的。`mode: ci` 会为每个镜像加盖 `org.opencontainers.image.revision`(构建提交)和 `com.magmamoose.diatreme.git-tree`(该提交的 git tree)标记 —— 这些是在构建时注入的,因此无需更改 bake 文件。`mode: release` 会将镜像的 tree 与发布提交的 tree 进行比较;如果某个 PR 在落后于分支尖端时被合并,比较将会失败(其 CI 镜像已过时),发布过程将根据发布时的 checkout 重新构建,而不是在新 tag 下提升旧代码。无法验证的镜像 —— 包括由不支持 provenance 的旧版 Diatreme 构建的镜像 —— 也会走全新构建的路径。后续环境的提升(例如 `v1.2.3-rc.1` → `v1.2.3`)可豁免:将前一环境的 artifact 原封不动地保留下来正是它们的目的。 一款 Magma Moose 产品。
标签:程序员工具, 请求拦截