-
Notifications
You must be signed in to change notification settings - Fork 448
139 lines (122 loc) · 4.41 KB
/
Copy pathpublish.yml
File metadata and controls
139 lines (122 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT license.
# Publishes all workspace crates to crates.io.
#
# Triggers:
# - push tag v{major}.{minor}.{patch} → real publish
# - pull_request touching Cargo.toml → automatic dry-run (pre-merge check)
# - workflow_dispatch → manual dry-run or real publish
#
# Requires CRATES_IO_TOKEN secret. Rust toolchain version is read from rust-toolchain.toml.
name: Publish to crates.io
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
pull_request:
branches: ["main"]
paths:
- 'Cargo.toml'
workflow_dispatch:
inputs:
dry_run:
description: 'Run in dry-run mode (test without actually publishing)'
required: false
default: 'true'
type: choice
options:
- 'true'
- 'false'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: false
env:
RUST_BACKTRACE: 1
defaults:
run:
shell: bash
permissions:
contents: read
jobs:
publish:
name: >-
${{
(github.event_name == 'pull_request' || github.event.inputs.dry_run == 'true')
&& 'Dry-run publish test'
|| 'Publish crates to crates.io'
}}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: true
fetch-depth: 0
- name: Read Rust version from rust-toolchain.toml
id: rust-version
run: |
RUST_VERSION=$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml)
echo "channel=$RUST_VERSION" >> "$GITHUB_OUTPUT"
- name: Install Rust ${{ steps.rust-version.outputs.channel }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.rust-version.outputs.channel }}
- uses: Swatinem/rust-cache@v2
- name: Prevent publish from non-main branch
if: >-
github.event_name == 'workflow_dispatch'
&& github.event.inputs.dry_run != 'true'
&& github.ref != 'refs/heads/main'
run: |
echo "::error::Live publishing is only allowed from main. Use dry-run for other branches."
exit 1
- name: Verify version matches tag
if: github.event_name == 'push'
run: |
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
CARGO_VERSION=$(grep -A 5 '^\[workspace\.package\]' Cargo.toml | grep 'version = ' | head -n1 | sed 's/.*"\(.*\)".*/\1/')
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
echo "::error::Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)"
exit 1
fi
- name: Verify tag is on main branch
if: github.event_name == 'push'
run: |
if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then
echo "::error::Tag must point to a commit on main"
exit 1
fi
- name: Verify all publishable crates use workspace version
run: |
bad_crates=()
for manifest in $(cargo metadata --no-deps --format-version 1 | jq -r '.packages[].manifest_path'); do
dir=$(dirname "$manifest")
name=$(basename "$dir")
# Skip the root manifest and crates with publish = false
if [ "$manifest" = "$(pwd)/Cargo.toml" ]; then
continue
fi
if grep -qE '^\s*publish\s*=\s*false' "$manifest"; then
continue
fi
if ! grep -qE 'version\s*=\s*\{\s*workspace\s*=\s*true\s*\}|version\.workspace\s*=\s*true' "$manifest"; then
bad_crates+=("$name")
fi
done
if [ ${#bad_crates[@]} -gt 0 ]; then
echo "::error::The following publishable crates do not use version.workspace = true: ${bad_crates[*]}"
exit 1
fi
- name: Publish workspace crates
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }}
run: |
DRY_RUN_FLAG=""
if [ "${{ github.event_name }}" = "pull_request" ] || [ "$DRY_RUN" = "true" ]; then
DRY_RUN_FLAG="--dry-run"
echo "🧪 DRY-RUN MODE"
else
echo "📦 LIVE MODE - Publishing to crates.io"
fi
cargo publish --locked --workspace $DRY_RUN_FLAG