跳至主内容

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

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

以下章节解释了如何配置自动化发布,以及如何根据你的偏好定制发布流程。

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

对于没有身份服务的部署环境,你可以使用导出的 Service Account 密钥。这类导出的 Service Account 密钥是长期存在的密钥,在某些环境中可能更容易使用,但也存在意外泄露的更大风险。

使用 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.yamlversion 键的值与此版本号匹配也很重要。

如果你的仓库包含多个软件包,则为每个软件包指定一个单独的标签模式。对于名为 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.devaudit-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 令牌中。因此,具有向仓库 push 权限的用户无法通过修改工作流文件来绕过环境保护规则

在 GitHub 仓库设置中,你可以使用环境保护规则来配置必需的评审者。如果你配置此选项,GitHub 会阻止使用该环境的 action 运行,直到其中一个必需的评审者批准运行。

GitHub Action waiting for deployment review

通过 Google Cloud Build 发布

#

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

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

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

创建用于发布的 Service Account

#

要发布到 pub.dev,你将创建一个被授予在 pub.dev 上发布你的软件包权限的Service Account。然后,你将授予 Cloud Build 模拟此 Service Account 的权限。

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

  2. 创建Service Account 如下:

    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 的 Service Account。

  3. 授予该 Service Account 发布你的软件包的权限。

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

    a. 导航到管理选项卡 (pub.dev/packages/<package>/admin)。 a. 点击使用 Google Cloud Service account 启用发布。 a. 在Service account 电子邮件字段中输入 Service Account 的电子邮件。你在上一步中创建了此帐户:pub-dev@$PROJECT_ID.iam.gserviceaccount.com

Configuration that allows service account to publish on pub.dev

完成此流程后,任何能够模拟此 Service Account 的人都可以发布软件包的新版本。务必审查谁拥有模拟 Service Account 的权限,并根据需要更改云项目中的权限。

授予 Cloud Build 发布权限

#

要从 Cloud Build 发布,你必须授予默认的 Cloud Build Service Account 模拟上一节中为发布创建的 Service Account 的权限。

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

    # 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. 授予模拟发布 Service Account 的权限。

    # 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 指定以下步骤:

  • 模拟 Service Account 以获取临时 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,用于模拟指定的 Service Account。此 id_token 由 Google 签名,签名在 1 小时内过期。audiences 参数让 pub.dev 知道它是此令牌的预期接收者。--include-email 选项对于 pub.dev 识别 Service Account 是必需的。

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

创建 Cloud Build 触发器

#

配置好 Service Account 并在仓库中有了 cloudbuild.yaml 文件后,你可以使用 console.cloud.google.com 控制台创建Cloud Build 触发器。要创建构建触发器,你需要连接到源代码仓库并指定哪些事件应触发构建。你可以使用GitHubCloud Source Repository其他选项之一。要了解如何配置Cloud Build 触发器,请查看创建和管理构建触发器

要使用上一步中的 cloudbuild.yaml,请将Cloud Build 触发器类型配置为“Cloud Build 配置”,其位于仓库中的 /cloudbuild.yaml 文件。不要为触发构建指定一个Service Account。相反,你将使用 Cloud Build 的默认 Service Account。

Configuration for trigger

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

使用 Cloud Build 审批增强安全性

#

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

Enabling approvals in configuration of the Cloud Build trigger

只有拥有Cloud Build 审批者角色的用户才能进行审批。进行审批时,审批者可以指定 URL 和评论。

Cloud Build run waiting for approval to run

你还可以配置待处理审批的通知。要了解更多信息,请查看门控构建上的审批

使用 Service Account 从任何位置发布

#

要在 GitHub Actions 之外实现自动化发布,你可以使用 Service Account 进行认证,方式类似于Cloud Build

这通常包括:

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

使用 Workload Identity Federation 发布

#

当在支持 OIDC 或 SAML 的云服务上运行时,你可以使用Workload Identity Federation 模拟 GCP Service Account。这使你能够利用云提供商的身份服务。

例如,如果在 EC2 上部署,你可以配置与 AWS 的 Workload Identity Federation,允许 EC2 元数据服务提供的临时 AWS 令牌模拟 Service Account。要了解如何配置这些流程,请查看Workload Identity Federation

使用导出的 Service Account 密钥发布

#

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

导出 Service Account 密钥

#
  1. 为现有 Service Account 创建导出的 Service Account 密钥。

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

使用导出的 Service Account 密钥发布软件包

#

要使用导出的 Service Account 密钥发布软件包,请执行以下步骤:

  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。要模拟 Service Account,请包含 --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