Skip to content

Commit c94a856

Browse files
committed
Release workflow for cli binaries
1 parent bbb9324 commit c94a856

2 files changed

Lines changed: 386 additions & 0 deletions

File tree

.github/upload.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/bin/bash
2+
# Upload an asset file to R2.
3+
4+
set -e
5+
set -o pipefail
6+
7+
CLOUDFLARE_R2_ASSETS_BUCKET_NAME=assets
8+
9+
: "${1:?"missing first argument [artifact name]"}"
10+
: "${CLOUDFLARE_ASSETS_ACCOUNT_ID:?"missing environment variable"}"
11+
: "${CLOUDFLARE_ASSETS_R2_ACCESS_KEY_ID:?"missing environment variable"}"
12+
: "${CLOUDFLARE_ASSETS_R2_SECRET_ACCESS_KEY:?"missing environment variable"}"
13+
14+
bucket_name=$CLOUDFLARE_R2_ASSETS_BUCKET_NAME
15+
endpoint_url="https://${CLOUDFLARE_ASSETS_ACCOUNT_ID}.r2.cloudflarestorage.com"
16+
17+
key="cli-extensions/$1"
18+
19+
echo "Collecting the files to be uploaded…"
20+
21+
export PATH=/usr/local/bin:$PATH
22+
23+
aws configure set default.s3.max_concurrent_requests 8
24+
aws configure set default.s3.multipart_threshold 512MB
25+
aws configure set default.s3.multipart_chunksize 128MB
26+
27+
s3_path="s3://${bucket_name}/${key}"
28+
echo "Uploading to: $s3_path"
29+
30+
# See https://developers.cloudflare.com/r2/examples/aws/aws-cli/ for the rationale behind the checksum algorithm: it is a compatibility issue between AWS CLI and R2.
31+
env -i \
32+
PATH="$PATH" \
33+
AWS_PAGER=0 \
34+
AWS_REGION=auto \
35+
AWS_ACCESS_KEY_ID="$CLOUDFLARE_ASSETS_R2_ACCESS_KEY_ID" \
36+
AWS_SECRET_ACCESS_KEY="$CLOUDFLARE_ASSETS_R2_SECRET_ACCESS_KEY" \
37+
aws --endpoint-url "$endpoint_url" s3 cp --no-progress "$1" "$s3_path" --checksum-algorithm=CRC32
38+
39+
env -i \
40+
PATH="$PATH" \
41+
AWS_PAGER=0 \
42+
AWS_REGION=auto \
43+
AWS_ACCESS_KEY_ID="$CLOUDFLARE_ASSETS_R2_ACCESS_KEY_ID" \
44+
AWS_SECRET_ACCESS_KEY="$CLOUDFLARE_ASSETS_R2_SECRET_ACCESS_KEY" \
45+
aws --endpoint-url "$endpoint_url" s3 ls "$s3_path" --human-readable
46+
47+
echo "Done."
Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
name: Release CLI Extensions
2+
3+
on:
4+
push:
5+
# branches:
6+
# - main
7+
# paths:
8+
# - "cli/**/Cargo.toml"
9+
10+
env:
11+
CARGO_TERM_COLOR: always
12+
RUSTFLAGS: -D warnings
13+
14+
jobs:
15+
check-versions:
16+
runs-on: ubuntu-latest
17+
outputs:
18+
matrix: ${{ steps.set-matrix.outputs.matrix }}
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Install Rust
26+
uses: ./.github/actions/install-rust
27+
28+
- name: Find extensions with version changes
29+
id: set-matrix
30+
run: |
31+
echo "Checking for CLI extensions with version changes..."
32+
33+
# Initialize matrix JSON
34+
MATRIX="{\"include\":[]}"
35+
36+
# Find all CLI extension directories
37+
for EXT_DIR in cli/*/; do
38+
if [ -f "${EXT_DIR}Cargo.toml" ]; then
39+
# Extract extension name and current version
40+
EXT_NAME=$(grep -m 1 -oP 'name\s*=\s*"\K[^"]+' "${EXT_DIR}Cargo.toml")
41+
CURRENT_VERSION=$(grep -m 1 -oP 'version\s*=\s*"\K[^"]+' "${EXT_DIR}Cargo.toml")
42+
43+
echo "Found extension: $EXT_NAME, version: $CURRENT_VERSION"
44+
45+
# Check if this version already exists as a release
46+
LATEST_TAG=$(gh release list --repo ${{ github.repository }} --limit 100 | grep "^${EXT_NAME}-v" | head -n 1 | awk '{print $1}' || echo "")
47+
LATEST_VERSION=${LATEST_TAG#${EXT_NAME}-v}
48+
49+
echo "Latest released version: $LATEST_VERSION"
50+
51+
# If no release exists or current version is newer, add to matrix
52+
if [ -z "$LATEST_VERSION" ] || [ "$(printf '%s\n' "$LATEST_VERSION" "$CURRENT_VERSION" | sort -V | head -n1)" != "$CURRENT_VERSION" ]; then
53+
echo "New version detected for $EXT_NAME: $CURRENT_VERSION"
54+
MATRIX=$(echo $MATRIX | jq -c '.include += [{"extension": "'$EXT_NAME'", "version": "'$CURRENT_VERSION'", "path": "'${EXT_DIR%/}'"}]')
55+
else
56+
echo "No new version for $EXT_NAME"
57+
fi
58+
fi
59+
done
60+
61+
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
62+
echo "Extensions to release: $MATRIX"
63+
env:
64+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
65+
66+
darwin:
67+
needs: check-versions
68+
if: ${{ fromJson(needs.check-versions.outputs.matrix).include[0] }}
69+
runs-on: depot-macos-latest
70+
strategy:
71+
matrix:
72+
target:
73+
- aarch64-apple-darwin
74+
steps:
75+
- name: Checkout code
76+
uses: actions/checkout@v4
77+
78+
- name: Install Rust
79+
uses: ./.github/actions/install-rust
80+
81+
- name: Add targets
82+
run: |
83+
rustup target add ${{ matrix.target }}
84+
85+
- name: Create artifact directory
86+
run: mkdir -p artifacts
87+
88+
- name: Build for macOS
89+
run: |
90+
extensions=$(echo '${{ toJSON(fromJson(needs.check-versions.outputs.matrix).include) }}' | jq -c '.')
91+
for ext in $(echo "${extensions}" | jq -r '.[] | @base64'); do
92+
_jq() {
93+
echo ${ext} | base64 --decode | jq -r ${1}
94+
}
95+
96+
extension=$(_jq '.extension')
97+
path=$(_jq '.path')
98+
99+
echo "Building ${extension} at path ${path}"
100+
cd "${path}" && cargo build --release --target ${{ matrix.target }}
101+
102+
cp "${path}/target/${{ matrix.target }}/release/${extension}" "artifacts/${extension}-${{ matrix.target }}"
103+
done
104+
105+
- name: Upload macOS binaries
106+
uses: actions/upload-artifact@v4
107+
with:
108+
name: macos-${{ matrix.target }}-binaries
109+
path: artifacts/*
110+
retention-days: 1
111+
112+
windows:
113+
needs: check-versions
114+
if: ${{ fromJson(needs.check-versions.outputs.matrix).include[0] }}
115+
runs-on: depot-windows-2022-8
116+
steps:
117+
- name: Get sources
118+
uses: actions/checkout@v4
119+
120+
- name: Install Rust
121+
uses: ./.github/actions/install-rust
122+
123+
- name: Run sccache-cache
124+
uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
125+
126+
- name: Build Windows binaries
127+
run: |
128+
$extensions = '${{ toJSON(fromJson(needs.check-versions.outputs.matrix).include) }}' | ConvertFrom-Json
129+
130+
# Create artifacts directory if it doesn't exist
131+
if (!(Test-Path -Path artifacts)) {
132+
New-Item -ItemType Directory -Force -Path artifacts
133+
}
134+
135+
foreach ($ext in $extensions) {
136+
Write-Host "Building $($ext.extension) at path $($ext.path)"
137+
Push-Location $ext.path
138+
cargo build --release
139+
Pop-Location
140+
141+
# Copy binary to artifacts directory
142+
Copy-Item "$($ext.path)/target/release/$($ext.extension).exe" -Destination "artifacts/$($ext.extension)-x86_64-pc-windows-msvc.exe"
143+
}
144+
shell: pwsh
145+
env:
146+
RUSTC_WRAPPER: sccache
147+
148+
- name: Upload Windows binaries
149+
uses: actions/upload-artifact@v4
150+
with:
151+
name: windows-binaries
152+
path: artifacts/*.exe
153+
retention-days: 1
154+
155+
linux:
156+
needs: check-versions
157+
if: ${{ fromJson(needs.check-versions.outputs.matrix).include[0] }}
158+
strategy:
159+
fail-fast: false
160+
matrix:
161+
archs:
162+
[
163+
{
164+
runner: depot-ubuntu-24.04-8,
165+
target: x86_64-unknown-linux-musl,
166+
platform: linux,
167+
},
168+
{
169+
runner: depot-ubuntu-24.04-arm-8,
170+
target: aarch64-unknown-linux-musl,
171+
platform: linux-arm,
172+
},
173+
]
174+
runs-on: ${{ matrix.archs.runner }}
175+
steps:
176+
- name: Get sources
177+
uses: actions/checkout@v4
178+
179+
- name: Install Rust
180+
uses: ./.github/actions/install-rust
181+
182+
- name: Run sccache-cache
183+
uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
184+
185+
- name: Install musl tools
186+
run: |
187+
sudo apt-get update
188+
sudo apt-get install -y musl-tools
189+
if: contains(matrix.archs.target, 'musl')
190+
191+
- name: Build Linux binaries
192+
run: |
193+
extensions=$(echo '${{ toJSON(fromJson(needs.check-versions.outputs.matrix).include) }}' | jq -c '.')
194+
195+
mkdir -p artifacts
196+
197+
for ext in $(echo "${extensions}" | jq -r '.[] | @base64'); do
198+
_jq() {
199+
echo ${ext} | base64 --decode | jq -r ${1}
200+
}
201+
202+
extension=$(_jq '.extension')
203+
path=$(_jq '.path')
204+
205+
echo "Building ${extension} at path ${path}"
206+
207+
rustup target add ${{ matrix.archs.target }}
208+
cd "${path}" && cargo build --release --target ${{ matrix.archs.target }}
209+
210+
cp "${path}/target/${{ matrix.archs.target }}/release/${extension}" "artifacts/${extension}-${{ matrix.archs.target }}"
211+
done
212+
env:
213+
RUSTC_WRAPPER: sccache
214+
215+
- name: Upload Linux binaries
216+
uses: actions/upload-artifact@v4
217+
with:
218+
name: linux-${{ matrix.archs.target }}-binaries
219+
path: artifacts/*
220+
retention-days: 1
221+
222+
create-release:
223+
needs: [check-versions, darwin, windows, linux]
224+
if: ${{ fromJson(needs.check-versions.outputs.matrix).include[0] }}
225+
runs-on: ubuntu-latest
226+
strategy:
227+
matrix: ${{ fromJson(needs.check-versions.outputs.matrix) }}
228+
steps:
229+
- name: Checkout code
230+
uses: actions/checkout@v4
231+
with:
232+
fetch-depth: 0
233+
234+
- name: Create artifacts directory
235+
run: mkdir -p flat_artifacts
236+
237+
- name: Download all artifacts
238+
uses: actions/download-artifact@v4
239+
with:
240+
path: artifacts
241+
242+
- name: Flatten artifact directory structure
243+
run: |
244+
# Copy all binaries for current extension to flat_artifacts directory
245+
find artifacts -type f -name "${{ matrix.extension }}*" -exec cp {} flat_artifacts/ \;
246+
ls -la flat_artifacts/
247+
248+
- name: Generate changelog
249+
run: |
250+
echo "# ${{ matrix.extension }} v${{ matrix.version }}" > changelog.md
251+
echo "" >> changelog.md
252+
echo "Released on $(date +'%Y-%m-%d')" >> changelog.md
253+
echo "" >> changelog.md
254+
255+
# Add a list of changes since last release if available
256+
if gh release view ${{ matrix.extension }}-v$(echo ${{ matrix.version }} | awk -F. '{print $1"."$2"."$3-1}') &> /dev/null; then
257+
echo "## Changes since last release" >> changelog.md
258+
echo "" >> changelog.md
259+
git log --pretty=format:"* %s" ${{ matrix.extension }}-v$(echo ${{ matrix.version }} | awk -F. '{print $1"."$2"."$3-1}')..HEAD -- ${{ matrix.path }} >> changelog.md
260+
else
261+
echo "## Initial release" >> changelog.md
262+
fi
263+
env:
264+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
265+
266+
- name: Create GitHub Release
267+
id: create_release
268+
uses: softprops/action-gh-release@v2
269+
with:
270+
tag_name: ${{ matrix.extension }}-v${{ matrix.version }}
271+
name: ${{ matrix.extension }} v${{ matrix.version }}
272+
body_path: ./changelog.md
273+
draft: false
274+
prerelease: false
275+
files: flat_artifacts/*
276+
env:
277+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
278+
279+
- name: Upload to Cloudflare R2 (Optional)
280+
if: env.CLOUDFLARE_ASSETS_ACCOUNT_ID != ''
281+
run: |
282+
# Create install script that downloads the correct binary for current platform
283+
echo '#!/bin/bash' > install-${{ matrix.extension }}
284+
echo '' >> install-${{ matrix.extension }}
285+
echo 'VERSION="${{ matrix.version }}"' >> install-${{ matrix.extension }}
286+
echo 'NAME="${{ matrix.extension }}"' >> install-${{ matrix.extension }}
287+
288+
# Add platform detection and download logic similar to Grafbase CLI installer
289+
cat << 'EOT' >> install-${{ matrix.extension }}
290+
# Platform detection
291+
PLATFORM="$(uname -s)"
292+
case $PLATFORM in
293+
Darwin)
294+
PLATFORM="apple-darwin"
295+
;;
296+
Linux)
297+
PLATFORM="unknown-linux-musl"
298+
;;
299+
MINGW*|MSYS*|CYGWIN*)
300+
PLATFORM="pc-windows-msvc.exe"
301+
;;
302+
*)
303+
echo "Unsupported platform: $PLATFORM"
304+
exit 1
305+
;;
306+
esac
307+
308+
# Architecture detection
309+
ARCHITECTURE="$(uname -m)"
310+
if [ "$ARCHITECTURE" = "x86_64" ]; then
311+
ARCHITECTURE="x86_64"
312+
elif [ "$ARCHITECTURE" = "arm64" ] || [ "$ARCHITECTURE" = "aarch64" ]; then
313+
ARCHITECTURE="aarch64"
314+
else
315+
echo "Unsupported architecture: $ARCHITECTURE"
316+
exit 1
317+
fi
318+
319+
BINARY="${NAME}-${ARCHITECTURE}-${PLATFORM}"
320+
URL="https://github.com/${{ github.repository }}/releases/download/${NAME}-v${VERSION}/${BINARY}"
321+
322+
echo "Downloading $NAME v${VERSION}..."
323+
if command -v curl > /dev/null 2>&1; then
324+
curl -fsSL "$URL" -o "$NAME"
325+
else
326+
wget -q "$URL" -O "$NAME"
327+
fi
328+
329+
chmod +x "$NAME"
330+
echo "$NAME v${VERSION} has been installed to the current directory."
331+
echo "Consider moving it to a directory in your PATH."
332+
EOT
333+
334+
# Upload to R2 if credentials are available
335+
./.github/upload.sh install-${{ matrix.extension }}
336+
env:
337+
CLOUDFLARE_ASSETS_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ASSETS_ACCOUNT_ID }}
338+
CLOUDFLARE_ASSETS_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ASSETS_R2_ACCESS_KEY_ID }}
339+
CLOUDFLARE_ASSETS_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_ASSETS_R2_SECRET_ACCESS_KEY }}

0 commit comments

Comments
 (0)