Record which rule produced each braille cell #702
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: Publish | ||
|
Check warning on line 1 in .github/workflows/publish.yml
|
||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| pull_request_target: | ||
| branches: | ||
| - main | ||
| permissions: write-all | ||
| jobs: | ||
| test: | ||
| name: Test | ||
| runs-on: ${{ matrix.platform }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| python-version: | ||
| - "3.11" | ||
| - "3.12" | ||
| - "3.13" | ||
| - "3.14" | ||
| platform: | ||
| - ubuntu-latest | ||
| - windows-latest | ||
| - macos-latest | ||
| steps: | ||
| # pull_request_target는 보안상 기본적으로 base branch(main)를 체크아웃한다. | ||
| # PR 코드의 커버리지를 측정하려면 PR head를 명시적으로 지정해야 한다. | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| # actions/checkout v7 은 pull_request_target 에서 fork PR 코드 체크아웃을 | ||
| # 기본 차단한다. 이 opt-in 이 없으면 fork PR 의 모든 job 이 checkout 에서 실패한다. | ||
| # 지우면 CI 가 다시 깨진다. https://gh.io/securely-using-pull_request_target | ||
| allow-unsafe-pr-checkout: true | ||
| - uses: oven-sh/setup-bun@v2 | ||
| with: | ||
| bun-version: latest | ||
| - name: Set up Python ${{ matrix.python-version }} | ||
| uses: actions/setup-python@v7 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v10.0.1 | ||
| - name: Install maturin | ||
| run: uv pip install maturin --system | ||
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| - name: Install | ||
| uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| components: clippy, rustfmt | ||
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| - name: Cargo tarpaulin and fmt | ||
| run: | | ||
| cargo install cargo-tarpaulin | ||
| rustup component add rustfmt clippy | ||
| - name: Install dependencies | ||
| run: bun install | ||
| - name: Build | ||
| run: bun run build | ||
| - name: Lint | ||
| run: bun run lint | ||
| - name: reformat | ||
| shell: bash | ||
| run: | | ||
| echo 'max_width = 100000' > .rustfmt.toml | ||
| echo 'tab_spaces = 4' >> .rustfmt.toml | ||
| echo 'newline_style = "Unix"' >> .rustfmt.toml | ||
| echo 'fn_call_width = 100000' >> .rustfmt.toml | ||
| echo 'fn_params_layout = "Compressed"' >> .rustfmt.toml | ||
| echo 'chain_width = 100000' >> .rustfmt.toml | ||
| echo 'merge_derives = true' >> .rustfmt.toml | ||
| echo 'use_small_heuristics = "Default"' >> .rustfmt.toml | ||
| cargo fmt | ||
| - name: Test (Rust coverage) | ||
| timeout-minutes: 20 | ||
| run: bun run test:rust | ||
| - name: Test (Node) | ||
| timeout-minutes: 10 | ||
| # Windows에서 중첩된 `bun run`이 테스트 완료 후 간헐적으로 멈추므로 직접 실행한다. | ||
| run: bun test | ||
| - name: Test (Python) | ||
| timeout-minutes: 10 | ||
| run: bun run test:python | ||
| - name: Set up MSVC for C/C++ tests | ||
| if: runner.os == 'Windows' | ||
| uses: ilammy/msvc-dev-cmd@v1 | ||
| - name: Test (C and C++) | ||
| timeout-minutes: 5 | ||
| run: bun run test:c | ||
| - name: Format Rollback | ||
| shell: bash | ||
| run: | | ||
| rm -rf .rustfmt.toml | ||
| cargo fmt | ||
| - name: Upload to codecov.io | ||
| uses: codecov/codecov-action@v7 | ||
| with: | ||
| token: ${{ secrets.CODECOV_TOKEN }} | ||
| fail_ci_if_error: true | ||
| if: github.ref == 'refs/heads/main' | ||
| dotnet-test: | ||
| name: .NET Test - ${{ matrix.rid }} | ||
| runs-on: ${{ matrix.runner }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| # Windows x64 | ||
| - runner: windows-latest | ||
| target: x86_64-pc-windows-msvc | ||
| rid: win-x64 | ||
| lib_name: braillify_native.dll | ||
| # Windows x86 (32-bit) | ||
| - runner: windows-latest | ||
| target: i686-pc-windows-msvc | ||
| rid: win-x86 | ||
| lib_name: braillify_native.dll | ||
| dotnet_arch: x86 | ||
| # Linux x64 | ||
| - runner: ubuntu-latest | ||
| target: x86_64-unknown-linux-gnu | ||
| rid: linux-x64 | ||
| lib_name: libbraillify_native.so | ||
| # macOS arm64 (native) | ||
| - runner: macos-14 | ||
| target: aarch64-apple-darwin | ||
| rid: osx-arm64 | ||
| lib_name: libbraillify_native.dylib | ||
| # macOS x64 (x64 SDK on macos-14) | ||
| - runner: macos-14 | ||
| target: x86_64-apple-darwin | ||
| rid: osx-x64 | ||
| lib_name: libbraillify_native.dylib | ||
| steps: | ||
| # pull_request_target에서도 PR 코드를 체크아웃해 테스트한다. | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| # actions/checkout v7 은 pull_request_target 에서 fork PR 코드 체크아웃을 | ||
| # 기본 차단한다. 이 opt-in 이 없으면 fork PR 의 모든 job 이 checkout 에서 실패한다. | ||
| # 지우면 CI 가 다시 깨진다. https://gh.io/securely-using-pull_request_target | ||
| allow-unsafe-pr-checkout: true | ||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| target: ${{ matrix.target }} | ||
| - name: Build native library | ||
| run: cargo build --release --target ${{ matrix.target }} -p dotnet | ||
| - name: Setup .NET | ||
| if: matrix.dotnet_arch != 'x86' && matrix.rid != 'osx-x64' | ||
| uses: actions/setup-dotnet@v6 | ||
| with: | ||
| dotnet-version: | | ||
| 9.0.x | ||
| 8.0.x | ||
| - name: Setup .NET x86 | ||
| if: matrix.dotnet_arch == 'x86' | ||
| shell: pwsh | ||
| run: | | ||
| $installDir = "$env:RUNNER_TEMP\dotnet-x86" | ||
| Invoke-WebRequest -Uri https://dot.net/v1/dotnet-install.ps1 -OutFile dotnet-install.ps1 | ||
| ./dotnet-install.ps1 -Channel 8.0 -Architecture x86 -InstallDir $installDir | ||
| ./dotnet-install.ps1 -Channel 9.0 -Architecture x86 -InstallDir $installDir | ||
| ./dotnet-install.ps1 -Channel 10.0 -Architecture x86 -InstallDir $installDir -Quality preview | ||
| # Add to PATH and set DOTNET_ROOT | ||
| echo "$installDir" | Out-File -FilePath $env:GITHUB_PATH -Append | ||
| echo "DOTNET_ROOT=$installDir" | Out-File -FilePath $env:GITHUB_ENV -Append | ||
| - name: Setup .NET x64 (macOS) | ||
| if: matrix.rid == 'osx-x64' | ||
| run: | | ||
| export DOTNET_INSTALL_DIR="$RUNNER_TEMP/dotnet-x64" | ||
| curl -sSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 8.0 --architecture x64 --install-dir "$DOTNET_INSTALL_DIR" | ||
| curl -sSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 9.0 --architecture x64 --install-dir "$DOTNET_INSTALL_DIR" | ||
| curl -sSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 10.0 --architecture x64 --install-dir "$DOTNET_INSTALL_DIR" --quality preview | ||
| echo "$DOTNET_INSTALL_DIR" >> $GITHUB_PATH | ||
| echo "DOTNET_ROOT=$DOTNET_INSTALL_DIR" >> $GITHUB_ENV | ||
| - name: Copy native library | ||
| run: | | ||
| mkdir -p packages/dotnet/BraillifyNet/runtimes/${{ matrix.rid }}/native | ||
| cp target/${{ matrix.target }}/release/${{ matrix.lib_name }} packages/dotnet/BraillifyNet/runtimes/${{ matrix.rid }}/native/ | ||
| shell: bash | ||
| - name: Restore dependencies | ||
| run: dotnet restore Braillify.Tests/Braillify.Tests.csproj | ||
| working-directory: packages/dotnet | ||
| - name: Build | ||
| run: dotnet build --no-restore -c Release Braillify.Tests/Braillify.Tests.csproj | ||
| working-directory: packages/dotnet | ||
| - name: Test (.NET 8.0) | ||
| run: dotnet test --no-build -c Release --verbosity normal --framework net8.0 Braillify.Tests/Braillify.Tests.csproj | ||
| working-directory: packages/dotnet | ||
| - name: Test (.NET 9.0) | ||
| run: dotnet test --no-build -c Release --verbosity normal --framework net9.0 Braillify.Tests/Braillify.Tests.csproj | ||
| working-directory: packages/dotnet | ||
| ruby-test: | ||
| name: Ruby Test - ${{ matrix.platform }} | ||
| runs-on: ${{ matrix.platform }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| platform: | ||
| - ubuntu-latest | ||
| - windows-latest | ||
| - macos-latest | ||
| steps: | ||
| # pull_request_target에서도 PR 코드를 체크아웃해 테스트한다. | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| # actions/checkout v7 은 pull_request_target 에서 fork PR 코드 체크아웃을 | ||
| # 기본 차단한다. 이 opt-in 이 없으면 fork PR 의 모든 job 이 checkout 에서 실패한다. | ||
| # 지우면 CI 가 다시 깨진다. https://gh.io/securely-using-pull_request_target | ||
| allow-unsafe-pr-checkout: true | ||
| # Ruby 플랫폼(Windows ucrt 등)에 맞는 Rust 타겟/bindgen 환경까지 구성하는 | ||
| # rb-sys 공식 셋업 액션. | ||
| - uses: oxidize-rb/actions/setup-ruby-and-rust@v1 | ||
| with: | ||
| ruby-version: "3.4" | ||
| bundler-cache: true | ||
| cargo-cache: true | ||
| working-directory: packages/ruby | ||
| # 실배포 gem 플랫폼(stable Ruby, Windows는 ucrt+GNU)에서의 lint. | ||
| # 루트 워크스페이스에서 실행해 [patch.crates-io]로 로컬 libs/braillify를 사용한다. | ||
| - name: Lint | ||
| run: cargo clippy -p braillify_rb --all-targets -- -D warnings | ||
| - name: Compile | ||
| run: bundle exec rake compile | ||
| working-directory: packages/ruby | ||
| - name: Test | ||
| run: bundle exec rake test | ||
| working-directory: packages/ruby | ||
| jvm-test: | ||
| name: JVM Test - ${{ matrix.native-target }} | ||
| runs-on: ${{ matrix.runner }} | ||
| permissions: | ||
| contents: read | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - runner: ubuntu-24.04 | ||
| native-target: linux-x86_64 | ||
| - runner: ubuntu-24.04-arm | ||
| native-target: linux-aarch64 | ||
| - runner: macos-15-intel | ||
| native-target: macos-x86_64 | ||
| - runner: macos-15 | ||
| native-target: macos-aarch64 | ||
| - runner: windows-2022 | ||
| native-target: windows-x86_64 | ||
| steps: | ||
| # pull_request_target에서도 PR 코드를 체크아웃해 실제 JVM 바인딩을 테스트한다. | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| allow-unsafe-pr-checkout: true | ||
| - name: Validate Gradle Wrapper | ||
| uses: gradle/actions/wrapper-validation@v4 | ||
| - name: Set up JDK 17 | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| distribution: temurin | ||
| java-version: "17" | ||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| - name: Setup Gradle | ||
| uses: gradle/actions/setup-gradle@v4 | ||
| with: | ||
| cache-read-only: ${{ github.event_name == 'pull_request_target' }} | ||
| - name: Test JVM binding | ||
| run: ./gradlew test --no-daemon | ||
| working-directory: packages/jvm | ||
| deploy-landing: | ||
| name: Deploy Landing | ||
| runs-on: ubuntu-latest | ||
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | ||
| needs: | ||
| - test | ||
| - dotnet-test | ||
| - jvm-test | ||
| - ruby-test | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - uses: oven-sh/setup-bun@v2 | ||
| with: | ||
| bun-version: latest | ||
| - name: Set up Python | ||
| uses: actions/setup-python@v7 | ||
| with: | ||
| python-version: "3.14" | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v10.0.1 | ||
| - name: Install maturin | ||
| run: uv pip install maturin --system | ||
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| - name: Install | ||
| uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| components: clippy, rustfmt | ||
| - run: | | ||
| bun i | ||
| bun run build | ||
| - run: cargo test test_by_testcase | ||
| # 실패하지만 어느정도 맞았는지 알려주므로 무시해야합니다. | ||
| continue-on-error: true | ||
| - name: Build Landing | ||
| run: bun run build:landing | ||
| - name: Upload artifact | ||
| uses: actions/upload-pages-artifact@v5 | ||
| with: | ||
| path: ./apps/landing/out | ||
| retention-days: 1 | ||
| - uses: actions/deploy-pages@v5 | ||
| # publish | ||
| changepacks: | ||
| name: changepacks | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| # create pull request comments | ||
| pull-requests: write | ||
| # Actions > General > Workflow permissions for creating pull request | ||
| # Create brench to create pull request | ||
| contents: write | ||
| needs: | ||
| - test | ||
| - dotnet-test | ||
| - go-test | ||
| - jvm-test | ||
| - ruby-test | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| # changepacks 는 base branch 와 견주어 바뀐 manifest 를 찾으므로 전체 | ||
| # 이력이 필요하다. 기본 shallow checkout 이면 그 비교가 실패한다. | ||
| fetch-depth: 0 | ||
| # actions/checkout v7 은 pull_request_target 에서 fork PR 코드 체크아웃을 | ||
| # 기본 차단한다. 이 opt-in 이 없으면 fork PR 의 모든 job 이 checkout 에서 실패한다. | ||
| allow-unsafe-pr-checkout: true | ||
| # changepacks 는 base branch 를 refs/heads/<name> 에서 찾는데, checkout 은 SHA 를 | ||
| # 주면 detached HEAD 로 두고 refs/remotes/origin/* 만 만든다. 그 로컬 ref 를 세운다. | ||
| - name: Materialize the base branch as a local ref | ||
| env: | ||
| BASE: ${{ github.event.pull_request.base.ref || github.ref_name }} | ||
| run: git branch --force "$BASE" "refs/remotes/origin/$BASE" | ||
| - uses: changepacks/action@main | ||
| id: changepacks | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| outputs: | ||
| changepacks: ${{ steps.changepacks.outputs.changepacks }} | ||
| release_assets_urls: ${{ steps.changepacks.outputs.release_assets_urls }} | ||
| # node | ||
| node-build: | ||
| needs: | ||
| - test | ||
| - dotnet-test | ||
| - changepacks | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/node/package.json') }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| settings: | ||
| # - host: macos-latest | ||
| # target: x86_64-apple-darwin | ||
| # build: bun run build --target x86_64-apple-darwin | ||
| # - host: windows-latest | ||
| # build: bun run build --target x86_64-pc-windows-msvc | ||
| # target: x86_64-pc-windows-msvc | ||
| - host: ubuntu-latest | ||
| target: x86_64-unknown-linux-gnu | ||
| build: bun run build | ||
| # - host: macos-latest | ||
| # target: aarch64-apple-darwin | ||
| # build: bun run build --target aarch64-apple-darwin | ||
| name: Node Build - ${{ matrix.settings.target }} | ||
| runs-on: ${{ matrix.settings.host }} | ||
| env: | ||
| # DEBUG: napi:* | ||
| MACOSX_DEPLOYMENT_TARGET: "10.13" | ||
| CARGO_INCREMENTAL: "1" | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Setup node | ||
| uses: actions/setup-node@v7 | ||
| with: | ||
| node-version: 22 | ||
| - uses: oven-sh/setup-bun@v2 | ||
| with: | ||
| bun-version: latest | ||
| - name: Set up Python | ||
| uses: actions/setup-python@v7 | ||
| with: | ||
| python-version: "3.14" | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v10.0.1 | ||
| - name: Install maturin | ||
| run: uv pip install maturin --system | ||
| - name: Install | ||
| uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| toolchain: stable | ||
| targets: ${{ matrix.settings.target }} | ||
| - uses: mlugg/setup-zig@v2 | ||
| if: ${{ contains(matrix.settings.target, 'musl') }} | ||
| with: | ||
| version: 0.14.1 | ||
| - name: Install cargo-zigbuild | ||
| uses: taiki-e/install-action@v2 | ||
| if: ${{ contains(matrix.settings.target, 'musl') }} | ||
| env: | ||
| GITHUB_TOKEN: ${{ github.token }} | ||
| with: | ||
| tool: cargo-zigbuild | ||
| - name: Setup toolchain | ||
| run: ${{ matrix.settings.setup }} | ||
| if: ${{ matrix.settings.setup }} | ||
| shell: bash | ||
| - name: Install dependencies | ||
| run: bun install | ||
| - name: Build | ||
| run: ${{ matrix.settings.build }} | ||
| shell: bash | ||
| working-directory: packages/node | ||
| - name: Upload artifact | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: pkg-${{ matrix.settings.target }} | ||
| path: | | ||
| packages/node/pkg/* | ||
| if-no-files-found: error | ||
| retention-days: 1 | ||
| # python | ||
| python-build: | ||
| runs-on: ${{ matrix.runner }} | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/python/pyproject.toml') }} | ||
| needs: | ||
| - test | ||
| - dotnet-test | ||
| - changepacks | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| # Linux manylinux | ||
| - runner: ubuntu-22.04 | ||
| target: x86_64 | ||
| manylinux: auto | ||
| os: linux | ||
| - runner: ubuntu-22.04 | ||
| target: x86 | ||
| manylinux: auto | ||
| os: linux | ||
| - runner: ubuntu-22.04 | ||
| target: aarch64 | ||
| manylinux: auto | ||
| os: linux | ||
| - runner: ubuntu-22.04 | ||
| target: armv7 | ||
| manylinux: auto | ||
| os: linux | ||
| - runner: ubuntu-22.04 | ||
| target: ppc64le | ||
| manylinux: auto | ||
| os: linux | ||
| # Linux musllinux | ||
| - runner: ubuntu-22.04 | ||
| target: x86_64 | ||
| manylinux: musllinux_1_2 | ||
| os: musllinux | ||
| - runner: ubuntu-22.04 | ||
| target: x86 | ||
| manylinux: musllinux_1_2 | ||
| os: musllinux | ||
| - runner: ubuntu-22.04 | ||
| target: aarch64 | ||
| manylinux: musllinux_1_2 | ||
| os: musllinux | ||
| - runner: ubuntu-22.04 | ||
| target: armv7 | ||
| manylinux: musllinux_1_2 | ||
| os: musllinux | ||
| # Windows | ||
| - runner: windows-latest | ||
| target: x64 | ||
| os: windows | ||
| python-target: x64 | ||
| - runner: windows-latest | ||
| target: x86 | ||
| os: windows | ||
| python-target: x86 | ||
| # macOS | ||
| - runner: macos-14 | ||
| target: x86_64 | ||
| os: macos | ||
| - runner: macos-14 | ||
| target: aarch64 | ||
| os: macos | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - uses: actions/setup-python@v7 | ||
| with: | ||
| python-version: 3.x | ||
| architecture: ${{ matrix.python-target || '' }} | ||
| - name: Build wheels | ||
| uses: PyO3/maturin-action@v1 | ||
| with: | ||
| target: ${{ matrix.target }} | ||
| args: --release --out dist --find-interpreter | ||
| working-directory: packages/python | ||
| manylinux: ${{ matrix.manylinux || '' }} | ||
| - name: Upload wheels | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: wheels-${{ matrix.os }}-${{ matrix.target }} | ||
| path: packages/python/dist | ||
| retention-days: 1 | ||
| node-publish: | ||
| name: Node Publish | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| id-token: write | ||
| needs: | ||
| - changepacks | ||
| - node-build | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/node/package.json') }} | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - uses: oven-sh/setup-bun@v2 | ||
| with: | ||
| bun-version: latest | ||
| - name: Set up Python | ||
| uses: actions/setup-python@v7 | ||
| with: | ||
| python-version: "3.14" | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v10.0.1 | ||
| - name: Install maturin | ||
| run: uv pip install maturin --system | ||
| - name: Install | ||
| uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| toolchain: stable | ||
| - name: Install dependencies | ||
| run: bun install | ||
| - name: Build | ||
| run: bun run build | ||
| working-directory: packages/node | ||
| # - name: create npm dirs | ||
| # run: bunx napi create-npm-dirs | ||
| # working-directory: packages/node | ||
| - name: Download all artifacts | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| path: packages/node/pkg/* | ||
| # npm (not bun) performs the publish, and it needs `registry-url` here: | ||
| # that is what writes the registry line into the job's .npmrc, which is | ||
| # what npm exchanges the Actions OIDC token against. Without it npm has | ||
| # no registry to authenticate to and falls back to an anonymous PUT, | ||
| # which the registry answers with a 404 rather than a 401. | ||
| - uses: actions/setup-node@v7 | ||
| with: | ||
| node-version: '24' | ||
| registry-url: 'https://registry.npmjs.org' | ||
| # Trusted Publishing (OIDC) requires npm >= 11.5.1. Node 24 bundles the | ||
| # 11.x line but not necessarily a new enough patch, so pin it explicitly | ||
| # rather than depending on whichever npm the runner image happens to | ||
| # carry. | ||
| - name: Ensure npm >= 11.5.1 (OIDC floor) | ||
| run: npm install -g 'npm@^11' | ||
| # - name: Move artifacts | ||
| # run: bun run artifacts | ||
| # working-directory: packages/node | ||
| # - name: List packages | ||
| # run: ls -R ./npm | ||
| # working-directory: packages/node | ||
| # Publishes with Trusted Publishing (OIDC): npm exchanges the job's | ||
| # `id-token` for a short-lived registry credential, so no NPM_TOKEN is | ||
| # written to .npmrc. Writing one would actually BREAK this - npm prefers | ||
| # an explicit `_authToken` and never starts the OIDC exchange when it | ||
| # finds one. | ||
| # | ||
| # This requires a trusted publisher registered for `braillify` on | ||
| # npmjs.com pointing at dev-five-git/braillify and this workflow file; | ||
| # without it the registry rejects the exchange. | ||
| - name: Publish | ||
| run: | | ||
| # bun install -g @napi-rs/cli | ||
| bun run build | ||
| # package.json 의 현재 버전이 이미 npm 에 publish 되어 있으면 nothing to do. | ||
| # (버전을 bump 하면 새 버전은 아직 존재하지 않으므로 정상 publish 됨) | ||
| PKG_NAME=$(node -p "require('./package.json').name") | ||
| PKG_VERSION=$(node -p "require('./package.json').version") | ||
| if npm view "$PKG_NAME@$PKG_VERSION" version >/dev/null 2>&1; then | ||
| echo "::notice::$PKG_NAME@$PKG_VERSION is already on npm. Nothing to publish (bump version to release a new one)." | ||
| exit 0 | ||
| fi | ||
| npm publish --access public | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| working-directory: packages/node | ||
| # - name: Upload Asset | ||
| # uses: owjs3901/upload-github-release-asset@main | ||
| # with: | ||
| # upload_url: ${{ fromJson(needs.changepacks.outputs.release_assets_urls)['packages/node/package.json'] }} | ||
| # asset_path: packages/node/pkg/* | ||
| python-publish: | ||
| name: Python Publish | ||
| runs-on: ubuntu-latest | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/python/pyproject.toml') }} | ||
| needs: | ||
| - changepacks | ||
| - python-build | ||
| permissions: | ||
| # Use to sign the release artifacts | ||
| id-token: write | ||
| # Used to upload release artifacts | ||
| contents: write | ||
| # Used to generate artifact attestation | ||
| attestations: write | ||
| steps: | ||
| - uses: actions/download-artifact@v8 | ||
| - name: Generate artifact attestation | ||
| uses: actions/attest-build-provenance@v4 | ||
| with: | ||
| subject-path: "wheels-*/*" | ||
| - name: Publish to PyPI | ||
| uses: PyO3/maturin-action@v1 | ||
| env: | ||
| MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} | ||
| with: | ||
| command: upload | ||
| args: --non-interactive --skip-existing wheels-*/* | ||
| - name: List wheels | ||
| run: ls -R . | ||
| - name: Delete existing release assets (idempotent re-run) | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| UPLOAD_URL: ${{ fromJson(needs.changepacks.outputs.release_assets_urls)['packages/python/pyproject.toml'] }} | ||
| run: | | ||
| # upload_url 형태: https://uploads.github.com/repos/OWNER/REPO/releases/RELEASE_ID/assets{?name,label} | ||
| RELEASE_ID=$(echo "$UPLOAD_URL" | sed -E 's#.*/releases/([0-9]+)/assets.*#\1#') | ||
| REPO="${GITHUB_REPOSITORY}" | ||
| for WHEEL in $(find . -name '*.whl' -type f); do | ||
| NAME=$(basename "$WHEEL") | ||
| ASSET_ID=$(gh api "repos/$REPO/releases/$RELEASE_ID/assets" \ | ||
| --paginate --jq ".[] | select(.name == \"$NAME\") | .id" || true) | ||
| if [ -n "$ASSET_ID" ]; then | ||
| echo "deleting existing asset $NAME (id=$ASSET_ID)" | ||
| gh api -X DELETE "repos/$REPO/releases/assets/$ASSET_ID" || true | ||
| fi | ||
| done | ||
| - name: Upload Asset | ||
| uses: owjs3901/upload-github-release-asset@main | ||
| with: | ||
| upload_url: ${{ fromJson(needs.changepacks.outputs.release_assets_urls)['packages/python/pyproject.toml'] }} | ||
| asset_path: "*/*.whl" | ||
| upload-assets: | ||
| needs: changepacks | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'libs/braillify/Cargo.toml') }} | ||
| permissions: | ||
| contents: write | ||
| id-token: write | ||
| name: Upload Assets for ${{ matrix.platform }} | ||
| runs-on: ${{ matrix.platform }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - platform: ubuntu-22.04 | ||
| os: linux | ||
| target: x86_64-unknown-linux-gnu | ||
| binary_name: braillify-linux-x86_64 | ||
| - platform: windows-2022 | ||
| os: windows | ||
| target: x86_64-pc-windows-msvc | ||
| binary_name: braillify-windows-x86_64.exe | ||
| - platform: macos-14 | ||
| os: macos | ||
| target: x86_64-apple-darwin | ||
| binary_name: braillify-darwin-x86_64 | ||
| - platform: macos-14 | ||
| os: macos | ||
| target: aarch64-apple-darwin | ||
| binary_name: braillify-darwin-arm64 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v7 | ||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| target: ${{ matrix.target }} | ||
| components: clippy, rustfmt | ||
| - name: Build Rust binary | ||
| run: cargo build --release --target ${{ matrix.target }} -p braillify | ||
| - name: Rename binary | ||
| run: mv target/${{ matrix.target }}/release/braillify${{ matrix.os == 'windows' && '.exe' || '' }} ${{ matrix.binary_name }} | ||
| - name: Delete existing release asset (idempotent re-run) | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| UPLOAD_URL: ${{ fromJson(needs.changepacks.outputs.release_assets_urls)['libs/braillify/Cargo.toml'] }} | ||
| NAME: ${{ matrix.binary_name }} | ||
| shell: bash | ||
| run: | | ||
| RELEASE_ID=$(echo "$UPLOAD_URL" | sed -E 's#.*/releases/([0-9]+)/assets.*#\1#') | ||
| REPO="${GITHUB_REPOSITORY}" | ||
| ASSET_ID=$(gh api "repos/$REPO/releases/$RELEASE_ID/assets" \ | ||
| --paginate --jq ".[] | select(.name == \"$NAME\") | .id" || true) | ||
| if [ -n "$ASSET_ID" ]; then | ||
| echo "deleting existing asset $NAME (id=$ASSET_ID)" | ||
| gh api -X DELETE "repos/$REPO/releases/assets/$ASSET_ID" || true | ||
| fi | ||
| - name: Upload Asset | ||
| uses: owjs3901/upload-github-release-asset@main | ||
| with: | ||
| upload_url: ${{ fromJson(needs.changepacks.outputs.release_assets_urls)['libs/braillify/Cargo.toml'] }} | ||
| asset_path: ${{ matrix.binary_name }} | ||
| cargo-publish: | ||
| name: Cargo Publish | ||
| runs-on: ubuntu-latest | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'libs/braillify') }} | ||
| needs: | ||
| - changepacks | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Publish to Cargo | ||
| run: | | ||
| # Cargo.toml 의 현재 버전이 이미 crates.io 에 publish 되어 있으면 nothing to do. | ||
| # (버전을 bump 하면 새 버전은 아직 존재하지 않으므로 정상 publish 됨) | ||
| VERSION=$(cargo pkgid -p braillify | sed -E 's/.*[#@]([0-9]+\.[0-9]+\.[0-9]+).*/\1/') | ||
| if curl -fsSL "https://crates.io/api/v1/crates/braillify/$VERSION" \ | ||
| -H "User-Agent: braillify-ci" >/dev/null 2>&1; then | ||
| echo "::notice::braillify@$VERSION is already on crates.io. Nothing to publish (bump version to release a new one)." | ||
| exit 0 | ||
| fi | ||
| cargo publish -p braillify | ||
| env: | ||
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | ||
| winget-publish: | ||
| name: Winget Publish | ||
| runs-on: windows-2022 | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'libs/braillify/Cargo.toml') }} | ||
| needs: | ||
| - changepacks | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| target: x86_64-pc-windows-msvc | ||
| components: clippy, rustfmt | ||
| - name: Build Rust binary | ||
| run: cargo build --release --target x86_64-pc-windows-msvc -p braillify | ||
| - name: Extract version | ||
| run: | | ||
| echo "version=$(cargo pkgid -p braillify | sed -E 's/.*#([0-9]+\.[0-9]+\.[0-9]+).*/\1/')" >> $GITHUB_OUTPUT | ||
| id: version | ||
| - name: Winget Publish | ||
| uses: vedantmgoyal9/winget-releaser@v2 | ||
| continue-on-error: true | ||
| with: | ||
| identifier: Braillify.Braillify | ||
| installers-regex: '\.exe$' # Only .exe files | ||
| token: ${{ secrets.WINGET_TOKEN }} | ||
| version: ${{ steps.version.outputs.version }} | ||
| # dotnet | ||
| dotnet-build: | ||
| name: .NET Build - ${{ matrix.rid }} | ||
| runs-on: ${{ matrix.runner }} | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/dotnet') }} | ||
| needs: | ||
| - test | ||
| - changepacks | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| # Windows | ||
| - runner: windows-latest | ||
| target: x86_64-pc-windows-msvc | ||
| rid: win-x64 | ||
| lib_name: braillify_native.dll | ||
| - runner: windows-latest | ||
| target: i686-pc-windows-msvc | ||
| rid: win-x86 | ||
| lib_name: braillify_native.dll | ||
| - runner: windows-latest | ||
| target: aarch64-pc-windows-msvc | ||
| rid: win-arm64 | ||
| lib_name: braillify_native.dll | ||
| # Linux | ||
| - runner: ubuntu-22.04 | ||
| target: x86_64-unknown-linux-gnu | ||
| rid: linux-x64 | ||
| lib_name: libbraillify_native.so | ||
| - runner: ubuntu-22.04 | ||
| target: aarch64-unknown-linux-gnu | ||
| rid: linux-arm64 | ||
| lib_name: libbraillify_native.so | ||
| # macOS | ||
| - runner: macos-14 | ||
| target: x86_64-apple-darwin | ||
| rid: osx-x64 | ||
| lib_name: libbraillify_native.dylib | ||
| - runner: macos-14 | ||
| target: aarch64-apple-darwin | ||
| rid: osx-arm64 | ||
| lib_name: libbraillify_native.dylib | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| target: ${{ matrix.target }} | ||
| - name: Install cross-compilation tools (Linux ARM64) | ||
| if: matrix.rid == 'linux-arm64' | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y gcc-aarch64-linux-gnu | ||
| - name: Build native library | ||
| run: cargo build --release --target ${{ matrix.target }} -p dotnet | ||
| env: | ||
| CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc | ||
| - name: Upload artifact | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: dotnet-native-${{ matrix.rid }} | ||
| path: target/${{ matrix.target }}/release/${{ matrix.lib_name }} | ||
| if-no-files-found: error | ||
| retention-days: 1 | ||
| dotnet-publish: | ||
| name: .NET Publish | ||
| runs-on: ubuntu-latest | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/dotnet') }} | ||
| needs: | ||
| - changepacks | ||
| - dotnet-build | ||
| permissions: | ||
| contents: write | ||
| id-token: write | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Setup .NET | ||
| uses: actions/setup-dotnet@v6 | ||
| with: | ||
| dotnet-version: "9.0.x" | ||
| - name: Download all native artifacts | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| path: native-artifacts | ||
| pattern: dotnet-native-* | ||
| - name: Prepare native libraries | ||
| run: | | ||
| # Create runtimes directories | ||
| mkdir -p packages/dotnet/BraillifyNet/runtimes/win-x64/native | ||
| mkdir -p packages/dotnet/BraillifyNet/runtimes/win-x86/native | ||
| mkdir -p packages/dotnet/BraillifyNet/runtimes/win-arm64/native | ||
| mkdir -p packages/dotnet/BraillifyNet/runtimes/linux-x64/native | ||
| mkdir -p packages/dotnet/BraillifyNet/runtimes/linux-arm64/native | ||
| mkdir -p packages/dotnet/BraillifyNet/runtimes/osx-x64/native | ||
| mkdir -p packages/dotnet/BraillifyNet/runtimes/osx-arm64/native | ||
| # Copy native libraries to runtimes folders | ||
| cp native-artifacts/dotnet-native-win-x64/* packages/dotnet/BraillifyNet/runtimes/win-x64/native/ | ||
| cp native-artifacts/dotnet-native-win-x86/* packages/dotnet/BraillifyNet/runtimes/win-x86/native/ | ||
| cp native-artifacts/dotnet-native-win-arm64/* packages/dotnet/BraillifyNet/runtimes/win-arm64/native/ | ||
| cp native-artifacts/dotnet-native-linux-x64/* packages/dotnet/BraillifyNet/runtimes/linux-x64/native/ | ||
| cp native-artifacts/dotnet-native-linux-arm64/* packages/dotnet/BraillifyNet/runtimes/linux-arm64/native/ | ||
| cp native-artifacts/dotnet-native-osx-x64/* packages/dotnet/BraillifyNet/runtimes/osx-x64/native/ | ||
| cp native-artifacts/dotnet-native-osx-arm64/* packages/dotnet/BraillifyNet/runtimes/osx-arm64/native/ | ||
| # List for verification | ||
| echo "=== Native libraries ===" | ||
| find packages/dotnet/BraillifyNet/runtimes -type f | ||
| - name: Build and Pack BraillifyNet | ||
| run: dotnet pack -c Release -o nupkg | ||
| working-directory: packages/dotnet/BraillifyNet | ||
| - name: Build and Pack Braillify CLI | ||
| run: dotnet pack -c Release -o nupkg | ||
| working-directory: packages/dotnet/Braillify | ||
| - name: List packages | ||
| run: | | ||
| echo "=== NuGet packages ===" | ||
| find packages/dotnet -name "*.nupkg" -type f | ||
| - name: Publish to NuGet | ||
| run: | | ||
| dotnet nuget push packages/dotnet/BraillifyNet/nupkg/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate | ||
| dotnet nuget push packages/dotnet/Braillify/nupkg/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate | ||
| - name: Upload NuGet packages as artifacts | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: nuget-packages | ||
| path: packages/dotnet/**/nupkg/*.nupkg | ||
| retention-days: 1 | ||
| # c | ||
| c-build: | ||
| name: C Build - ${{ matrix.rid }} | ||
| runs-on: ${{ matrix.runner }} | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/c/Cargo.toml') }} | ||
| needs: | ||
| - test | ||
| - changepacks | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - runner: ubuntu-22.04 | ||
| target: x86_64-unknown-linux-gnu | ||
| rid: linux-x64 | ||
| archive: braillify-c-linux-x64.tar.gz | ||
| - runner: ubuntu-22.04 | ||
| target: aarch64-unknown-linux-gnu | ||
| rid: linux-arm64 | ||
| archive: braillify-c-linux-arm64.tar.gz | ||
| - runner: macos-14 | ||
| target: x86_64-apple-darwin | ||
| rid: macos-x64 | ||
| archive: braillify-c-macos-x64.tar.gz | ||
| - runner: macos-14 | ||
| target: aarch64-apple-darwin | ||
| rid: macos-arm64 | ||
| archive: braillify-c-macos-arm64.tar.gz | ||
| - runner: windows-2022 | ||
| target: x86_64-pc-windows-msvc | ||
| rid: windows-x64 | ||
| archive: braillify-c-windows-x64.tar.gz | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| target: ${{ matrix.target }} | ||
| - name: Set up MSVC | ||
| if: runner.os == 'Windows' | ||
| uses: ilammy/msvc-dev-cmd@v1 | ||
| - name: Install cross-compilation tools (Linux ARM64) | ||
| if: matrix.rid == 'linux-arm64' | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y gcc-aarch64-linux-gnu | ||
| - name: Build C libraries | ||
| run: cargo build --release --target ${{ matrix.target }} -p braillify-c | ||
| env: | ||
| CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc | ||
| - name: Bundle libraries and header | ||
| shell: bash | ||
| env: | ||
| TARGET: ${{ matrix.target }} | ||
| RID: ${{ matrix.rid }} | ||
| ARCHIVE: ${{ matrix.archive }} | ||
| run: | | ||
| mkdir -p "dist/$RID/include" "dist/$RID/lib" | ||
| cp packages/c/include/braillify.h "dist/$RID/include/" | ||
| cp packages/c/README.md "dist/$RID/" | ||
| case "$RUNNER_OS" in | ||
| Linux) | ||
| cp "target/$TARGET/release/libbraillify_c.a" "dist/$RID/lib/" | ||
| cp "target/$TARGET/release/libbraillify_c.so" "dist/$RID/lib/" | ||
| ;; | ||
| macOS) | ||
| cp "target/$TARGET/release/libbraillify_c.a" "dist/$RID/lib/" | ||
| cp "target/$TARGET/release/libbraillify_c.dylib" "dist/$RID/lib/" | ||
| ;; | ||
| Windows) | ||
| cp "target/$TARGET/release/braillify_c.dll" "dist/$RID/lib/" | ||
| cp "target/$TARGET/release/braillify_c.dll.lib" "dist/$RID/lib/" | ||
| cp "target/$TARGET/release/braillify_c.lib" "dist/$RID/lib/" | ||
| ;; | ||
| esac | ||
| tar -C dist -czf "$ARCHIVE" "$RID" | ||
| - name: Upload artifact | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: c-bindings-${{ matrix.rid }} | ||
| path: ${{ matrix.archive }} | ||
| if-no-files-found: error | ||
| retention-days: 1 | ||
| c-publish: | ||
| name: C Publish | ||
| runs-on: ubuntu-latest | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/c/Cargo.toml') }} | ||
| needs: | ||
| - changepacks | ||
| - c-build | ||
| permissions: | ||
| contents: write | ||
| id-token: write | ||
| attestations: write | ||
| steps: | ||
| - name: Download C artifacts | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| pattern: c-bindings-* | ||
| path: c-artifacts | ||
| merge-multiple: true | ||
| - name: Generate artifact attestation | ||
| uses: actions/attest-build-provenance@v4 | ||
| with: | ||
| subject-path: "c-artifacts/*.tar.gz" | ||
| - name: Delete existing release assets (idempotent re-run) | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| UPLOAD_URL: ${{ fromJson(needs.changepacks.outputs.release_assets_urls)['packages/c/Cargo.toml'] }} | ||
| run: | | ||
| RELEASE_ID=$(echo "$UPLOAD_URL" | sed -E 's#.*/releases/([0-9]+)/assets.*#\1#') | ||
| REPO="${GITHUB_REPOSITORY}" | ||
| for ARCHIVE in c-artifacts/*.tar.gz; do | ||
| NAME=$(basename "$ARCHIVE") | ||
| ASSET_ID=$(gh api "repos/$REPO/releases/$RELEASE_ID/assets" \ | ||
| --paginate --jq ".[] | select(.name == \"$NAME\") | .id" || true) | ||
| if [ -n "$ASSET_ID" ]; then | ||
| gh api -X DELETE "repos/$REPO/releases/assets/$ASSET_ID" || true | ||
| fi | ||
| done | ||
| - name: Upload release assets | ||
| uses: owjs3901/upload-github-release-asset@main | ||
| with: | ||
| upload_url: ${{ fromJson(needs.changepacks.outputs.release_assets_urls)['packages/c/Cargo.toml'] }} | ||
| asset_path: "c-artifacts/*.tar.gz" | ||
| # ruby | ||
| ruby-build: | ||
| name: Ruby Build - ${{ matrix.platform }} | ||
| runs-on: ubuntu-latest | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/ruby/Cargo.toml') }} | ||
| needs: | ||
| - test | ||
| - dotnet-test | ||
| - ruby-test | ||
| - changepacks | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| platform: | ||
| - x86_64-linux | ||
| - aarch64-linux | ||
| - x86_64-darwin | ||
| - arm64-darwin | ||
| - x64-mingw-ucrt | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: "3.4" | ||
| bundler-cache: true | ||
| working-directory: packages/ruby | ||
| - uses: oxidize-rb/actions/cross-gem@v1 | ||
| id: cross-gem | ||
| with: | ||
| platform: ${{ matrix.platform }} | ||
| ruby-versions: "3.1,3.2,3.3,3.4" | ||
| working-directory: packages/ruby | ||
| - name: Upload artifact | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: ruby-gem-${{ matrix.platform }} | ||
| path: ${{ steps.cross-gem.outputs.gem-path }} | ||
| if-no-files-found: error | ||
| ruby-publish: | ||
| name: Ruby Publish | ||
| runs-on: ubuntu-latest | ||
| if: ${{ contains(needs.changepacks.outputs.changepacks, 'packages/ruby/Cargo.toml') }} | ||
| needs: | ||
| - changepacks | ||
| - ruby-build | ||
| permissions: | ||
| contents: write | ||
| id-token: write | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: "3.4" | ||
| - name: Download platform gems | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| pattern: ruby-gem-* | ||
| path: gems | ||
| - name: Build source gem | ||
| run: | | ||
| gem build braillify.gemspec | ||
| mkdir -p ../../gems/source | ||
| mv braillify-*.gem ../../gems/source/ | ||
| working-directory: packages/ruby | ||
| - name: Publish | ||
| env: | ||
| GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }} | ||
| run: | | ||
| VERSION=$(ruby -e 'print File.read("packages/ruby/Cargo.toml")[/^version = "([^"]+)"/, 1]') | ||
| EXISTING=$(curl -fsSL "https://rubygems.org/api/v1/versions/braillify.json" || echo "[]") | ||
| for GEM in $(find gems -name '*.gem' -type f); do | ||
| BASE=$(basename "$GEM" .gem) | ||
| PLATFORM=${BASE#braillify-$VERSION} | ||
| PLATFORM=${PLATFORM#-} | ||
| PLATFORM=${PLATFORM:-ruby} | ||
| if echo "$EXISTING" | jq -e --arg v "$VERSION" --arg p "$PLATFORM" \ | ||
| 'any(.[]; .number == $v and .platform == $p)' > /dev/null; then | ||
| echo "::notice::braillify-$VERSION ($PLATFORM) is already on rubygems.org. Skipping." | ||
| continue | ||
| fi | ||
| gem push "$GEM" | ||
| done | ||
| # go | ||
| go-test: | ||
| name: Go Test - ${{ matrix.platform }} | ||
| runs-on: ${{ matrix.runner }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| # Windows x64 | ||
| - runner: windows-latest | ||
| target: x86_64-pc-windows-gnu | ||
| platform: windows-amd64 | ||
| # Linux x64 | ||
| - runner: ubuntu-latest | ||
| target: x86_64-unknown-linux-gnu | ||
| platform: linux-amd64 | ||
| # Linux ARM64 | ||
| # go test 는 네이티브로 돌기 때문에 러너 아키텍처가 target 과 같아야 한다. | ||
| # amd64 러너에서 크로스 빌드하면 cgo 가 libs/linux-amd64 를 찾다가 링크에 실패한다. | ||
| - runner: ubuntu-24.04-arm | ||
| target: aarch64-unknown-linux-gnu | ||
| platform: linux-arm64 | ||
| # macOS ARM64 | ||
| - runner: macos-14 | ||
| target: aarch64-apple-darwin | ||
| platform: darwin-arm64 | ||
| # macOS x64 | ||
| - runner: macos-15-intel | ||
| target: x86_64-apple-darwin | ||
| platform: darwin-amd64 | ||
| steps: | ||
| # pull_request_target에서도 PR 코드를 체크아웃해 테스트한다. | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| allow-unsafe-pr-checkout: true | ||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| target: ${{ matrix.target }} | ||
| - uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: stable | ||
| - name: Build native library | ||
| run: cargo build --release --target ${{ matrix.target }} -p braillify-go | ||
| - name: Copy native library | ||
| run: | | ||
| mkdir -p packages/go/libs/${{ matrix.platform }} | ||
| cp target/${{ matrix.target }}/release/libbraillify_go.a packages/go/libs/${{ matrix.platform }}/ | ||
| shell: bash | ||
| - name: Test | ||
| run: go test -v ./... | ||
| working-directory: packages/go | ||
| go-build: | ||
| name: Go Build - ${{ matrix.platform }} | ||
| runs-on: ${{ matrix.runner }} | ||
| needs: | ||
| - test | ||
| - changepacks | ||
| if: >- | ||
| github.event_name == 'push' && | ||
| github.ref == 'refs/heads/main' && | ||
| contains(needs.changepacks.outputs.changepacks, 'packages/go/Cargo.toml') | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| # Windows x64 | ||
| - runner: windows-latest | ||
| target: x86_64-pc-windows-gnu | ||
| platform: windows-amd64 | ||
| # Linux x64 | ||
| - runner: ubuntu-latest | ||
| target: x86_64-unknown-linux-gnu | ||
| platform: linux-amd64 | ||
| # Linux ARM64 | ||
| - runner: ubuntu-latest | ||
| target: aarch64-unknown-linux-gnu | ||
| platform: linux-arm64 | ||
| # macOS ARM64 | ||
| - runner: macos-14 | ||
| target: aarch64-apple-darwin | ||
| platform: darwin-arm64 | ||
| # macOS x64 | ||
| - runner: macos-15-intel | ||
| target: x86_64-apple-darwin | ||
| platform: darwin-amd64 | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| target: ${{ matrix.target }} | ||
| - name: Install cross-compilation tools (Linux ARM64) | ||
| if: matrix.platform == 'linux-arm64' | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y gcc-aarch64-linux-gnu | ||
| - name: Build native library | ||
| run: cargo build --release --target ${{ matrix.target }} -p braillify-go | ||
| env: | ||
| CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc | ||
| - name: Upload artifact | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: go-lib-${{ matrix.platform }} | ||
| path: target/${{ matrix.target }}/release/libbraillify_go.a | ||
| if-no-files-found: error | ||
| go-publish: | ||
| name: Go Publish | ||
| runs-on: ubuntu-latest | ||
| needs: | ||
| - changepacks | ||
| - go-build | ||
| if: >- | ||
| github.event_name == 'push' && | ||
| github.ref == 'refs/heads/main' && | ||
| contains(needs.changepacks.outputs.changepacks, 'packages/go/Cargo.toml') | ||
| permissions: | ||
| contents: write | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| fetch-depth: 0 | ||
| - name: Extract version | ||
| id: version | ||
| working-directory: packages/go | ||
| run: | | ||
| v=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([0-9.]+)".*/\1/') | ||
| echo "version=$v" >> $GITHUB_OUTPUT | ||
| echo "Resolved version: $v" | ||
| - name: Download platform libs | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| pattern: go-lib-* | ||
| path: libs-raw | ||
| merge-multiple: false | ||
| - name: Place libs | ||
| run: | | ||
| for d in libs-raw/go-lib-*; do | ||
| [ -d "$d" ] || continue | ||
| plat="${d##*go-lib-}" | ||
| mkdir -p "packages/go/libs/$plat" | ||
| cp "$d/libbraillify_go.a" "packages/go/libs/$plat/" | ||
| done | ||
| echo "=== Placed libs ===" | ||
| find packages/go/libs -type f | ||
| - name: Commit libs + new module tag | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
| TAG="packages/go/v${{ steps.version.outputs.version }}" | ||
| if git rev-parse "$TAG" >/dev/null 2>&1; then | ||
| echo "Tag $TAG already exists — skip (no force-move)." | ||
| exit 0 | ||
| fi | ||
| git add -f packages/go/libs/ | ||
| git commit -m "chore(go): publish static libs v${{ steps.version.outputs.version }} [skip ci]" | ||
| git pull --rebase origin main | ||
| git tag "$TAG" | ||
| git push origin main | ||
| git push origin "$TAG" | ||
| # jvm | ||
| # JVM 릴리스 job은 다른 바인딩 게시 흐름과 섞이지 않도록 파일 맨 아래에 둔다. | ||
| jvm-native-build: | ||
| name: JVM Native Build - ${{ matrix.native-target }} | ||
| runs-on: ${{ matrix.runner }} | ||
| if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && contains(needs.changepacks.outputs.changepacks, 'packages/jvm/build.gradle.kts') }} | ||
| needs: | ||
| - changepacks | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - runner: ubuntu-24.04 | ||
| native-target: linux-x86_64 | ||
| rust-target: x86_64-unknown-linux-gnu | ||
| library-name: libbraillify_jvm.so | ||
| glibc: "2.17" | ||
| - runner: ubuntu-24.04 | ||
| native-target: linux-aarch64 | ||
| rust-target: aarch64-unknown-linux-gnu | ||
| library-name: libbraillify_jvm.so | ||
| glibc: "2.17" | ||
| - runner: macos-15-intel | ||
| native-target: macos-x86_64 | ||
| rust-target: x86_64-apple-darwin | ||
| library-name: libbraillify_jvm.dylib | ||
| deployment-target: "10.13" | ||
| - runner: macos-15 | ||
| native-target: macos-aarch64 | ||
| rust-target: aarch64-apple-darwin | ||
| library-name: libbraillify_jvm.dylib | ||
| deployment-target: "11.0" | ||
| - runner: windows-2022 | ||
| native-target: windows-x86_64 | ||
| rust-target: x86_64-pc-windows-msvc | ||
| library-name: braillify_jvm.dll | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Setup Rust | ||
| uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| target: ${{ matrix.rust-target }} | ||
| - name: Set up MSVC | ||
| if: runner.os == 'Windows' | ||
| uses: ilammy/msvc-dev-cmd@v1 | ||
| - name: Set up Zig | ||
| if: matrix.glibc | ||
| uses: mlugg/setup-zig@v2 | ||
| with: | ||
| version: 0.14.1 | ||
| - name: Install cargo-zigbuild | ||
| if: matrix.glibc | ||
| uses: taiki-e/install-action@v2 | ||
| env: | ||
| GITHUB_TOKEN: ${{ github.token }} | ||
| with: | ||
| tool: cargo-zigbuild | ||
| - name: Build Linux native library with glibc 2.17 compatibility | ||
| if: matrix.glibc | ||
| run: cargo zigbuild --release -p braillify-jvm --target ${{ matrix.rust-target }}.${{ matrix.glibc }} | ||
| - name: Build macOS or Windows native library | ||
| if: ${{ !matrix.glibc }} | ||
| run: cargo build --release -p braillify-jvm --target ${{ matrix.rust-target }} | ||
| env: | ||
| MACOSX_DEPLOYMENT_TARGET: ${{ matrix.deployment-target }} | ||
| - name: Inspect Linux ABI and dependencies | ||
| if: runner.os == 'Linux' | ||
| shell: bash | ||
| env: | ||
| LIBRARY: target/${{ matrix.rust-target }}/release/${{ matrix.library-name }} | ||
| run: | | ||
| readelf -d "$LIBRARY" | ||
| readelf --version-info "$LIBRARY" | ||
| if readelf --version-info "$LIBRARY" \ | ||
| | grep -oE 'GLIBC_[0-9]+\.[0-9]+' \ | ||
| | sort -Vu \ | ||
| | awk -F'[_.]' '$2 > 2 || ($2 == 2 && $3 > 17) { found = 1 } END { exit !found }'; then | ||
| echo "::error::$LIBRARY requires a GLIBC symbol newer than 2.17" | ||
| exit 1 | ||
| fi | ||
| if [ "${{ matrix.native-target }}" = "linux-x86_64" ]; then | ||
| ldd "$LIBRARY" | ||
| fi | ||
| - name: Inspect macOS dependencies | ||
| if: runner.os == 'macOS' | ||
| run: otool -L target/${{ matrix.rust-target }}/release/${{ matrix.library-name }} | ||
| - name: Inspect Windows dependencies | ||
| if: runner.os == 'Windows' | ||
| run: dumpbin /DEPENDENTS target/${{ matrix.rust-target }}/release/${{ matrix.library-name }} | ||
| - name: Upload native library | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: jvm-native-${{ matrix.native-target }} | ||
| path: target/${{ matrix.rust-target }}/release/${{ matrix.library-name }} | ||
| if-no-files-found: error | ||
| retention-days: 1 | ||
| jvm-jar: | ||
| name: JVM Fat JAR | ||
| runs-on: ubuntu-latest | ||
| if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && contains(needs.changepacks.outputs.changepacks, 'packages/jvm/build.gradle.kts') }} | ||
| needs: | ||
| - changepacks | ||
| - jvm-native-build | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Validate Gradle Wrapper | ||
| uses: gradle/actions/wrapper-validation@v4 | ||
| - name: Set up JDK 17 | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| distribution: temurin | ||
| java-version: "17" | ||
| - name: Setup Gradle | ||
| uses: gradle/actions/setup-gradle@v4 | ||
| - name: Download native libraries | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| pattern: jvm-native-* | ||
| path: native-artifacts | ||
| - name: Stage native libraries | ||
| shell: bash | ||
| run: | | ||
| stage_native() { | ||
| local native_target="$1" | ||
| local library_name="$2" | ||
| local library | ||
| library=$(find "native-artifacts/jvm-native-$native_target" -type f -name "$library_name" -print -quit) | ||
| if [ -z "$library" ]; then | ||
| echo "::error::Missing $library_name for $native_target" | ||
| exit 1 | ||
| fi | ||
| ./packages/jvm/gradlew -p packages/jvm stageNativeLibrary \ | ||
| -PnativeTarget="$native_target" \ | ||
| -PnativeLibrary="$GITHUB_WORKSPACE/$library" \ | ||
| --no-daemon | ||
| } | ||
| stage_native linux-x86_64 libbraillify_jvm.so | ||
| stage_native linux-aarch64 libbraillify_jvm.so | ||
| stage_native macos-x86_64 libbraillify_jvm.dylib | ||
| stage_native macos-aarch64 libbraillify_jvm.dylib | ||
| stage_native windows-x86_64 braillify_jvm.dll | ||
| - name: Assemble fat JAR | ||
| run: ./gradlew assembleJvmJar --no-daemon | ||
| working-directory: packages/jvm | ||
| - name: Verify fat JAR | ||
| shell: bash | ||
| run: | | ||
| JAR=$(find packages/jvm/build/libs -maxdepth 1 -type f -name '*.jar' ! -name '*-sources.jar' ! -name '*-javadoc.jar' -print -quit) | ||
| if [ -z "$JAR" ]; then | ||
| echo "::error::JVM binary JAR was not created" | ||
| exit 1 | ||
| fi | ||
| jar tf "$JAR" | sort > jvm-jar-entries.txt | ||
| for entry in \ | ||
| META-INF/native/linux-x86_64/libbraillify_jvm.so \ | ||
| META-INF/native/linux-aarch64/libbraillify_jvm.so \ | ||
| META-INF/native/macos-x86_64/libbraillify_jvm.dylib \ | ||
| META-INF/native/macos-aarch64/libbraillify_jvm.dylib \ | ||
| META-INF/native/windows-x86_64/braillify_jvm.dll; do | ||
| grep -Fx "$entry" jvm-jar-entries.txt >/dev/null || { | ||
| echo "::error::Missing JAR entry: $entry" | ||
| exit 1 | ||
| } | ||
| done | ||
| if find packages/jvm/build/libs -maxdepth 1 -type f -name '*-debug*' -print -quit | grep -q .; then | ||
| echo "::error::Debug artifact found in JVM release output" | ||
| exit 1 | ||
| fi | ||
| sha256sum "$JAR" | ||
| - name: Upload fat JAR | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: jvm-fat-jar | ||
| path: packages/jvm/build/libs/*.jar | ||
| if-no-files-found: error | ||
| retention-days: 1 | ||
| jvm-consumer-test: | ||
| name: JVM JAR Consumer - ${{ matrix.native-target }} / Java ${{ matrix.java-version }} | ||
| runs-on: ${{ matrix.runner }} | ||
| if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && contains(needs.changepacks.outputs.changepacks, 'packages/jvm/build.gradle.kts') }} | ||
| needs: | ||
| - changepacks | ||
| - jvm-jar | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - runner: ubuntu-24.04 | ||
| native-target: linux-x86_64 | ||
| java-version: "17" | ||
| path-separator: ":" | ||
| - runner: ubuntu-24.04-arm | ||
| native-target: linux-aarch64 | ||
| java-version: "17" | ||
| path-separator: ":" | ||
| - runner: macos-15-intel | ||
| native-target: macos-x86_64 | ||
| java-version: "17" | ||
| path-separator: ":" | ||
| - runner: macos-15 | ||
| native-target: macos-aarch64 | ||
| java-version: "17" | ||
| path-separator: ":" | ||
| - runner: windows-2022 | ||
| native-target: windows-x86_64 | ||
| java-version: "17" | ||
| path-separator: ";" | ||
| - runner: ubuntu-24.04 | ||
| native-target: linux-x86_64 | ||
| java-version: "8" | ||
| path-separator: ":" | ||
| - runner: ubuntu-24.04 | ||
| native-target: linux-x86_64 | ||
| java-version: "25" | ||
| path-separator: ":" | ||
| java-options: --enable-native-access=ALL-UNNAMED | ||
| steps: | ||
| - name: Set up Java ${{ matrix.java-version }} | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| distribution: temurin | ||
| java-version: ${{ matrix.java-version }} | ||
| - name: Download fat JAR | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| name: jvm-fat-jar | ||
| path: jvm-dist | ||
| - name: Compile and run external consumer | ||
| shell: bash | ||
| run: | | ||
| JAR=$(find jvm-dist -maxdepth 1 -type f -name '*.jar' ! -name '*-sources.jar' ! -name '*-javadoc.jar' -print -quit) | ||
| if [ -z "$JAR" ]; then | ||
| echo "::error::JVM binary JAR artifact is missing" | ||
| exit 1 | ||
| fi | ||
| if [ "$RUNNER_OS" = "Windows" ]; then | ||
| JAR=$(cygpath -w "$JAR") | ||
| fi | ||
| printf '%s\n' \ | ||
| 'import io.github.kdyann.braillify.Braillify;' \ | ||
| 'public final class Consumer {' \ | ||
| ' public static void main(String[] args) {' \ | ||
| ' byte[] encoded = Braillify.encode("안녕하세요");' \ | ||
| ' String unicode = Braillify.translateToUnicode("안녕하세요");' \ | ||
| ' String font = Braillify.translateToBrailleFont("안녕하세요");' \ | ||
| ' if (encoded.length == 0 || unicode.isEmpty() || font.isEmpty()) {' \ | ||
| ' throw new AssertionError("Braillify returned an empty result");' \ | ||
| ' }' \ | ||
| ' for (int i = 0; i < unicode.length(); i++) {' \ | ||
| ' char cell = unicode.charAt(i);' \ | ||
| ' if (cell < 0x2800 || cell > 0x28ff) {' \ | ||
| ' throw new AssertionError("Non-braille Unicode result");' \ | ||
| ' }' \ | ||
| ' }' \ | ||
| ' }' \ | ||
| '}' > Consumer.java | ||
| javac -cp "$JAR" Consumer.java | ||
| java ${{ matrix.java-options }} -cp "$JAR${{ matrix.path-separator }}." Consumer | ||
| - name: Compile and run Kotlin consumer | ||
| if: matrix.native-target == 'linux-x86_64' && matrix.java-version == '17' | ||
| shell: bash | ||
| run: | | ||
| JAR=$(find jvm-dist -maxdepth 1 -type f -name '*.jar' ! -name '*-sources.jar' ! -name '*-javadoc.jar' -print -quit) | ||
| printf '%s\n' \ | ||
| 'import io.github.kdyann.braillify.Braillify' \ | ||
| 'fun main() {' \ | ||
| ' val encoded = Braillify.encode("안녕하세요")' \ | ||
| ' val unicode = Braillify.translateToUnicode("안녕하세요")' \ | ||
| ' val font = Braillify.translateToBrailleFont("안녕하세요")' \ | ||
| ' check(encoded.isNotEmpty() && unicode.isNotEmpty() && font.isNotEmpty())' \ | ||
| '}' > Consumer.kt | ||
| kotlinc -jvm-target 1.8 -cp "$JAR" Consumer.kt -include-runtime -d consumer-kotlin.jar | ||
| java -cp "$JAR:consumer-kotlin.jar" ConsumerKt | ||
| jvm-publish: | ||
| name: JVM Publish to Maven Central | ||
| runs-on: ubuntu-latest | ||
| if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && contains(needs.changepacks.outputs.changepacks, 'packages/jvm/build.gradle.kts') }} | ||
| needs: | ||
| - changepacks | ||
| - jvm-native-build | ||
| - jvm-consumer-test | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| attestations: write | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Validate Gradle Wrapper | ||
| uses: gradle/actions/wrapper-validation@v4 | ||
| - name: Set up JDK 17 | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| distribution: temurin | ||
| java-version: "17" | ||
| - name: Setup Gradle | ||
| uses: gradle/actions/setup-gradle@v4 | ||
| - name: Download native libraries | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| pattern: jvm-native-* | ||
| path: native-artifacts | ||
| - name: Stage native libraries | ||
| shell: bash | ||
| run: | | ||
| stage_native() { | ||
| local native_target="$1" | ||
| local library_name="$2" | ||
| local library | ||
| library=$(find "native-artifacts/jvm-native-$native_target" -type f -name "$library_name" -print -quit) | ||
| if [ -z "$library" ]; then | ||
| echo "::error::Missing $library_name for $native_target" | ||
| exit 1 | ||
| fi | ||
| ./packages/jvm/gradlew -p packages/jvm stageNativeLibrary \ | ||
| -PnativeTarget="$native_target" \ | ||
| -PnativeLibrary="$GITHUB_WORKSPACE/$library" \ | ||
| --no-daemon | ||
| } | ||
| stage_native linux-x86_64 libbraillify_jvm.so | ||
| stage_native linux-aarch64 libbraillify_jvm.so | ||
| stage_native macos-x86_64 libbraillify_jvm.dylib | ||
| stage_native macos-aarch64 libbraillify_jvm.dylib | ||
| stage_native windows-x86_64 braillify_jvm.dll | ||
| - name: Check whether the JVM release already exists | ||
| id: jvm-release | ||
| shell: bash | ||
| run: | | ||
| VERSION=$(./gradlew properties --no-daemon --console=plain -q | sed -n 's/^version: //p' | head -1) | ||
| if [ -z "$VERSION" ]; then | ||
| echo "::error::Could not resolve the JVM publication version" | ||
| exit 1 | ||
| fi | ||
| POM_URL="https://repo1.maven.org/maven2/io/github/kdyann/braillify/$VERSION/braillify-$VERSION.pom" | ||
| if curl -fsIL "$POM_URL" >/dev/null; then | ||
| echo "::notice::io.github.kdyann:braillify:$VERSION is already on Maven Central. Nothing to publish." | ||
| echo "exists=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "exists=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| working-directory: packages/jvm | ||
| - name: Create signed Maven Central bundle | ||
| if: steps.jvm-release.outputs.exists != 'true' | ||
| run: ./gradlew createCentralBundle --no-daemon | ||
| working-directory: packages/jvm | ||
| env: | ||
| MAVEN_SIGNING_KEY: ${{ secrets.MAVEN_SIGNING_KEY }} | ||
| MAVEN_SIGNING_PASSWORD: ${{ secrets.MAVEN_SIGNING_PASSWORD }} | ||
| - name: Verify Maven Central bundle | ||
| if: steps.jvm-release.outputs.exists != 'true' | ||
| shell: bash | ||
| run: | | ||
| test -s packages/jvm/build/central/central-bundle.zip | ||
| unzip -l packages/jvm/build/central/central-bundle.zip | ||
| unzip -Z1 packages/jvm/build/central/central-bundle.zip > central-bundle-entries.txt | ||
| for suffix in .jar .pom -sources.jar -javadoc.jar .asc .md5 .sha1; do | ||
| grep -F -- "$suffix" central-bundle-entries.txt >/dev/null || { | ||
| echo "::error::Central bundle is missing an artifact ending in $suffix" | ||
| exit 1 | ||
| } | ||
| done | ||
| sha256sum packages/jvm/build/central/central-bundle.zip | ||
| - name: Generate artifact attestation | ||
| if: steps.jvm-release.outputs.exists != 'true' | ||
| uses: actions/attest-build-provenance@v4 | ||
| with: | ||
| subject-path: packages/jvm/build/central/central-bundle.zip | ||
| - name: Publish and validate on Maven Central Portal | ||
| if: steps.jvm-release.outputs.exists != 'true' | ||
| run: ./gradlew publishToCentralPortal --no-daemon | ||
| working-directory: packages/jvm | ||
| env: | ||
| MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} | ||
| MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} | ||
| MAVEN_SIGNING_KEY: ${{ secrets.MAVEN_SIGNING_KEY }} | ||
| MAVEN_SIGNING_PASSWORD: ${{ secrets.MAVEN_SIGNING_PASSWORD }} | ||
| - name: Upload Central bundle | ||
| if: steps.jvm-release.outputs.exists != 'true' | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: jvm-central-bundle | ||
| path: packages/jvm/build/central/central-bundle.zip | ||
| if-no-files-found: error | ||
| retention-days: 7 | ||