Skip to content

Commit 3892851

Browse files
crodasthesimplekid
authored andcommitted
Add dart publish workflow, prebuilt binary support, and README
Add a GitHub Actions workflow (dart-publish.yml) in the monorepo that automates the full Dart release pipeline for the cdk-dart repo: - Syncs sources to cdk-dart using rsync and resolves Cargo workspace references. - Builds native FFI libraries for 8 targets (Linux, macOS, Windows, Android, iOS). - Generates Dart bindings via uniffi-bindgen reusing cargo cache. - Creates per-platform release archives containing source code and binaries. - Stages changes on a release branch and merges to master. - Creates a GitHub release with tags and per-platform release assets. Extend the Dart build hook (build.dart) to detect and use prebuilt binaries from a `prebuilt/<target-triple>/` directory, skipping the cargo build when available. Falls back to building from source otherwise. Enable npubcash and bip353 features on cdk-ffi for the Dart bindings. Update bindings/dart/README.md with installation and workflow instructions.
1 parent bbbcae7 commit 3892851

10 files changed

Lines changed: 483 additions & 439 deletions

File tree

.github/workflows/dart-publish.yml

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
name: "FFI - Dart Bindings"
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
release_tag:
7+
description: 'Tag to create for release (e.g. v0.17.0)'
8+
required: true
9+
cdk_version:
10+
description: 'CDK dependency version (e.g. 0.17.0). Defaults to release_tag without the "v" prefix.'
11+
required: false
12+
env:
13+
CARGO_TERM_COLOR: ${{ vars.CARGO_TERM_COLOR }}
14+
15+
16+
jobs:
17+
dart-sync-sources:
18+
name: "dart: Sync sources to cdk-dart"
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout monorepo
22+
uses: actions/checkout@v4
23+
with:
24+
ref: main
25+
26+
- name: Clone cdk-dart
27+
run: |
28+
git clone https://x-access-token:${{ secrets.DART_DEPLOY_KEY }}@github.com/${{ vars.CDK_DART_REPO }}.git cdk-dart
29+
30+
- name: Copy bindings/dart to cdk-dart
31+
run: |
32+
rsync -av --delete \
33+
--exclude='.github' \
34+
--exclude='target' \
35+
--exclude='.git' \
36+
bindings/dart/ cdk-dart/
37+
cp rust-toolchain.toml cdk-dart/
38+
39+
- name: Update versions and resolve workspace references
40+
run: |
41+
TAG="${{ inputs.release_tag }}"
42+
CDK_VER="${{ inputs.cdk_version }}"
43+
CDK_VER="${CDK_VER:-${TAG#v}}"
44+
RELEASE_VER="${TAG#v}"
45+
echo "Setting CDK version to ${CDK_VER}, release version to ${RELEASE_VER}"
46+
47+
# Helper: extract a value from [workspace.package] in root Cargo.toml
48+
ws_pkg() {
49+
sed -n '/^\[workspace\.package\]/,/^\[/p' Cargo.toml \
50+
| grep "^$1 " | head -1 | sed 's/.*= *"\(.*\)"/\1/'
51+
}
52+
53+
# Helper: extract a workspace dependency version
54+
ws_dep_ver() {
55+
local line
56+
line=$(sed -n '/^\[workspace\.dependencies\]/,/^\[/p' Cargo.toml \
57+
| grep "^$1 " | head -1)
58+
# Handle both: dep = "version" and dep = { ..., version = "x", ... }
59+
if echo "$line" | grep -q 'version *= *"'; then
60+
echo "$line" | sed 's/.*version *= *"\([^"]*\)".*/\1/'
61+
else
62+
echo "$line" | sed 's/.*= *"\([^"]*\)".*/\1/'
63+
fi
64+
}
65+
66+
# Read workspace values dynamically
67+
WS_EDITION=$(ws_pkg edition)
68+
WS_RUST_VERSION=$(ws_pkg rust-version)
69+
WS_LICENSE=$(ws_pkg license)
70+
WS_HOMEPAGE=$(ws_pkg homepage)
71+
WS_REPOSITORY=$(ws_pkg repository)
72+
WS_README=$(ws_pkg readme)
73+
WS_UNIFFI_VER=$(ws_dep_ver uniffi)
74+
75+
echo "Workspace values: edition=${WS_EDITION} rust-version=${WS_RUST_VERSION} uniffi=${WS_UNIFFI_VER}"
76+
77+
# Update pubspec.yaml version
78+
sed -i "s/^version: \".*\"/version: \"${RELEASE_VER}\"/" cdk-dart/pubspec.yaml
79+
80+
# Resolve workspace package fields in rust/Cargo.toml
81+
sed -i \
82+
-e "s/^edition\.workspace = true/edition = \"${WS_EDITION}\"/" \
83+
-e "s/^rust-version\.workspace = true/rust-version = \"${WS_RUST_VERSION}\"/" \
84+
-e "s/^license\.workspace = true/license = \"${WS_LICENSE}\"/" \
85+
-e "s|^homepage\.workspace = true|homepage = \"${WS_HOMEPAGE}\"|" \
86+
-e "s|^repository\.workspace = true|repository = \"${WS_REPOSITORY}\"|" \
87+
-e "s/^version\.workspace = true/version = \"${CDK_VER}\"/" \
88+
-e "s/^readme\.workspace = true/readme = \"${WS_README}\"/" \
89+
cdk-dart/rust/Cargo.toml
90+
91+
# Resolve workspace dependency references
92+
sed -i \
93+
-e "s/cdk-ffi = { workspace = true/cdk-ffi = { version = \"=${CDK_VER}\", default-features = false/" \
94+
-e "s/uniffi = { workspace = true/uniffi = { version = \"${WS_UNIFFI_VER}\"/" \
95+
cdk-dart/rust/Cargo.toml
96+
97+
# Remove workspace lints reference
98+
sed -i '/^\[lints\]/,/^$/s/^workspace = true//' cdk-dart/rust/Cargo.toml
99+
100+
# Add release profile
101+
printf '\n[profile.release]\nlto = true\nstrip = true\ncodegen-units = 1\n' >> cdk-dart/rust/Cargo.toml
102+
103+
cat cdk-dart/pubspec.yaml
104+
echo "---"
105+
cat cdk-dart/rust/Cargo.toml
106+
107+
- name: Push to cdk-dart release branch
108+
working-directory: cdk-dart
109+
run: |
110+
TAG="${{ inputs.release_tag }}"
111+
RELEASE_BRANCH="release/v${TAG#v}"
112+
git config user.name "github-actions[bot]"
113+
git config user.email "github-actions[bot]@users.noreply.github.com"
114+
git checkout -b "${RELEASE_BRANCH}"
115+
git add -A
116+
git diff --cached --quiet && echo "No changes to commit" && exit 0
117+
git commit -m "sync: update sources for ${TAG}"
118+
git push origin "${RELEASE_BRANCH}"
119+
120+
dart-build-native:
121+
name: "dart: Build ${{ matrix.target }}"
122+
needs: [dart-sync-sources]
123+
runs-on: ${{ matrix.runner }}
124+
strategy:
125+
fail-fast: false
126+
matrix:
127+
include:
128+
# Linux
129+
- target: x86_64-unknown-linux-gnu
130+
runner: ubuntu-22.04
131+
artifact: libcdk_ffi_dart.so
132+
- target: aarch64-unknown-linux-gnu
133+
runner: ubuntu-24.04-arm
134+
artifact: libcdk_ffi_dart.so
135+
136+
# macOS
137+
- target: aarch64-apple-darwin
138+
runner: macos-14
139+
artifact: libcdk_ffi_dart.dylib
140+
141+
# Windows
142+
- target: x86_64-pc-windows-msvc
143+
runner: windows-latest
144+
artifact: cdk_ffi_dart.dll
145+
146+
# Android
147+
- target: aarch64-linux-android
148+
runner: ubuntu-22.04
149+
artifact: libcdk_ffi_dart.so
150+
- target: armv7-linux-androideabi
151+
runner: ubuntu-22.04
152+
artifact: libcdk_ffi_dart.so
153+
- target: x86_64-linux-android
154+
runner: ubuntu-22.04
155+
artifact: libcdk_ffi_dart.so
156+
157+
# iOS
158+
- target: aarch64-apple-ios
159+
runner: macos-14
160+
artifact: libcdk_ffi_dart.a
161+
162+
steps:
163+
- name: Clone cdk-dart
164+
shell: bash
165+
run: |
166+
TAG="${{ inputs.release_tag }}"
167+
RELEASE_BRANCH="release/v${TAG#v}"
168+
git clone --branch "${RELEASE_BRANCH}" \
169+
https://x-access-token:${{ secrets.DART_DEPLOY_KEY }}@github.com/${{ vars.CDK_DART_REPO }}.git cdk-dart
170+
171+
- name: Install Rust toolchain
172+
uses: dtolnay/rust-toolchain@stable
173+
with:
174+
targets: ${{ matrix.target }}
175+
176+
- name: Install cross (Android)
177+
if: contains(matrix.target, 'android')
178+
run: cargo install cross --git https://github.com/cross-rs/cross --tag v0.2.5
179+
180+
- name: Build (native)
181+
if: "!contains(matrix.target, 'android')"
182+
working-directory: cdk-dart/rust
183+
run: cargo build --release --target ${{ matrix.target }}
184+
185+
- name: Build (cross / Android)
186+
if: contains(matrix.target, 'android')
187+
working-directory: cdk-dart/rust
188+
run: cross build --release --target ${{ matrix.target }}
189+
190+
- name: Strip debug symbols
191+
shell: bash
192+
run: |
193+
FILE="cdk-dart/rust/target/${{ matrix.target }}/release/${{ matrix.artifact }}"
194+
case "${{ matrix.target }}" in
195+
*windows*) strip --strip-all "$FILE" ;;
196+
*apple*) strip -S "$FILE" ;;
197+
*android*) "$ANDROID_NDK_LATEST_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip" --strip-all "$FILE" ;;
198+
*) strip --strip-all "$FILE" ;;
199+
esac
200+
201+
- name: Generate Dart bindings (darwin only)
202+
if: matrix.target == 'aarch64-apple-darwin'
203+
working-directory: cdk-dart/rust
204+
run: |
205+
mkdir -p ../generated-bindings
206+
cargo run --release --bin uniffi-bindgen -- \
207+
target/${{ matrix.target }}/release/${{ matrix.artifact }} \
208+
--out-dir ../generated-bindings
209+
210+
- name: Upload generated bindings
211+
if: matrix.target == 'aarch64-apple-darwin'
212+
uses: actions/upload-artifact@v4
213+
with:
214+
name: dart-bindings-generated
215+
path: cdk-dart/generated-bindings/
216+
217+
- name: Prepare artifact
218+
shell: bash
219+
run: |
220+
mkdir -p dist
221+
cp "cdk-dart/rust/target/${{ matrix.target }}/release/${{ matrix.artifact }}" \
222+
"dist/${{ matrix.target }}-${{ matrix.artifact }}"
223+
224+
- name: Upload artifact
225+
uses: actions/upload-artifact@v4
226+
with:
227+
name: dart-native-${{ matrix.target }}
228+
path: dist/
229+
230+
231+
dart-publish:
232+
name: "dart: Publish to cdk-dart"
233+
runs-on: ubuntu-latest
234+
needs: [dart-build-native]
235+
steps:
236+
- name: Clone cdk-dart
237+
run: |
238+
TAG="${{ inputs.release_tag }}"
239+
RELEASE_BRANCH="release/v${TAG#v}"
240+
git clone --branch "${RELEASE_BRANCH}" \
241+
https://x-access-token:${{ secrets.DART_DEPLOY_KEY }}@github.com/${{ vars.CDK_DART_REPO }}.git cdk-dart
242+
243+
- name: Download all native artifacts
244+
uses: actions/download-artifact@v4
245+
with:
246+
path: ./artifacts
247+
pattern: dart-native-*
248+
merge-multiple: true
249+
250+
- name: Organize prebuilt binaries
251+
run: |
252+
mkdir -p cdk-dart/prebuilt
253+
254+
for f in artifacts/*; do
255+
filename=$(basename "$f")
256+
for suffix in libcdk_ffi_dart.so libcdk_ffi_dart.dylib libcdk_ffi_dart.a cdk_ffi_dart.dll; do
257+
if [[ "$filename" == *"-${suffix}" ]]; then
258+
target="${filename%-${suffix}}"
259+
mkdir -p "cdk-dart/prebuilt/${target}"
260+
cp "$f" "cdk-dart/prebuilt/${target}/${suffix}"
261+
break
262+
fi
263+
done
264+
done
265+
266+
- name: Download generated bindings
267+
uses: actions/download-artifact@v4
268+
with:
269+
name: dart-bindings-generated
270+
path: cdk-dart/lib/src/generated
271+
272+
- name: Commit and push prebuilt files
273+
working-directory: cdk-dart
274+
run: |
275+
git config user.name "github-actions[bot]"
276+
git config user.email "github-actions[bot]@users.noreply.github.com"
277+
git add -A
278+
git diff --cached --quiet && echo "No changes to commit" || \
279+
(git commit -m "prebuilt binaries before bindgen" && git push origin HEAD)
280+
281+
- name: Commit to release branch
282+
working-directory: cdk-dart
283+
run: |
284+
git config user.name "github-actions[bot]"
285+
git config user.email "github-actions[bot]@users.noreply.github.com"
286+
git add -A
287+
git diff --cached --quiet && echo "No changes to commit" && exit 0
288+
git commit -m "release: ${{ inputs.release_tag }} — add bindings and prebuilt binaries"
289+
git push origin HEAD
290+
291+
- name: Merge to master, tag, and cleanup
292+
working-directory: cdk-dart
293+
run: |
294+
TAG="${{ inputs.release_tag }}"
295+
RELEASE_BRANCH="release/v${TAG#v}"
296+
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@')
297+
git checkout "${DEFAULT_BRANCH}"
298+
git merge "${RELEASE_BRANCH}" --squash
299+
git commit -m "release: ${TAG}"
300+
git tag "${TAG}"
301+
git push origin "${DEFAULT_BRANCH}" --tags
302+
git push origin --delete "${RELEASE_BRANCH}"
303+
304+
- name: Create per-platform release archives
305+
run: |
306+
mkdir -p release-archives
307+
308+
# Copy source without prebuilt dir and .git
309+
rsync -a --exclude='.git' --exclude='prebuilt' cdk-dart/ staging/
310+
311+
for dir in cdk-dart/prebuilt/*/; do
312+
target=$(basename "$dir")
313+
# Add only this platform's prebuilt
314+
mkdir -p "staging/prebuilt/${target}"
315+
cp -r "$dir"* "staging/prebuilt/${target}/"
316+
# Archive
317+
if [[ "$target" == *windows* ]]; then
318+
(cd staging && zip -qr "../release-archives/${target}.zip" .)
319+
else
320+
tar -czf "release-archives/${target}.tar.gz" -C staging .
321+
fi
322+
# Clean up for next platform
323+
rm -rf staging/prebuilt
324+
done
325+
ls -lh release-archives/
326+
327+
- name: Create release on cdk-dart
328+
env:
329+
GH_TOKEN: ${{ secrets.DART_DEPLOY_KEY }}
330+
run: |
331+
gh release create "${{ inputs.release_tag }}" \
332+
--repo ${{ vars.CDK_DART_REPO }} \
333+
--title "Release ${{ inputs.release_tag }}" \
334+
--generate-notes \
335+
release-archives/*

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ fuzz/corpus/
3333
__pycache__
3434
libcdk_ffi*
3535
cdk_ffi.py
36+
pubspec.lock
3637

3738
# Kotlin bindings
3839
.gradle/
@@ -47,4 +48,3 @@ out/
4748
bindings/kotlin/cdk-jvm/src/main/kotlin/uniffi/
4849
bindings/kotlin/cdk-jvm/src/main/resources/*.so
4950
bindings/kotlin/cdk-jvm/src/main/resources/*.dylib
50-

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ cdk-lnbits = { path = "./crates/cdk-lnbits", version = "=0.16.0" }
5858
cdk-lnd = { path = "./crates/cdk-lnd", version = "=0.16.0" }
5959
cdk-ldk-node = { path = "./crates/cdk-ldk-node", version = "=0.16.0" }
6060
cdk-fake-wallet = { path = "./crates/cdk-fake-wallet", version = "=0.16.0" }
61-
cdk-ffi = { path = "./crates/cdk-ffi", version = "=0.16.0" }
61+
cdk-ffi = { path = "./crates/cdk-ffi", default-features = true, version = "=0.16.0" }
6262
cdk-http-client = { path = "./crates/cdk-http-client", version = "=0.16.0" }
6363
cdk-payment-processor = { path = "./crates/cdk-payment-processor", default-features = true, version = "=0.16.0" }
6464
cdk-mint-rpc = { path = "./crates/cdk-mint-rpc", version = "=0.16.0" }

bindings/dart/.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
prebuilt/** binary

0 commit comments

Comments
 (0)