bdk-ffi Release Watch #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: bdk-ffi Release Watch | |
| on: | |
| schedule: | |
| # Run every Monday at 09:30 UTC. | |
| - cron: "30 9 * * 1" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| issues: write | |
| concurrency: | |
| group: bdk-ffi-release-watch | |
| cancel-in-progress: false | |
| jobs: | |
| open-update-issue: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Check latest bdk-ffi release and open issue | |
| uses: actions/github-script@v7 | |
| env: | |
| UPSTREAM_REPO: bitcoindevkit/bdk-ffi | |
| DEPENDENCY_FILE: native/Cargo.toml | |
| with: | |
| script: | | |
| const fs = require('node:fs'); | |
| const dependencyFile = process.env.DEPENDENCY_FILE; | |
| const upstreamRepo = process.env.UPSTREAM_REPO; | |
| const [upstreamOwner, upstreamName] = upstreamRepo.split('/'); | |
| if (!upstreamOwner || !upstreamName) { | |
| core.setFailed(`Invalid UPSTREAM_REPO: ${upstreamRepo}`); | |
| return; | |
| } | |
| const cargoToml = fs.readFileSync(dependencyFile, 'utf8'); | |
| const pinMatch = cargoToml.match(/^\s*bdk-ffi\s*=\s*\{[^}]*\btag\s*=\s*"([^"]+)"/ms); | |
| if (!pinMatch) { | |
| core.setFailed(`Could not find a tag-pinned bdk-ffi dependency in ${dependencyFile}`); | |
| return; | |
| } | |
| const currentTag = pinMatch[1]; | |
| function parseSemver(tag) { | |
| const match = String(tag).trim().match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.*)?$/); | |
| if (!match) return null; | |
| return { | |
| major: Number(match[1]), | |
| minor: Number(match[2]), | |
| patch: Number(match[3]), | |
| prerelease: match[4] ?? null, | |
| }; | |
| } | |
| function compareSemver(aTag, bTag) { | |
| const a = parseSemver(aTag); | |
| const b = parseSemver(bTag); | |
| if (!a || !b) return null; | |
| for (const key of ['major', 'minor', 'patch']) { | |
| if (a[key] > b[key]) return 1; | |
| if (a[key] < b[key]) return -1; | |
| } | |
| if (a.prerelease && !b.prerelease) return -1; | |
| if (!a.prerelease && b.prerelease) return 1; | |
| if (!a.prerelease && !b.prerelease) return 0; | |
| if (a.prerelease > b.prerelease) return 1; | |
| if (a.prerelease < b.prerelease) return -1; | |
| return 0; | |
| } | |
| let latestRelease; | |
| try { | |
| latestRelease = await github.rest.repos.getLatestRelease({ | |
| owner: upstreamOwner, | |
| repo: upstreamName, | |
| }); | |
| } catch (error) { | |
| if (error.status === 404) { | |
| core.info(`No stable GitHub release found for ${upstreamRepo}; skipping.`); | |
| return; | |
| } | |
| throw error; | |
| } | |
| const latestTag = latestRelease.data.tag_name; | |
| const cmp = compareSemver(latestTag, currentTag); | |
| core.info(`Current pinned bdk-ffi tag: ${currentTag}`); | |
| core.info(`Latest upstream bdk-ffi release: ${latestTag}`); | |
| if (currentTag === latestTag) { | |
| core.info('Pinned tag is already at the latest release.'); | |
| return; | |
| } | |
| if (cmp !== null && cmp <= 0) { | |
| core.info('Pinned tag is not older than the latest stable release; skipping.'); | |
| return; | |
| } | |
| const issueTitle = `chore: update bdk-ffi to ${latestTag}`; | |
| const searchQuery = `repo:${context.repo.owner}/${context.repo.repo} is:open "${issueTitle}"`; | |
| const existing = await github.rest.search.issuesAndPullRequests({ | |
| q: searchQuery, | |
| per_page: 10, | |
| }); | |
| const existingMatch = existing.data.items.find((item) => item.title === issueTitle); | |
| if (existingMatch) { | |
| core.info(`Open issue or PR already exists: #${existingMatch.number}`); | |
| return; | |
| } | |
| const issueBody = [ | |
| '<!-- bdk-ffi-release-watch -->', | |
| '', | |
| 'A new upstream `bdk-ffi` release is available.', | |
| '', | |
| `- Current pinned tag in \`${dependencyFile}\`: \`${currentTag}\``, | |
| `- Latest upstream release: \`${latestTag}\``, | |
| `- Release notes: ${latestRelease.data.html_url}`, | |
| '', | |
| 'Suggested follow-up:', | |
| '1. Update the `bdk-ffi` tag in `native/Cargo.toml`.', | |
| '2. Regenerate bindings with `./scripts/generate_bindings.sh`.', | |
| '3. Run `dart test` (and CI) before merging.', | |
| ].join('\n'); | |
| const created = await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: issueTitle, | |
| body: issueBody, | |
| }); | |
| core.info(`Created issue #${created.data.number}: ${created.data.html_url}`); |