Skip to content

[skip-changelog]: bump ruby/setup-ruby from 1.310.0 to 1.313.0 #365

[skip-changelog]: bump ruby/setup-ruby from 1.310.0 to 1.313.0

[skip-changelog]: bump ruby/setup-ruby from 1.310.0 to 1.313.0 #365

name: UniFFI Bindings Check
on:
pull_request:
branches: [master]
concurrency:
group: uniffi-check-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
UNIFFI_RUSTDOC_TOOLCHAIN: nightly-2025-09-30
jobs:
# ── Change Detection ────────────────────────────────────────────────
changes:
name: Detect Changed Paths
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
should_run: ${{ steps.filter.outputs.rust }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 2
- name: Detect changes
id: filter
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
with:
filters: |
rust:
- 'crates/mdk-core/src/**'
- 'crates/mdk-uniffi/src/**'
- 'crates/mdk-uniffi/unbound-methods.txt'
- 'scripts/check-uniffi-bindings.ts'
- '.github/workflows/uniffi-bindings-check.yml'
# ── Check UniFFI binding coverage ───────────────────────────────────
check-bindings:
name: Check Bindings
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.should_run == 'true'
permissions:
contents: read
pull-requests: write
issues: write
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install Rust nightly for rustdoc JSON
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # pinned from master
with:
toolchain: ${{ env.UNIFFI_RUSTDOC_TOOLCHAIN }}
- name: Install Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
- name: Cache cargo registry and build
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
key: uniffi-check
- name: Generate rustdoc JSON for mdk-core
run: |
RUSTDOCFLAGS='-Z unstable-options --output-format json' \
cargo +"${UNIFFI_RUSTDOC_TOOLCHAIN}" doc -p mdk-core --no-deps --all-features
- name: Generate rustdoc JSON for mdk-uniffi
run: |
RUSTDOCFLAGS='-Z unstable-options --output-format json' \
cargo +"${UNIFFI_RUSTDOC_TOOLCHAIN}" doc -p mdk-uniffi --no-deps --all-features
- name: Check UniFFI binding coverage
id: check
run: bun scripts/check-uniffi-bindings.ts
- name: Comment on PR
if: steps.check.outcome == 'success' && github.event_name == 'pull_request'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const fs = require('fs');
const commentMarker = '<!-- uniffi-bindings-check -->';
// Skip commenting on PRs from forks
const isFork = context.payload.pull_request.head.repo.full_name
!== context.payload.repository.full_name;
if (isFork) {
console.log('Skipping PR comment: PR is from a fork');
return;
}
// Check if there are unbound methods to report
let body;
try {
body = fs.readFileSync('/tmp/uniffi-check-comment.md', 'utf-8');
} catch (e) {
body = null;
}
// Find existing comment from a previous run
const { data: comments } = await github.rest.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
});
const existing = comments.find(c =>
c.body.includes(commentMarker) && c.user.type === 'Bot'
);
try {
if (!body) {
// All methods covered — delete stale comment if one exists
if (existing) {
await github.rest.issues.deleteComment({
comment_id: existing.id,
owner: context.repo.owner,
repo: context.repo.repo,
});
}
return;
}
body = commentMarker + '\n' + body;
if (existing) {
await github.rest.issues.updateComment({
comment_id: existing.id,
owner: context.repo.owner,
repo: context.repo.repo,
body: body,
});
} else {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body,
});
}
} catch (error) {
if (error.status === 403) {
console.log('Unable to comment on PR (likely from fork):', error.message);
} else {
throw error;
}
}