目录

自动将软件包发布到 pub.dev

您可以自动发布来自

以下部分说明如何配置自动发布,以及如何根据您的偏好自定义发布流程。

配置自动发布时,您无需创建复制到自动部署环境中的长期密钥。相反,身份验证依赖于由 GitHub Actions(请参阅 GitHub Actions 的 OIDC)或 Google Cloud IAM 签名的临时 OpenID Connect 令牌。

您可以为不存在身份服务的部署环境使用导出的服务帐号密钥。此类导出的服务帐号密钥是长期密钥,在某些环境中可能更容易使用,但如果意外泄露也会带来更大的风险。

使用 GitHub Actions 发布软件包

#

您可以使用 GitHub Actions 配置自动发布。这包括

  • 在 pub.dev 上启用自动发布,指定

    • GitHub 存储库,以及
    • 必须匹配才能允许发布的标签模式
  • 创建用于发布到 pub.dev 的 GitHub Actions 工作流

  • 推送要发布的版本的 git 标签

以下部分概述如何完成这些步骤。

配置从 GitHub Actions 自动发布到 pub.dev

#

要启用从 GitHub Actions 到 pub.dev 的自动发布,您必须是

  • 软件包上的上传者,或
  • 发布者的管理员(如果软件包由发布者拥有)。

如果您具有足够的权限,则可以通过以下方式启用自动发布

  1. 导航到“管理”选项卡(pub.dev/packages/<package>/admin)。

  2. 找到“自动发布”部分。

  3. 单击“启用从 GitHub Actions 发布”,这将提示您指定

    • 存储库(<组织>/<存储库>,例如:dart-lang/pana),
    • 标签模式(包含 {{version}} 的字符串)。

存储库是 GitHub 上的 <组织>/<存储库>。例如,如果您的存储库是 https://github.com/dart-lang/pana,则必须在存储库字段中指定 dart-lang/pana

标签模式是一个必须包含 {{version}} 的字符串。只有由与此标签模式匹配的标签推送触发的 GitHub Actions 才允许发布您的软件包。

Configuration of publishing from GitHub Actions on pub.dev

示例:v{{version}} 这样的标签模式允许 GitHub Actions(由 git tag v1.2.3 && git push v1.2.3 触发)发布您软件包的版本 1.2.3。因此,pubspec.yaml 中的 version 键也必须与此版本号匹配。

如果您的存储库包含多个软件包,请为每个软件包提供单独的标签模式。考虑对名为 my_package_name 的软件包使用类似 my_package_name-v{{version}}标签模式

配置用于发布到 pub.dev 的 GitHub Action 工作流

#

在 pub.dev 上启用从 GitHub Actions 自动发布后,您可以创建一个用于发布的 GitHub Actions 工作流。这是通过创建如下的 .github/workflows/publish.yml 文件来完成的

yaml
# .github/workflows/publish.yml
name: Publish to pub.dev

on:
  push:
    tags:
    # must align with the tag-pattern configured on pub.dev, often just replace
      # {{version}} with [0-9]+.[0-9]+.[0-9]+
    - 'v[0-9]+.[0-9]+.[0-9]+' # tag-pattern on pub.dev: 'v{{version}}'
    # If you prefer tags like '1.2.3', without the 'v' prefix, then use:
    # - '[0-9]+.[0-9]+.[0-9]+' # tag-pattern on pub.dev: '{{version}}'
    # If your repository contains multiple packages consider a pattern like:
    # - 'my_package_name-v[0-9]+.[0-9]+.[0-9]+'

# Publish using the reusable workflow from dart-lang.
jobs:
  publish:
    permissions:
      id-token: write # Required for authentication using OIDC
    uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1
    # with:
    #   working-directory: path/to/package/within/repository

确保 on.push.tags 中的模式与 pub.dev 上指定的标签模式匹配。否则,GitHub Action 工作流将无法工作。如果从同一存储库发布多个软件包,请使用每个软件包的标签模式(如 my_package_name-v{{version}}),并为每个软件包创建一个单独的工作流文件。

上面的工作流文件使用 dart-lang/setup-dart/.github/workflows/publish.yml 来发布软件包。这是一个可重用的工作流,它允许 Dart 团队维护发布逻辑,并使 pub.dev 知道软件包是如何发布的。强烈建议使用此可重用的工作流

