Skip to content

Commit 70f9e85

Browse files
authored
Add automated protoc artifact bundle generation for releases (#1835)
## Motivation Currently the build plugin distributed from swift-protobuf and other repos that offer protoc plugins such as grpc-swift, are hardly usable since they require the user to install protoc and then point SwiftPM or the IDE to its location. ## Modifications This PR adds a new step in our release flow that bundles the upstream protoc binaries into an artifactbundle and uploads them to the latest draft release. It also adds to the release steps to update the `Package.swift` ## Result We now have an ecosystem wide distributing of protoc that can be used directly from the package manager without requiring users to install it manually. This makes build and command plugins that rely on protoc vastly more useful.
1 parent 5c021bc commit 70f9e85

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/bin/bash
2+
3+
# This script generates an artifactbundle for protoc. This artifactbundle
4+
# is used by the Swift package manger. The script is run by a GitHub action
5+
# when a new pre-release is created for swift-protobuf.
6+
7+
set -eux
8+
9+
# Fetch the latest stable release from protocolbuffers/protobuf
10+
AUTH="Authorization: token $GITHUB_TOKEN"
11+
response=$(curl -sH "$AUTH" "https://api.github.com/repos/protocolbuffers/protobuf/releases/latest")
12+
TAG=$(echo "$response" | grep -m 1 '"tag_name":' | cut -d '"' -f 4)
13+
14+
# Remove 'v' prefix if present
15+
TAG="${TAG#v}"
16+
17+
if [[ ! "$TAG" =~ ^[0-9]+\.[0-9]+$ ]]; then
18+
echo "Error: $TAG does not match the expected pattern"
19+
exit 1
20+
fi
21+
22+
# Fetch all protoc release assets from protocolbuffers/protobuf
23+
curl -LJ --output protoc-$TAG-osx-x86_64.zip -H 'Accept: application/octet-stream' https://github.com/protocolbuffers/protobuf/releases/download/v$TAG/protoc-$TAG-osx-x86_64.zip
24+
curl -LJ --output protoc-$TAG-osx-aarch_64.zip -H 'Accept: application/octet-stream' https://github.com/protocolbuffers/protobuf/releases/download/v$TAG/protoc-$TAG-osx-aarch_64.zip
25+
curl -LJ --output protoc-$TAG-linux-aarch_64.zip -H 'Accept: application/octet-stream' https://github.com/protocolbuffers/protobuf/releases/download/v$TAG/protoc-$TAG-linux-aarch_64.zip
26+
curl -LJ --output protoc-$TAG-linux-x86_64.zip -H 'Accept: application/octet-stream' https://github.com/protocolbuffers/protobuf/releases/download/v$TAG/protoc-$TAG-linux-x86_64.zip
27+
curl -LJ --output protoc-$TAG-win64.zip -H 'Accept: application/octet-stream' https://github.com/protocolbuffers/protobuf/releases/download/v$TAG/protoc-$TAG-win64.zip
28+
29+
# Fetch and validate license from protocolbuffers/protobuf
30+
curl -LJ --output LICENSE -H 'Accept: application/vnd.github.v3.raw' https://api.github.com/repos/protocolbuffers/protobuf/contents/LICENSE
31+
LICENSE_HASH=$(sha256sum LICENSE | cut -d ' ' -f 1)
32+
EXPECTED_HASH="6e5e117324afd944dcf67f36cf329843bc1a92229a8cd9bb573d7a83130fea7d"
33+
34+
if [ "$LICENSE_HASH" != "$EXPECTED_HASH" ]; then
35+
echo "Error: License file has changed. Expected hash: $EXPECTED_HASH, Got: $LICENSE_HASH"
36+
exit 1
37+
fi
38+
39+
# Unzip all assets
40+
mkdir protoc-$TAG.artifactbundle
41+
unzip -d protoc-$TAG.artifactbundle/protoc-$TAG-osx-x86_64 protoc-$TAG-osx-x86_64.zip
42+
unzip -d protoc-$TAG.artifactbundle/protoc-$TAG-osx-aarch_64 protoc-$TAG-osx-aarch_64.zip
43+
unzip -d protoc-$TAG.artifactbundle/protoc-$TAG-linux-aarch_64 protoc-$TAG-linux-aarch_64.zip
44+
unzip -d protoc-$TAG.artifactbundle/protoc-$TAG-linux-x86_64 protoc-$TAG-linux-x86_64.zip
45+
unzip -d protoc-$TAG.artifactbundle/protoc-$TAG-win64 protoc-$TAG-win64.zip
46+
47+
# Copy license file into artifactbundle
48+
cp LICENSE protoc-$TAG.artifactbundle/
49+
50+
# Create info.json for artifactbundle
51+
cat > protoc-$TAG.artifactbundle/info.json << EOF
52+
{
53+
"schemaVersion": "1.0",
54+
"artifacts": {
55+
"protoc": {
56+
"type": "executable",
57+
"version": "$TAG",
58+
"variants": [
59+
{
60+
"path": "protoc-$TAG-linux-x86_64/bin/protoc",
61+
"supportedTriples": ["x86_64-unknown-linux-gnu"]
62+
},
63+
{
64+
"path": "protoc-$TAG-linux-aarch_64/bin/protoc",
65+
"supportedTriples": ["aarch64-unknown-linux-gnu", "arm64-unknown-linux-gnu", "aarch64-unknown-linux", "arm64-unknown-linux"]
66+
},
67+
{
68+
"path": "protoc-$TAG-osx-x86_64/bin/protoc",
69+
"supportedTriples": ["x86_64-apple-macosx"]
70+
},
71+
{
72+
"path": "protoc-$TAG-osx-aarch_64/bin/protoc",
73+
"supportedTriples": ["arm64-apple-macosx"]
74+
},
75+
{
76+
"path": "protoc-$TAG-win64/bin/protoc.exe",
77+
"supportedTriples": ["x86_64-unknown-windows"]
78+
},
79+
]
80+
}
81+
}
82+
}
83+
EOF
84+
85+
# Zip artifactbundle
86+
zip -r protoc-$TAG.artifactbundle.zip protoc-$TAG.artifactbundle
87+
88+
# Get asset upload url for the latest swift-protobuf draft release
89+
response=$(curl -sH "$AUTH" "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/releases")
90+
upload_url=$(echo "$response" | jq -r '.[] | select(.draft == true) | .upload_url' | head -n 1)
91+
SWIFT_PROTOBUF_TAG=$(echo "$response" | jq -r '.[] | select(.draft == true) | .tag_name' | head -n 1)
92+
93+
if [ -z "$SWIFT_PROTOBUF_TAG" ] || [ -z "$upload_url" ]; then
94+
echo "Error: No draft release found"
95+
exit 1
96+
fi
97+
98+
# Remove the {?name,label} template from upload_url
99+
upload_url=$(echo "$upload_url" | sed 's/{?name,label}//')
100+
echo "Found draft release: $SWIFT_PROTOBUF_TAG"
101+
echo "Upload URL: $upload_url"
102+
103+
# Upload asset
104+
curl --data-binary @protoc-$TAG.artifactbundle.zip -H "$AUTH" -H "Content-Type: application/octet-stream" "$upload_url?name=protoc-$TAG.artifactbundle.zip"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: Upload protoc artifactbundle
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
upload-artifactbundle:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: "Checkout code"
11+
uses: actions/checkout@v4
12+
- name: Upload artifactbundle
13+
env:
14+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
15+
run: cd ${{ github.workspace }} && .github/scripts/upload_artifactbundle.sh
16+

Documentation/RELEASING.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,47 @@ When doing a release:
4848
everything based on the PR descriptions and _semver_ tags in the repo. Just read
4949
though was was generate to see if any tweaks are needed.
5050

51-
When everything is good, click on _Publish release_.
51+
**Important:** Save this as a **draft** release first (do not publish yet).
52+
53+
1. Generate protoc artifact bundle if needed
54+
55+
First, check if there have been any new protoc releases since the last
56+
time we bundled protoc. To do this check the binary target protoc version number
57+
in the Package.swift. If there has been a new release of protoc then once you
58+
have created the draft release, trigger the "Upload protoc artifactbundle"
59+
workflow from the [Actions tab](https://github.com/apple/swift-protobuf/actions/workflows/prerelease_protoc_artifactbundle.yml).
60+
61+
This workflow will:
62+
- Fetch the latest stable protoc release from protocolbuffers/protobuf
63+
- Create a Swift Package Manager compatible artifact bundle
64+
- Upload it to your draft release
65+
66+
Wait for the workflow to complete successfully before proceeding.
67+
68+
1. Update Package.swift with new artifact bundle
69+
70+
If there was a new protoc release and you uploaded a new artifact bundle in
71+
the previous step. Create a pull request that updates the `Package.swift` file
72+
to reference the new artifact bundle. You'll need to update two things:
73+
74+
- **URL**: Change to point to your new release tag
75+
- **Checksum**: Download the artifact bundle and calculate its SHA256 hash
76+
77+
Example update:
78+
```swift
79+
.binaryTarget(
80+
name: "protoc",
81+
url: "https://github.com/apple/swift-protobuf/releases/download/[a.b.c]/protoc-X.Y.artifactbundle.zip",
82+
checksum: "new-sha256-checksum-here"
83+
),
84+
```
85+
86+
To get the checksum copy it from the Github UI when looking at the draft release.bundle.zip
87+
88+
1. Publish the release
89+
90+
After the Package.swift PR is merged, return to your draft release and click
91+
_Publish release_.
5292

5393
1. Publish the `SwiftProtobuf.podspec`
5494

0 commit comments

Comments
 (0)