跳到主要内容

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

您可以从以下位置自动化发布:

以下各节介绍如何配置自动发布,以及如何根据您的偏好自定义发布流程。

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

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

使用 GitHub Actions 发布软件包

#

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

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

    • GitHub 仓库和
    • 必须匹配才能允许发布的标签模式
  • 创建用于发布到 pub.dev 的 GitHub Actions 工作流程

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

以下各节概述了如何完成这些步骤。

在 pub.dev 上配置来自 GitHub Actions 的自动发布

#

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

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

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

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

  2. 找到自动发布部分。

  3. 点击启用从 GitHub Actions 发布,这将提示您指定:

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

仓库是 GitHub 上的 <organization>/<repository>。例如,如果您的仓库是 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 的工作流程日志。

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

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

Audit log after publishing from GitHub Actions

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

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

#

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

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

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

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

#

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

  1. 导航到管理选项卡 (pub.dev/packages/<package>/admin)。
  2. 找到自动发布部分。
  3. 点击需要 GitHub Actions 环境
  4. 指定环境名称,(pub.dev 通常是一个不错的名称)

Configure pub.dev to require a GitHub deployment environment

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

  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. 导航到管理选项卡 (pub.dev/packages/<package>/admin)。 a. 点击使用 Google Cloud Service account 启用发布。 a. 在服务帐户电子邮件字段中键入服务帐户的电子邮件。您在上一步中创建了这个帐户: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:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
      --role=roles/iam.serviceAccountTokenCreator

编写 Cloud Build 配置文件

#

要从 Cloud Build 发布,您必须为 Cloud Build 指定以下步骤:

  • 模拟服务帐户以获取临时 OIDC 令牌。
  • 将临时 OIDC 令牌提供给 dart pub 以供发布时使用。
  • 调用 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 触发器类型配置为“Cloud Build Configuration”,该类型位于仓库的 /cloudbuild.yaml 文件中。不要为要触发的构建指定服务帐户。相反,您需要使用 Cloud Build 的默认服务帐户。

Configuration for trigger

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

使用 Cloud Build 审批加强安全性

#

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

Enabling approvals in configuration of the Cloud Build trigger

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

Cloud Build run waiting for approval to run

您还可以为待处理的审批配置通知。要了解更多信息,请查看gate build on approval

使用服务帐户从任何位置发布

#

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

这通常涉及:

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

使用工作负载身份联合发布

#

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

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

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

#

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

导出服务帐户密钥

#
  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