如果您的软件包中需要生成的代码,则最好将此生成的代码检入到您的存储库中。这简化了验证 pub.dev 上发布的文件是否与您存储库中的文件匹配。如果将生成或构建的工件检入到您的存储库中是不合理的,您可以创建一个类似于以下的自定义工作流

yaml
# .github/workflows/publish.yml
name: Publish to pub.dev

on:
  push:
    tags:
    - 'v[0-9]+.[0-9]+.[0-9]+' # tag pattern on pub.dev: 'v{{version}'

# Publish using custom workflow
jobs:
  publish:
    permissions:
      id-token: write # Required for authentication using OIDC
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: dart-lang/setup-dart@v1
      - name: Install dependencies
        run: dart pub get
      # Here you can insert custom steps you need
      # - run: dart tool/generate-code.dart
      - name: Publish
        run: dart pub publish --force

该工作流使用临时的 GitHub 签名的 OIDC 令牌pub.dev 进行身份验证,该令牌是在 dart-lang/setup-dart 步骤中创建和配置的。要发布到 pub.dev,后续步骤可以运行 dart pub publish --force

从 GitHub Actions 触发自动发布

#

pub.dev 上配置自动发布并创建 GitHub Actions 工作流后,您可以发布软件包的新版本。要发布,请推送与配置的标签模式匹配的 git 标签

$ cat pubspec.yaml
yaml
package: my_package_name
version: 1.2.3            # must match the version number used in the git tag
environment:
  sdk: ^2.19.0
$ git tag v1.2.3          # assuming my tag pattern is: 'v{{version}}'
$ git push origin v1.2.3  # triggers the action that publishes my package.

推送后,请在 https://github.com/<organization>/<repository>/actions 上查看工作流日志。

如果操作未触发,请检查在 .github/workflows/publish.yml 中配置的模式是否与推送的 git 标签匹配。如果操作失败,日志可能会包含失败原因的线索。

发布后,您可以在 pub.dev 上的 audit-log 中看到发布事件。 audit-log 条目应包含指向发布软件包版本的 GitHub Action 运行的链接。

Audit log after publishing from GitHub Actions

如果您不喜欢使用 git CLI 创建标签,您可以在 GitHub 上从 https://github.com/<组织>/<仓库>/releases/new 创建发布版本。要了解更多信息,请查看 GitHub 上的 在仓库中管理发布版本

使用 GitHub 上的标签保护规则加强安全性

#

从 GitHub Actions 配置自动发布允许任何可以向您的仓库推送标签的人触发向 pub.dev 的发布。您可以使用 GitHub 上的 标签保护规则 来限制谁可以向您的仓库推送标签。

通过限制谁可以创建与您的标签模式匹配的标签,您可以限制谁可以发布软件包。

目前,标签保护规则缺乏灵活性。您可能希望使用 GitHub 部署环境来限制谁可以触发发布,如下一节所述。

使用 GitHub 部署环境加强安全性

#

在 pub.dev 上从 GitHub Actions 配置自动发布时,您可以要求一个 GitHub Actions 环境。要为发布要求一个GitHub Actions 环境,您必须

  1. 导航到 Admin 选项卡 (pub.dev/packages/<package>/admin)。
  2. 找到“自动发布”部分。
  3. 点击 Require GitHub Actions environment
  4. 指定一个 Environment 名称,(pub.dev 通常是一个不错的名称)

Configure pub.dev to require a GitHub deployment environment

