Bindings Release #6
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
| # SPDX-FileCopyrightText: Copyright 2025 - 2026 gematik GmbH | |
| # | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| # | |
| # ******* | |
| # | |
| # For additional notes and disclaimer from gematik and in case of changes by gematik, | |
| # find details in the "Readme" file. | |
| name: Bindings Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Release version (e.g. 1.0.0)' | |
| required: false | |
| type: string | |
| env: | |
| CARGO_TERM_COLOR: always | |
| concurrency: | |
| group: bindings-release-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| release-notes: | |
| name: Release notes tag check | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Verify ReleaseNotes.md tag entry | |
| run: | | |
| set -euo pipefail | |
| version="${{ inputs.version }}" | |
| if [ -z "${version}" ]; then | |
| echo "No release version provided; skipping release notes tag check." | |
| exit 0 | |
| fi | |
| echo "Release version: ${version}" | |
| needle="### ${version} (Latest)" | |
| if grep -Fq "${needle}" ReleaseNotes.md; then | |
| echo "ReleaseNotes.md contains '${needle}'." | |
| else | |
| echo "::error::ReleaseNotes.md must include '${needle}'." | |
| exit 1 | |
| fi | |
| kotlin-bindings: | |
| name: Kotlin bindings (${{ matrix.display_name }}) | |
| runs-on: ${{ matrix.runner }} | |
| needs: release-notes | |
| env: | |
| OUT_ROOT: ${{ github.workspace }}/artifacts/${{ matrix.display_name }}/generated/uniffi | |
| CARGO_TARGET_DIR: ${{ github.workspace }}/artifacts/${{ matrix.display_name }}/cargo | |
| ANDROID_SDK_ROOT: /usr/local/lib/android/sdk | |
| RUST_BACKTRACE: "1" | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - runner: ubuntu-latest | |
| display_name: linux-x86_64 | |
| platform: linux | |
| arch: x86_64 | |
| library_file: libhealthcard.so | |
| just_shell: "" | |
| - runner: windows-latest | |
| display_name: windows-x86_64 | |
| platform: windows | |
| arch: x86_64 | |
| library_file: healthcard.dll | |
| just_shell: "C:/Program Files/Git/bin/bash.exe" | |
| - runner: macos-26 | |
| display_name: darwin-aarch64 | |
| platform: darwin | |
| arch: aarch64 | |
| library_file: libhealthcard.dylib | |
| just_shell: "" | |
| defaults: | |
| run: | |
| shell: bash | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache Cargo builds | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: ". -> ${{ env.CARGO_TARGET_DIR }}" | |
| - name: Install just | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: just | |
| - name: Set up Java (Linux only) | |
| if: runner.os == 'Linux' | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: "21" | |
| - name: Ensure Android SDK platforms (Linux only) | |
| if: runner.os == 'Linux' | |
| run: | | |
| yes | "${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager" --sdk_root="${ANDROID_SDK_ROOT}" --licenses >/dev/null || true | |
| "${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager" --sdk_root="${ANDROID_SDK_ROOT}" "platforms;android-34" "build-tools;34.0.0" | |
| - name: Install cargo-ndk (Linux only) | |
| if: runner.os == 'Linux' | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-ndk | |
| - name: Add Rust Android targets (Linux only) | |
| if: runner.os == 'Linux' | |
| run: rustup target add aarch64-linux-android x86_64-linux-android | |
| - name: Set Perl environment variables | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $perl = (where.exe perl)[0] | |
| echo "PERL=$perl" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 | |
| echo "OPENSSL_SRC_PERL=$perl" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 | |
| - name: Setup MSVC (Windows only) | |
| if: runner.os == 'Windows' | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| with: | |
| arch: x64 | |
| - name: Remove conflicting link.exe (Windows only) | |
| if: runner.os == 'Windows' | |
| run: | | |
| if [ -x /usr/bin/link ]; then | |
| rm -f /usr/bin/link | |
| fi | |
| - name: Build Kotlin bindings | |
| run: | | |
| if [ -n "${{ matrix.just_shell }}" ]; then | |
| just --shell="${{ matrix.just_shell }}" kotlin-bindings-generate ${{ matrix.platform }} ${{ matrix.arch }} ${{ matrix.library_file }} release | |
| else | |
| just kotlin-bindings-generate ${{ matrix.platform }} ${{ matrix.arch }} ${{ matrix.library_file }} release | |
| fi | |
| - name: Build Android native libraries (Linux only - arm64-v8a, x86_64) | |
| if: runner.os == 'Linux' | |
| run: | | |
| just kotlin-bindings-generate-android | |
| - name: Upload OpenSSL Configure logs (on failure) | |
| if: failure() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: openssl-configure-logs-${{ matrix.display_name }} | |
| path: | | |
| ${{ env.CARGO_TARGET_DIR }}/**/configure.log | |
| ${{ github.workspace }}/**/configure.log | |
| if-no-files-found: warn | |
| - name: Upload Resources | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: kotlin-bindings-${{ matrix.display_name }} | |
| path: | | |
| ${{ env.OUT_ROOT }}/resources/** | |
| ${{ env.OUT_ROOT }}/kotlin/** | |
| ${{ env.OUT_ROOT }}/android-jni/** | |
| if-no-files-found: warn | |
| swift-bindings: | |
| name: Swift bindings (darwin-universal) | |
| runs-on: macos-26 | |
| needs: release-notes | |
| env: | |
| OUT_ROOT: ${{ github.workspace }}/artifacts/swift/generated/uniffi | |
| CARGO_TARGET_DIR: ${{ github.workspace }}/artifacts/swift/cargo | |
| RUST_BACKTRACE: "1" | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: aarch64-apple-ios, aarch64-apple-ios-sim, x86_64-apple-ios, aarch64-apple-darwin, x86_64-apple-darwin | |
| - name: Cache Cargo builds | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: ". -> ${{ env.CARGO_TARGET_DIR }}" | |
| - name: Install just | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: just | |
| - name: Build XCFramework | |
| run: just swift-xcframework | |
| - name: Stage Swift wrapper for release | |
| run: cp core-modules-swift/healthcard/Sources/OpenHealthHealthcard/OpenHealthHealthcard.swift OpenHealthHealthcard.swift | |
| - name: Upload Swift wrapper | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: swift-wrapper | |
| path: OpenHealthHealthcard.swift | |
| if-no-files-found: error | |
| - name: Upload OpenSSL Configure logs (Swift - on failure) | |
| if: failure() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: openssl-configure-logs-swift | |
| path: | | |
| ${{ env.CARGO_TARGET_DIR }}/**/configure.log | |
| ${{ github.workspace }}/**/configure.log | |
| if-no-files-found: warn | |
| - name: Zip XCFramework | |
| working-directory: core-modules-swift/healthcard | |
| run: zip -r OpenHealthHealthcardFFI.xcframework.zip OpenHealthHealthcardFFI.xcframework | |
| - name: Write XCFramework checksum | |
| working-directory: core-modules-swift/healthcard | |
| run: | | |
| swift package compute-checksum OpenHealthHealthcardFFI.xcframework.zip > OpenHealthHealthcardFFI.xcframework.sha256 | |
| - name: Upload XCFramework Zip | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: swift-xcframework | |
| path: core-modules-swift/healthcard/OpenHealthHealthcardFFI.xcframework.zip | |
| - name: Upload XCFramework checksum | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: swift-xcframework-checksum | |
| path: core-modules-swift/healthcard/OpenHealthHealthcardFFI.xcframework.sha256 | |
| assemble-kotlin-bindings: | |
| name: Assemble Kotlin bindings bundle | |
| runs-on: ubuntu-latest | |
| needs: kotlin-bindings | |
| env: | |
| OUT_ROOT: ${{ github.workspace }}/assembly/dist/generated/uniffi | |
| steps: | |
| - name: Checkout (for directory layout) | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install just | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: just | |
| - name: Set up Java | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: "21" | |
| - name: Set up Gradle cache | |
| uses: gradle/actions/setup-gradle@v5 | |
| - name: Download platform artifacts | |
| uses: actions/download-artifact@v7 | |
| with: | |
| pattern: "kotlin-bindings-*" | |
| path: assembly/input | |
| - name: Collect libraries and generated Kotlin | |
| run: | | |
| just kotlin-bindings-assemble assembly/input assembly/dist/generated/uniffi | |
| - name: Upload Kotlin bindings bundle | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: kotlin-bindings-bundle | |
| path: | | |
| ${{ env.OUT_ROOT }}/resources/** | |
| ${{ env.OUT_ROOT }}/kotlin/** | |
| ${{ env.OUT_ROOT }}/android-jni/** | |
| if-no-files-found: error | |
| - name: Publish Kotlin bindings to mavenLocal (assembled outputs) | |
| run: | | |
| if [ -n "${{ inputs.version }}" ]; then | |
| export ORG_GRADLE_PROJECT_version="${{ inputs.version }}" | |
| fi | |
| just kotlin-publish-local | |
| - name: Stage Maven local artifacts for upload | |
| run: | | |
| set -euo pipefail | |
| upload_root="${GITHUB_WORKSPACE}/assembly/maven-repo" | |
| src_root="${HOME}/.m2/repository/de/gematik/openhealth" | |
| mkdir -p "${upload_root}/de/gematik" | |
| cp -a "${src_root}" "${upload_root}/de/gematik/" | |
| - name: Upload Maven local artifacts | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: kotlin-bindings-maven-local | |
| path: assembly/maven-repo | |
| if-no-files-found: error | |
| release: | |
| name: Create Release | |
| runs-on: ubuntu-latest | |
| needs: [swift-bindings, assemble-kotlin-bindings] | |
| if: inputs.version != '' | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download Swift Artifact | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: swift-xcframework | |
| path: artifacts/swift | |
| - name: Download Swift wrapper | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: swift-wrapper | |
| path: artifacts/swift-wrapper | |
| - name: Download Swift checksum | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: swift-xcframework-checksum | |
| path: artifacts/swift-checksum | |
| - name: Download Kotlin Artifact | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: kotlin-bindings-maven-local | |
| path: artifacts/kotlin | |
| - name: Zip Kotlin Maven Repo | |
| run: | | |
| cd artifacts/kotlin | |
| zip -r ../../maven-repo.zip . | |
| - name: Update Package.swift | |
| run: | | |
| VERSION="${{ inputs.version }}" | |
| ZIP_PATH="artifacts/swift/OpenHealthHealthcardFFI.xcframework.zip" | |
| CHECKSUM=$(cat artifacts/swift-checksum/OpenHealthHealthcardFFI.xcframework.sha256) | |
| REPO_URL="https://github.com/${{ github.repository }}/releases/download/${VERSION}/OpenHealthHealthcardFFI.xcframework.zip" | |
| mkdir -p core-modules-swift/healthcard/Sources/OpenHealthHealthcard | |
| cp artifacts/swift-wrapper/OpenHealthHealthcard.swift core-modules-swift/healthcard/Sources/OpenHealthHealthcard/OpenHealthHealthcard.swift | |
| # Update Package.swift to use remote binary target | |
| sed -i "s|path: \"core-modules-swift/healthcard/OpenHealthHealthcardFFI.xcframework\"|url: \"$REPO_URL\", checksum: \"$CHECKSUM\"|" Package.swift | |
| # Verify change | |
| cat Package.swift | |
| git config user.name "GitHub Actions" | |
| git config user.email "actions@github.com" | |
| git add Package.swift | |
| git add -f core-modules-swift/healthcard/Sources/OpenHealthHealthcard/OpenHealthHealthcard.swift | |
| git commit -m "Release ${VERSION}" | |
| git tag "${VERSION}" | |
| git push origin "${VERSION}" | |
| - name: Render release body | |
| id: release-body | |
| run: | | |
| set -euo pipefail | |
| template=".github/workflows/changelog_template.md" | |
| latest_tag="${{ inputs.version }}" | |
| body_path="artifacts/release-body.md" | |
| mkdir -p "$(dirname "${body_path}")" | |
| sed -e "s|{LATEST_TAG}|${latest_tag}|g" "${template}" > "${body_path}" | |
| echo "Release body rendered to ${body_path}." | |
| echo "path=${body_path}" >> "${GITHUB_OUTPUT}" | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ inputs.version }} | |
| body_path: ${{ steps.release-body.outputs.path }} | |
| files: | | |
| artifacts/swift/OpenHealthHealthcardFFI.xcframework.zip | |
| maven-repo.zip | |
| generate_release_notes: false |