Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/publish-mirror.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ on:
plan:
required: true
type: string
signed-archives:
description: "Artifact ID for the verified native archives and checksums"
required: true
type: string

permissions: {}

Expand All @@ -29,6 +33,12 @@ jobs:
pattern: artifacts-*
path: artifacts
merge-multiple: true
- name: "Use signed native release archives"
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ inputs.signed-archives }}
path: artifacts
merge-multiple: true
- name: "Upload to R2"
env:
AWS_ACCESS_KEY_ID: ${{ secrets.MIRROR_R2_ACCESS_KEY_ID }}
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ on:
plan:
required: true
type: string
artifacts:
description: "Artifact ID for the complete verified PyPI distributions"
required: true
type: string

env:
ACTIONS_CACHE_MODE: none
Expand All @@ -33,7 +37,7 @@ jobs:
enable-cache: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: wheels-*
artifact-ids: ${{ inputs.artifacts }}
path: wheels
merge-multiple: true
- name: Publish to PyPi
Expand Down
54 changes: 50 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,14 @@ jobs:
release-gate:
# N.B. This name should not change, it is used for downstream checks.
name: release-gate
if: ${{ github.event_name == 'workflow_dispatch' && inputs.tag != 'dry-run' }}
if: ${{ github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' }}
runs-on: ${{ github.repository == 'astral-sh/ty' && 'github-ubuntu-24.04-x86_64-4' || 'ubuntu-latest' }}
# This environment requires a 2-factor approval, i.e., the workflow must be approved by another
# team member. GitHub fires approval events on every job that deploys to an environment, so we
# have a dedicated environment for this purpose instead of using the `release` environment.
# We use a GitHub App with a deployment protection rule webhook to ensure that the `release`
# environment is only approved when the `release-gate` job succeeds.
# environment is only approved when the `release-gate` job succeeds. Dry-runs also require
# approval because they use the real signing keys.
environment:
name: release-gate
deployment: true
Expand Down Expand Up @@ -149,10 +150,24 @@ jobs:
"id-token": "write"
"packages": "write"

# Signing is a manually maintained stage between binary builds and cargo-dist manifests.
sign-release-binaries:
needs:
- plan
- release-gate
- custom-build-binaries
if: ${{ always() && github.repository == 'astral-sh/ty' && github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' && needs.plan.result == 'success' && needs.custom-build-binaries.result == 'success' && needs.release-gate.result == 'success' }}
uses: ./.github/workflows/sign-release-binaries.yml
secrets: inherit # zizmor: ignore[secrets-inherit]
permissions:
contents: read
id-token: write

# The custom binary jobs produce checksum sidecars outside cargo-dist.
# Include them in a local manifest before generating the installers.
generate-checksum-manifest:
needs:
- sign-release-binaries
- plan
- custom-build-binaries
if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' || inputs.tag == 'dry-run' }}
Expand Down Expand Up @@ -183,6 +198,12 @@ jobs:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- name: "Use signed native release archives"
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ needs.sign-release-binaries.outputs.github-archives }}
path: target/distrib/
merge-multiple: true
- name: Generate local dist manifest
shell: bash
env:
Expand All @@ -205,6 +226,7 @@ jobs:
# Build and package all the platform-agnostic(ish) things
build-global-artifacts:
needs:
- sign-release-binaries
- plan
- custom-build-binaries
- custom-build-docker
Expand Down Expand Up @@ -233,6 +255,12 @@ jobs:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- name: "Use signed native release archives"
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ needs.sign-release-binaries.outputs.github-archives }}
path: target/distrib/
merge-multiple: true
- id: cargo-dist
shell: bash
run: |
Expand Down Expand Up @@ -261,13 +289,14 @@ jobs:
# Determines if we should publish/announce
host:
needs:
- sign-release-binaries
- plan
- custom-build-binaries
- custom-build-docker
- build-global-artifacts
- generate-checksum-manifest
# Require checksums for all built archives before publishing. Other build jobs may be skipped.
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && needs.generate-checksum-manifest.result == 'success' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') && (needs.custom-build-docker.result == 'skipped' || needs.custom-build-docker.result == 'success') }}
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && needs.sign-release-binaries.result == 'success' && needs.generate-checksum-manifest.result == 'success' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') && (needs.custom-build-docker.result == 'skipped' || needs.custom-build-docker.result == 'success') }}
permissions:
"contents": "read"
env:
Expand Down Expand Up @@ -295,6 +324,12 @@ jobs:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- name: "Use signed native release archives"
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ needs.sign-release-binaries.outputs.github-archives }}
path: target/distrib/
merge-multiple: true
# This is a harmless no-op for GitHub Releases, hosting for that happens in "announce"
- id: host
shell: bash
Expand All @@ -318,13 +353,15 @@ jobs:

custom-publish-pypi:
needs:
- sign-release-binaries
- plan
- host
- release-gate
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
uses: $/.github/workflows/publish-pypi.yml
with:
plan: ${{ needs.plan.outputs.val }}
artifacts: ${{ needs.sign-release-binaries.outputs.pypi-artifacts }}
secrets: inherit
# publish jobs get escalated permissions
permissions:
Expand All @@ -334,14 +371,15 @@ jobs:
# Create a GitHub Release while uploading all files to it
announce:
needs:
- sign-release-binaries
- plan
- host
- release-gate
- custom-publish-pypi
# use "always() && ..." to allow us to wait for all publish jobs while
# still allowing individual publish jobs to skip themselves (for prereleases).
# "host" however must run to completion, no skipping allowed!
if: ${{ always() && needs.host.result == 'success' && needs.release-gate.result == 'success' && (needs.custom-publish-pypi.result == 'skipped' || needs.custom-publish-pypi.result == 'success') }}
if: ${{ always() && needs.host.result == 'success' && needs.sign-release-binaries.result == 'success' && needs.release-gate.result == 'success' && (needs.custom-publish-pypi.result == 'skipped' || needs.custom-publish-pypi.result == 'success') }}
runs-on: "depot-ubuntu-latest-4"
environment:
name: release
Expand All @@ -361,6 +399,12 @@ jobs:
pattern: artifacts-*
path: artifacts
merge-multiple: true
- name: "Use signed native release archives"
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ needs.sign-release-binaries.outputs.github-archives }}
path: artifacts
merge-multiple: true
- name: Cleanup
run: |
# Remove the granular manifests
Expand Down Expand Up @@ -436,11 +480,13 @@ jobs:

custom-publish-mirror:
needs:
- sign-release-binaries
- plan
- announce
uses: $/.github/workflows/publish-mirror.yml
with:
plan: ${{ needs.plan.outputs.val }}
signed-archives: ${{ needs.sign-release-binaries.outputs.github-archives }}
secrets: inherit
permissions:
"contents": "read"
Loading