当 pub.dev 上需要一个环境时,除非它们有 environment: pub.dev,否则 GitHub Actions 将无法发布。因此,您必须

  1. 在 GitHub 上创建一个具有相同名称的环境(通常为 pub.dev
  2. 修改您的 .github/workflows/publish.yml 工作流程文件以指定 environment: pub.dev,如下所示
yaml
# .github/workflows/publish.yml
name: Publish to pub.dev

on:
  push:
    tags:
    - 'v[0-9]+.[0-9]+.[0-9]+' # for tags like: 'v1.2.3'

jobs:
  publish:
    permissions:
      id-token: write # Required for authentication using OIDC
    uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1
    with:
      # Specify the github actions deployment environment
      environment: pub.dev
      # working-directory: path/to/package/within/repository

环境反映在用于与 pub.dev 进行身份验证的临时 GitHub 签名的 OIDC 令牌中。因此,有权推送到您的仓库的用户无法通过修改工作流程文件来规避 环境保护规则

在 GitHub 仓库设置中,您可以使用 环境保护规则来配置必需的审阅者。如果您配置此选项,GitHub 将阻止具有该环境的操作运行,直到其中一个必需的审阅者批准该运行为止。

GitHub Action waiting for deployment review

从 Google Cloud Build 发布

#

您可以从 Google Cloud Build 配置自动发布。这包括

  • 注册一个 Google Cloud 项目(或使用现有项目),
  • 为发布到 pub.dev 创建一个 服务帐户
  • 在 pub.dev 上软件包的管理选项卡中启用自动发布,指定为发布创建的服务帐户的电子邮件。
  • 授予默认的 Cloud Build 服务帐户模拟为发布创建的服务帐户的权限。
  • 创建一个 cloudbuild.yaml 文件,该文件获取一个临时的 OIDC id_token 并将其用于发布到 pub.dev
  • 配置一个 Cloud Build 触发器,用于在 Google Cloud Build 上在您的项目中运行 cloudbuild.yaml 中的步骤。

以下部分概述如何完成这些步骤。

创建用于发布的 Service Account

#

对于发布到 pub.dev,您将创建一个被授予在 pub.dev 上发布您的软件包权限的服务帐户。然后,您将授予 Cloud Build 模拟此服务帐户的权限。

  1. 如果您没有现有项目,创建一个云项目

  2. 创建一个服务帐户,如下所示

    $ gcloud iam service-accounts create pub-dev \
      --description='Service account to be impersonated when publishing to pub.dev' \
      --display-name='pub-dev'

    这将创建一个名为 pub-dev@$PROJECT_ID.iam.gserviceaccount.com 的服务帐户。

  3. 授予服务帐户发布您的软件包的权限。

    要完成此步骤,您必须拥有软件包的上传者权限,或者是拥有该软件包的发布者的管理员

    a. 导航到 Admin 选项卡 (pub.dev/packages/<package>/admin)。 a. 点击 Enable publishing with Google Cloud Service account。 a. 在 Service account email 字段中输入服务帐户的电子邮件。您在上一步中创建了这个帐户:pub-dev@$PROJECT_ID.iam.gserviceaccount.com

Configuration that allows service account to publish on pub.dev

完成此过程后,任何可以模拟服务帐户的人都可以发布软件包的新版本。请务必查看谁有权模拟服务帐户,并根据需要在云项目中更改权限。

授予 Cloud Build 发布权限

#

要从 Cloud Build 发布,您必须授予 默认的 Cloud Build 服务帐户模拟上一节中创建的用于发布的服务帐户的权限。

  1. 在云项目中启用 IAM Service Account Credentials API。如果没有此 API,尝试模拟服务帐户将失败。

    # Enable IAM Service Account Credentials API
    $ gcloud services enable iamcredentials.googleapis.com
  2. 找到项目编号。

    # The PROJECT_NUMBER can be obtained as follows:
    $ gcloud projects describe $PROJECT_ID --format='value(projectNumber)'
  3. 授予模拟发布服务帐户的权限。

    # Grant default cloud
    $ gcloud iam service-accounts add-iam-policy-binding \
      pub-dev@$PROJECT_ID.iam.gserviceaccount.com \
      --member=serviceAccount:[email protected] \
      --role=roles/iam.serviceAccountTokenCreator

编写 Cloud Build 配置文件

#

要从 Cloud Build 发布,您必须指定 Cloud Build 的步骤

  • 模拟服务帐户以获取临时的 OIDC 令牌。
  • dart pub 提供临时的 OIDC 令牌,以便在发布时使用。
  • 调用 dart pub publish 来发布软件包。

Google Cloud Build 的步骤在 cloudbuild.yaml 文件中提供,有关格式的完整文档,请参阅 构建配置文件架构

对于从 Google Cloud Build 发布到 pub.dev,如下所示的 cloudbuild.yaml 文件可以做到

yaml
# cloudbuild.yaml
steps:
- id: Create temporary token
  name: gcr.io/cloud-builders/gcloud
  volumes:
  - name: temporary-secrets
    path: /secrets
  script: |
    gcloud auth print-identity-token \
      --impersonate-service-account=pub-dev@$PROJECT_ID.iam.gserviceaccount.com \
      --audiences=https://pub.dev \
      --include-email > /secrets/temporary-pub-token.txt
  env:
  - PROJECT_ID=$PROJECT_ID
- id: Publish to pub.dev
  name: dart
  volumes:
  - name: temporary-secrets
    path: /secrets
  script: | 
    cat /secrets/temporary-pub-token.txt | dart pub token add https://pub.dev
    dart pub publish --force

gcloud auth print-identity-token 创建一个模拟指定服务帐户的 OIDC id_token。此 id_token 由 Google 签名,签名在 1 小时内过期。audiences 参数让 pub.dev 知道它是令牌的预期接收者。--include-email 选项对于 pub.dev 识别服务帐户是必需的。

创建 id_token 后,它将被写入驻留在中的文件;此机制用于 在步骤之间传递数据。不要将令牌存储在 /workspace 中。由于 /workspace 是检出您要发布的仓库的位置。不使用 /workspace 存储令牌会降低在发布时意外将其包含在软件包中的风险。

创建 Cloud Build 触发器

#

配置服务帐户并在仓库中配置 cloudbuild.yaml 文件后,您可以使用 console.cloud.google.com 仪表板创建 Cloud Build 触发器。要创建构建触发器,您需要连接到源仓库并指定哪些事件应触发构建。您可以使用 GitHubCloud Source Repository其他选项之一。要了解如何配置Cloud Build 触发器,请查看 创建和管理构建触发器

要使用上一步中的 cloudbuild.yaml,请将Cloud Build 触发器类型配置为位于 /cloudbuild.yaml 文件中仓库中的“Cloud Build Configuration”。不要为要触发的构建指定服务帐户。相反,您应该使用 Cloud Build 的默认服务帐户。

Configuration for trigger

在配置 Cloud Build 触发器时,请考虑谁可以触发构建。因为触发构建可能会发布软件包的新版本。请考虑仅允许手动构建或使用 Cloud Build 审批来控制构建,如下一节所述。

使用 Cloud Build Approvals 加强安全性

#

在配置 Cloud Build 触发器时,您可以选择 require approval before build executes。如果 Cloud Build 触发器需要审批,则在触发时不会运行。相反,它将等待批准。这可用于限制谁可以发布软件包的新版本。

Enabling approvals in configuration of the Cloud Build trigger

只有具有 Cloud Build Approver 角色的用户才能给出批准。在给出批准时,批准者可以指定 URL 和评论。

Cloud Build run waiting for approval to run

您还可以配置待批准通知。要了解更多信息,请查看 通过批准控制构建

使用 Service Account 从任何位置发布

#

要允许在 GitHub Actions 之外进行自动发布,您可以使用类似于 Cloud Build 的方式使用服务帐户进行身份验证。

这通常包括

Cloud Build 部分概述了如何 创建一个用于发布的服务帐户。这应该提供一个服务帐户,例如 pub-dev@$PROJECT_ID.iam.gserviceaccount.com

使用 Workload Identity Federation 发布

#

在支持 OIDC 或 SAML 的云服务上运行时,您可以使用 工作负载身份联合来模拟 GCP 服务帐户。这使您能够利用云提供商的身份服务。

例如,如果部署在 EC2 上,您可以配置与 AWS 的工作负载身份联合,允许来自 EC2 元数据服务的临时 AWS 令牌模拟服务帐户。要了解如何配置这些流程,请查看工作负载身份联合

使用导出的 Service Account 密钥发布

#

在没有身份服务的自定义系统上运行时,您可以导出服务帐户密钥。导出的服务帐户密钥允许您以该服务帐户的身份进行身份验证。要了解更多信息,请查看如何创建和管理服务帐户密钥

导出服务帐户密钥

#
  1. 为现有的服务帐户创建导出的服务帐户密钥。

    $ gcloud iam service-accounts keys create key-file.json \
      --iam-account=pub-dev@$PROJECT_ID.iam.gserviceaccount.com
  2. 保存 key-file.json 文件以供后续使用。

使用导出的服务帐户密钥发布软件包

#

要使用导出的服务帐户密钥发布软件包

  1. 设置 gcloud 使用 key-file.json 进行身份验证(在上一步中创建)。

    $ gcloud auth activate-service-account --key-file=key-file.json
  2. 为 pub.dev 创建一个临时令牌,并将其传递给 dart pub token add https://pub.dev。要模拟服务帐户,请包含 --include-email 选项。

    $ gcloud auth print-identity-token \
      --audiences=https://pub.dev \
      | dart pub token add https://pub.dev
  3. 使用临时令牌发布。添加 --force 选项以跳过 yes/no 提示。

    $ dart pub publish --force