fix: avoid stack overflows on deeply nested HTML #252
Workflow file for this run
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: CI E2E | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - "crates/**" | |
| - "packages/**" | |
| - "e2e/**" | |
| - "fixtures/**" | |
| - "alef.toml" | |
| - "tools/**" | |
| - "scripts/**" | |
| - "Cargo.toml" | |
| - "Cargo.lock" | |
| - "Taskfile.yaml" | |
| - ".task/**" | |
| - "pyproject.toml" | |
| - "uv.lock" | |
| - "uv.toml" | |
| - "pnpm-lock.yaml" | |
| - "pnpm-workspace.yaml" | |
| - "package.json" | |
| - "Gemfile" | |
| - "Gemfile.lock" | |
| - "composer.json" | |
| - "composer.lock" | |
| - "go.mod" | |
| - "go.sum" | |
| - "rust-toolchain.toml" | |
| - ".cargo/config.toml" | |
| - ".github/workflows/ci-e2e.yaml" | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - "crates/**" | |
| - "packages/**" | |
| - "e2e/**" | |
| - "fixtures/**" | |
| - "alef.toml" | |
| - "tools/**" | |
| - "scripts/**" | |
| - "Cargo.toml" | |
| - "Cargo.lock" | |
| - "Taskfile.yaml" | |
| - ".task/**" | |
| - "pyproject.toml" | |
| - "uv.lock" | |
| - "uv.toml" | |
| - "pnpm-lock.yaml" | |
| - "pnpm-workspace.yaml" | |
| - "package.json" | |
| - "Gemfile" | |
| - "Gemfile.lock" | |
| - "composer.json" | |
| - "composer.lock" | |
| - "go.mod" | |
| - "go.sum" | |
| - "rust-toolchain.toml" | |
| - ".cargo/config.toml" | |
| - ".github/workflows/ci-e2e.yaml" | |
| workflow_dispatch: {} | |
| concurrency: | |
| group: ci-e2e-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CARGO_TERM_COLOR: always | |
| CARGO_INCREMENTAL: 0 | |
| RUST_BACKTRACE: short | |
| BUILD_PROFILE: "ci" | |
| GO_VERSION: "1.26.0" | |
| GO_TOOLCHAIN: "go1.26.0" | |
| GOLANGCI_LINT_VERSION: "latest" | |
| permissions: | |
| contents: read | |
| jobs: | |
| changes: | |
| name: "Detect Changes" | |
| runs-on: ubuntu-24.04-arm | |
| outputs: | |
| core: ${{ steps.filter.outputs.core }} | |
| rust: ${{ steps.filter.outputs.rust }} | |
| ffi: ${{ steps.filter.outputs.ffi }} | |
| python: ${{ steps.filter.outputs.python }} | |
| node: ${{ steps.filter.outputs.node }} | |
| ruby: ${{ steps.filter.outputs.ruby }} | |
| php: ${{ steps.filter.outputs.php }} | |
| go: ${{ steps.filter.outputs.go }} | |
| java: ${{ steps.filter.outputs.java }} | |
| elixir: ${{ steps.filter.outputs.elixir }} | |
| r: ${{ steps.filter.outputs.r }} | |
| wasm: ${{ steps.filter.outputs.wasm }} | |
| csharp: ${{ steps.filter.outputs.csharp }} | |
| kotlin: ${{ steps.filter.outputs.kotlin }} | |
| swift: ${{ steps.filter.outputs.swift }} | |
| dart: ${{ steps.filter.outputs.dart }} | |
| zig: ${{ steps.filter.outputs.zig }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Detect changes | |
| uses: dorny/paths-filter@v4 | |
| id: filter | |
| with: | |
| filters: | | |
| core: | |
| - 'crates/html-to-markdown/**' | |
| - 'Cargo.toml' | |
| - 'Cargo.lock' | |
| - 'rust-toolchain.toml' | |
| - '.cargo/config.toml' | |
| - 'fixtures/**' | |
| - 'tools/e2e-generator/**' | |
| rust: | |
| - 'crates/html-to-markdown/**' | |
| - 'crates/html-to-markdown-cli/**' | |
| - 'e2e/rust/**' | |
| - 'Cargo.toml' | |
| - 'Cargo.lock' | |
| - 'rustfmt.toml' | |
| ffi: | |
| - 'crates/html-to-markdown-ffi/**' | |
| - 'crates/html-to-markdown/**' | |
| - 'e2e/c/**' | |
| - 'Cargo.toml' | |
| - 'Cargo.lock' | |
| python: | |
| - 'crates/html-to-markdown-py/**' | |
| - 'packages/python/**' | |
| - 'e2e/python/**' | |
| - 'pyproject.toml' | |
| - 'uv.lock' | |
| - 'uv.toml' | |
| - 'fixtures/**' | |
| node: | |
| - 'crates/html-to-markdown-node/**' | |
| - 'packages/typescript/**' | |
| - 'e2e/node/**' | |
| - 'package.json' | |
| - 'pnpm-lock.yaml' | |
| - 'pnpm-workspace.yaml' | |
| - 'fixtures/**' | |
| ruby: | |
| - 'packages/ruby/**' | |
| - 'e2e/ruby/**' | |
| - 'Gemfile' | |
| - 'Gemfile.lock' | |
| - 'fixtures/**' | |
| php: | |
| - 'crates/html-to-markdown-php/**' | |
| - 'packages/php/**' | |
| - 'packages/php-ext/**' | |
| - 'e2e/php/**' | |
| - 'composer.json' | |
| - 'composer.lock' | |
| - 'fixtures/**' | |
| go: | |
| - 'packages/go/**' | |
| - 'e2e/go/**' | |
| - 'crates/html-to-markdown-ffi/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| - 'fixtures/**' | |
| java: | |
| - 'packages/java/**' | |
| - 'e2e/java/**' | |
| - 'crates/html-to-markdown-ffi/**' | |
| - 'fixtures/**' | |
| elixir: | |
| - 'packages/elixir/**' | |
| - 'e2e/elixir/**' | |
| - 'crates/html-to-markdown-ffi/**' | |
| - 'fixtures/**' | |
| r: | |
| - 'packages/r/**' | |
| - 'e2e/r/**' | |
| - 'fixtures/**' | |
| wasm: | |
| - 'crates/html-to-markdown-wasm/**' | |
| - 'crates/html-to-markdown-wasm-wasi/**' | |
| - 'e2e/wasm/**' | |
| - 'fixtures/**' | |
| csharp: | |
| - 'packages/csharp/**' | |
| - 'e2e/csharp/**' | |
| - 'crates/html-to-markdown-ffi/**' | |
| - 'fixtures/**' | |
| kotlin: | |
| - 'packages/kotlin-android/**' | |
| - 'crates/html-to-markdown-ffi/**' | |
| - 'fixtures/**' | |
| swift: | |
| - 'packages/swift/**' | |
| - 'e2e/swift_e2e/**' | |
| - 'fixtures/**' | |
| dart: | |
| - 'packages/dart/**' | |
| - 'e2e/dart/**' | |
| - 'fixtures/**' | |
| zig: | |
| - 'packages/zig/**' | |
| - 'e2e/zig/**' | |
| - 'crates/html-to-markdown-ffi/**' | |
| - 'fixtures/**' | |
| build-ffi: | |
| needs: [changes] | |
| name: "Build: FFI (${{ matrix.runner }})" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.ffi == 'true' | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| runner: | |
| - ubuntu-latest | |
| - ubuntu-24.04-arm | |
| - macos-latest | |
| - windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| id: checkout | |
| - name: Free disk space | |
| if: startsWith(matrix.runner, 'ubuntu') | |
| uses: xberg-io/actions/free-disk-space-linux@v1 # v1 | |
| with: | |
| show-initial: "false" | |
| show-final: "true" | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: ffi-${{ matrix.runner }} | |
| use-sccache: false | |
| - name: Build html-to-markdown-ffi (release, Unix) | |
| if: matrix.runner != 'windows-latest' | |
| run: cargo build --release --locked -p html-to-markdown-ffi | |
| shell: bash | |
| env: | |
| CARGO_TERM_COLOR: always | |
| CARGO_INCREMENTAL: "0" | |
| RUST_BACKTRACE: short | |
| - name: Build html-to-markdown-ffi (debug, Windows) | |
| if: matrix.runner == 'windows-latest' | |
| run: cargo build --locked -p html-to-markdown-ffi | |
| shell: bash | |
| env: | |
| CARGO_TERM_COLOR: always | |
| - name: Verify header exists | |
| shell: bash | |
| run: | | |
| HEADER="crates/html-to-markdown-ffi/include/html_to_markdown.h" | |
| test -f "$HEADER" | |
| echo "Header verified: $HEADER" | |
| - name: Upload FFI artifacts | |
| if: matrix.runner != 'windows-latest' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ffi-${{ matrix.runner }} | |
| path: | | |
| target/release/libhtml_to_markdown_ffi.* | |
| target/release/html_to_markdown_ffi.* | |
| crates/html-to-markdown-ffi/include/html_to_markdown.h | |
| retention-days: 7 | |
| if-no-files-found: warn | |
| - name: Cleanup Rust cache | |
| if: always() && steps.checkout.outcome == 'success' | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| build-python: | |
| needs: [changes] | |
| name: "Build: Python (${{ matrix.os }})" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.python == 'true' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 45 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| python: ["3.10", "3.12", "3.14"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| id: checkout | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| enable-cache: true | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| components: rustfmt, clippy, llvm-tools-preview | |
| cache-key-prefix: python-${{ matrix.os }}-${{ matrix.python }} | |
| - name: Install Python Dependencies | |
| uses: nick-fields/retry@v4 # v4 | |
| with: | |
| timeout_minutes: 5 | |
| max_attempts: 3 | |
| retry_wait_seconds: 30 | |
| command: | | |
| if [[ "${{ runner.os }}" == "Windows" ]] && [[ -d ".venv" ]]; then | |
| echo "Removing existing .venv directory on Windows" | |
| rm -rf .venv | |
| fi | |
| uv sync --all-extras --no-install-project --no-install-workspace | |
| shell: bash | |
| - name: Build Python Bindings | |
| run: | | |
| uv pip install maturin | |
| cd packages/python && uv run maturin develop --release | |
| shell: bash | |
| - name: Build CLI binary | |
| run: cargo build --release --locked -p html-to-markdown-cli | |
| shell: bash | |
| - name: Cleanup Rust cache | |
| if: always() && steps.checkout.outcome == 'success' | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| build-node: | |
| needs: [changes] | |
| name: "Build: Node (${{ matrix.os }}, ${{ matrix.runtime }})" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.node == 'true' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| runtime: [node, bun] | |
| exclude: | |
| - os: windows-latest | |
| runtime: bun | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| id: checkout | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: node-${{ matrix.os }}-${{ matrix.runtime }} | |
| - name: Setup Node.js workspace | |
| if: matrix.runtime == 'node' | |
| uses: xberg-io/actions/setup-node-workspace@v1 # v1 | |
| - name: Setup Bun | |
| if: matrix.runtime == 'bun' | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Build NAPI-RS Bindings (Node.js) | |
| if: matrix.runtime == 'node' | |
| uses: xberg-io/actions/build-node-napi@v1 # v1 | |
| with: | |
| crate-dir: crates/html-to-markdown-node | |
| - name: Install workspace dependencies (Bun) | |
| if: matrix.runtime == 'bun' | |
| run: bun install | |
| shell: bash | |
| - name: Build NAPI-RS Bindings (Bun) | |
| if: matrix.runtime == 'bun' | |
| working-directory: crates/html-to-markdown-node | |
| run: bun run build | |
| shell: bash | |
| - name: Build TypeScript package (Node.js) | |
| if: matrix.runtime == 'node' | |
| uses: ./.github/actions/build-typescript | |
| - name: Build TypeScript package (Bun) | |
| if: matrix.runtime == 'bun' | |
| working-directory: packages/typescript | |
| run: bun x tsc --project tsconfig.json | |
| shell: bash | |
| - name: Cleanup Rust cache | |
| if: always() && steps.checkout.outcome == 'success' | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| build-ruby: | |
| needs: [changes] | |
| name: "Build: Ruby (${{ matrix.os }}, ruby-${{ matrix.ruby }})" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.ruby == 'true' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| ruby: ["3.2", "3.3"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| id: checkout | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: ruby-${{ matrix.os }}-${{ matrix.ruby }} | |
| - name: Setup Ruby (Unix) | |
| if: runner.os != 'Windows' | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: ${{ matrix.ruby }} | |
| bundler: "4.0.3" | |
| bundler-cache: false | |
| working-directory: packages/ruby | |
| - name: Setup Ruby (Windows) | |
| if: runner.os == 'Windows' | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: ${{ matrix.ruby }} | |
| bundler: "4.0.3" | |
| bundler-cache: false | |
| working-directory: packages/ruby | |
| windows-toolchain: UCRT64 | |
| - name: Build CLI binary | |
| uses: xberg-io/actions/build-rust-cli@v1 # v1 | |
| with: | |
| package-name: html-to-markdown-cli | |
| binary-name: html-to-markdown | |
| - name: Build Ruby extension | |
| uses: xberg-io/actions/build-ruby-gem@v1 # v1 | |
| - name: Cleanup Rust cache | |
| if: always() && steps.checkout.outcome == 'success' | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| build-php: | |
| needs: [changes] | |
| name: "Build: PHP" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.php == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| id: checkout | |
| - name: Setup PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: "8.4" | |
| extensions: ctype, dom, json, libxml, mbstring, tokenizer, xml, xmlwriter | |
| tools: composer:2.9.8 | |
| coverage: none | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: php | |
| - name: Capture php-config path | |
| run: scripts/ci/php/set-php-config.sh | |
| shell: bash | |
| - name: Install root Composer dependencies | |
| uses: ramsey/composer-install@4.0.0 | |
| with: | |
| dependency-versions: locked | |
| env: | |
| COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GITHUB_TOKEN }}"}}' | |
| - name: Install PHP package Composer dependencies | |
| uses: ramsey/composer-install@4.0.0 | |
| with: | |
| dependency-versions: locked | |
| working-directory: packages/php | |
| env: | |
| COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GITHUB_TOKEN }}"}}' | |
| - name: Build PHP extension | |
| id: build-php-extension | |
| uses: xberg-io/actions/build-php-extension@v1 # v1 | |
| with: | |
| crate-name: html-to-markdown-php | |
| lib-name: html_to_markdown_php | |
| - name: Upload PHP extension artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: php-extension-ubuntu | |
| path: ${{ steps.build-php-extension.outputs.extension-path }} | |
| retention-days: 7 | |
| - name: Cleanup Rust cache | |
| if: always() && steps.checkout.outcome == 'success' | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| build-csharp: | |
| needs: [changes] | |
| name: "Build: C# (${{ matrix.os }})" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.csharp == 'true' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| id: checkout | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: csharp-${{ matrix.os }} | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "10.0.x" | |
| - name: Build FFI library (Unix) | |
| if: runner.os != 'Windows' | |
| run: cargo build --release --locked -p html-to-markdown-ffi | |
| shell: bash | |
| - name: Build FFI library (Windows) | |
| if: runner.os == 'Windows' | |
| run: cargo build --locked -p html-to-markdown-ffi | |
| shell: bash | |
| - name: Restore C# dependencies | |
| run: dotnet restore packages/csharp/ | |
| shell: bash | |
| - name: Build C# package | |
| run: dotnet build packages/csharp/ -c Release | |
| shell: bash | |
| - name: Cleanup Rust cache | |
| if: always() && steps.checkout.outcome == 'success' | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| build-java: | |
| needs: [changes] | |
| name: "Build: Java (${{ matrix.os }})" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.java == 'true' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| java: ["25"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| id: checkout | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: java-${{ matrix.os }} | |
| - name: Test Java Panama FFI bindings | |
| uses: xberg-io/actions/test-java-ffi@v1 # v1 | |
| with: | |
| ffi-crate-name: html-to-markdown-ffi | |
| ffi-lib-name: html_to_markdown_ffi | |
| java-version: ${{ matrix.java }} | |
| - name: Cleanup Rust cache | |
| if: always() && steps.checkout.outcome == 'success' | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| build-wasm: | |
| needs: [changes] | |
| name: "Build: WASM" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.wasm == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 120 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| id: checkout | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| target: wasm32-unknown-unknown | |
| use-sccache: false | |
| cache-key-prefix: wasm | |
| - name: Ensure wasm target installed | |
| run: scripts/common/ensure-wasm-target.sh | |
| shell: bash | |
| - name: Install wasm-pack | |
| run: scripts/common/install-wasm-pack.sh | |
| shell: bash | |
| - name: Setup Node workspace | |
| uses: xberg-io/actions/setup-node-workspace@v1 # v1 | |
| - name: Build WASM (all targets) | |
| uses: xberg-io/actions/build-wasm-package@v1 # v1 | |
| with: | |
| crate-dir: crates/html-to-markdown-wasm | |
| - name: Cleanup Rust cache | |
| if: always() && steps.checkout.outcome == 'success' | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| test-python: | |
| needs: [build-python] | |
| name: "Test: Python (${{ matrix.os }}, py-${{ matrix.python }})" | |
| if: always() && !cancelled() && needs.build-python.result != 'skipped' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 45 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| python: ["3.10", "3.12", "3.14"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| enable-cache: true | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| components: rustfmt, clippy, llvm-tools-preview | |
| - name: Install Python Dependencies | |
| uses: nick-fields/retry@v4 # v4 | |
| with: | |
| timeout_minutes: 5 | |
| max_attempts: 3 | |
| retry_wait_seconds: 30 | |
| command: | | |
| if [[ "${{ runner.os }}" == "Windows" ]] && [[ -d ".venv" ]]; then | |
| echo "Removing existing .venv directory on Windows" | |
| rm -rf .venv | |
| fi | |
| uv sync --all-extras --no-install-project --no-install-workspace | |
| shell: bash | |
| - name: Build Python Bindings | |
| run: | | |
| uv pip install maturin | |
| cd packages/python && uv run maturin develop --release | |
| shell: bash | |
| - name: Build CLI binary | |
| run: cargo build --release --locked -p html-to-markdown-cli | |
| shell: bash | |
| - name: Install alef | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests | |
| run: alef test --e2e --lang python | |
| shell: bash | |
| test-node: | |
| needs: [build-node] | |
| name: "Test: Node (${{ matrix.os }}, ${{ matrix.runtime }})" | |
| if: always() && !cancelled() && needs.build-node.result != 'skipped' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| runtime: [node, bun] | |
| exclude: | |
| - os: windows-latest | |
| runtime: bun | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| - name: Setup Node.js workspace | |
| if: matrix.runtime == 'node' | |
| uses: xberg-io/actions/setup-node-workspace@v1 # v1 | |
| - name: Setup Bun | |
| if: matrix.runtime == 'bun' | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Build NAPI-RS Bindings (Node.js) | |
| if: matrix.runtime == 'node' | |
| uses: xberg-io/actions/build-node-napi@v1 # v1 | |
| with: | |
| crate-dir: crates/html-to-markdown-node | |
| - name: Install workspace dependencies (Bun) | |
| if: matrix.runtime == 'bun' | |
| run: bun install | |
| shell: bash | |
| - name: Build NAPI-RS Bindings (Bun) | |
| if: matrix.runtime == 'bun' | |
| working-directory: crates/html-to-markdown-node | |
| run: bun run build | |
| shell: bash | |
| - name: Run Rust Tests (Node.js only) | |
| if: matrix.runtime == 'node' | |
| run: task rust:test | |
| shell: bash | |
| - name: Build TypeScript package (Node.js) | |
| if: matrix.runtime == 'node' | |
| uses: ./.github/actions/build-typescript | |
| - name: Build TypeScript package (Bun) | |
| if: matrix.runtime == 'bun' | |
| working-directory: packages/typescript | |
| run: bun x tsc --project tsconfig.json | |
| shell: bash | |
| - name: Install alef | |
| if: matrix.runtime == 'node' | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests (Node.js only) | |
| if: matrix.runtime == 'node' | |
| run: alef test --e2e --lang node | |
| shell: bash | |
| test-ruby: | |
| needs: [build-ruby] | |
| name: "Test: Ruby (${{ matrix.os }}, ruby-${{ matrix.ruby }})" | |
| if: always() && !cancelled() && needs.build-ruby.result != 'skipped' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| ruby: ["3.2", "3.3"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| - name: Setup Ruby (Unix) | |
| if: runner.os != 'Windows' | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: ${{ matrix.ruby }} | |
| bundler: "4.0.3" | |
| bundler-cache: false | |
| working-directory: packages/ruby | |
| - name: Setup Ruby (Windows) | |
| if: runner.os == 'Windows' | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: ${{ matrix.ruby }} | |
| bundler: "4.0.3" | |
| bundler-cache: false | |
| working-directory: packages/ruby | |
| windows-toolchain: UCRT64 | |
| - name: Build CLI binary | |
| uses: xberg-io/actions/build-rust-cli@v1 # v1 | |
| with: | |
| package-name: html-to-markdown-cli | |
| binary-name: html-to-markdown | |
| - name: Build Ruby extension | |
| uses: xberg-io/actions/build-ruby-gem@v1 # v1 | |
| - name: Run Rubocop (Ubuntu/ruby-3.3 only) | |
| if: runner.os != 'Windows' && matrix.os == 'ubuntu-latest' && matrix.ruby == '3.3' | |
| run: ./scripts/ci/ruby/run-rubocop.sh | |
| shell: bash | |
| - name: Validate RBS signatures (Ubuntu/ruby-3.3 only) | |
| if: runner.os != 'Windows' && matrix.os == 'ubuntu-latest' && matrix.ruby == '3.3' | |
| run: ./scripts/ci/ruby/run-rbs-validate.sh | |
| shell: bash | |
| - name: Run Steep type checking (Ubuntu/ruby-3.3 only) | |
| if: runner.os != 'Windows' && matrix.os == 'ubuntu-latest' && matrix.ruby == '3.3' | |
| working-directory: packages/ruby | |
| run: ../../scripts/ci/ruby/run-steep.sh | |
| shell: bash | |
| - name: Run Ruby specs (Unix) | |
| if: runner.os != 'Windows' | |
| working-directory: packages/ruby | |
| run: ../../scripts/ci/ruby/run-rspec-unix.sh | |
| shell: bash | |
| - name: Run Ruby specs (Windows) | |
| if: runner.os == 'Windows' | |
| working-directory: packages/ruby | |
| shell: pwsh | |
| run: ../../scripts/ci/ruby/run-rspec-windows.ps1 | |
| - name: Install Task | |
| if: runner.os != 'Windows' | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Install alef | |
| if: runner.os != 'Windows' | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests (Unix only) | |
| if: runner.os != 'Windows' | |
| run: alef test --e2e --lang ruby | |
| shell: bash | |
| test-php: | |
| needs: [build-php] | |
| name: "Test: PHP" | |
| if: always() && !cancelled() && needs.build-php.result != 'skipped' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: "8.4" | |
| extensions: ctype, dom, json, libxml, mbstring, tokenizer, xml, xmlwriter | |
| tools: composer:2.9.8 | |
| coverage: none | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| - name: Capture php-config path | |
| run: scripts/ci/php/set-php-config.sh | |
| shell: bash | |
| - name: Install root Composer dependencies | |
| uses: ramsey/composer-install@4.0.0 | |
| with: | |
| dependency-versions: locked | |
| env: | |
| COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GITHUB_TOKEN }}"}}' | |
| - name: Install PHP package Composer dependencies | |
| uses: ramsey/composer-install@4.0.0 | |
| with: | |
| dependency-versions: locked | |
| working-directory: packages/php | |
| env: | |
| COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GITHUB_TOKEN }}"}}' | |
| - name: Build PHP extension | |
| id: build-php-extension | |
| uses: xberg-io/actions/build-php-extension@v1 # v1 | |
| with: | |
| crate-name: html-to-markdown-php | |
| lib-name: html_to_markdown_php | |
| - name: Run PHP static analysis | |
| run: scripts/ci/php/run-phpstan.sh | |
| shell: bash | |
| - name: Run PHP tests | |
| run: scripts/ci/php/run-php-tests.sh | |
| shell: bash | |
| env: | |
| EXTENSION_PATH: ${{ steps.build-php-extension.outputs.extension-path }} | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Install alef | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests | |
| run: alef test --e2e --lang php | |
| shell: bash | |
| env: | |
| EXTENSION_PATH: ${{ steps.build-php-extension.outputs.extension-path }} | |
| test-csharp: | |
| needs: [build-csharp, build-ffi, changes] | |
| name: "Test: C# (${{ matrix.os }})" | |
| if: | | |
| always() && !cancelled() && needs.build-csharp.result != 'skipped' && | |
| (github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.csharp == 'true' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.core == 'true') | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: csharp-test-${{ matrix.os }} | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "10.0.x" | |
| - name: Build FFI library (Unix) | |
| if: runner.os != 'Windows' | |
| run: cargo build --release --locked -p html-to-markdown-ffi | |
| shell: bash | |
| - name: Build FFI library (Windows) | |
| if: runner.os == 'Windows' | |
| run: cargo build --locked -p html-to-markdown-ffi | |
| shell: bash | |
| - name: Restore C# dependencies | |
| run: dotnet restore packages/csharp/ | |
| shell: bash | |
| - name: Build C# package | |
| run: dotnet build packages/csharp/ -c Release | |
| shell: bash | |
| - name: Run C# unit tests | |
| run: dotnet test packages/csharp/ -c Release | |
| shell: bash | |
| - name: Install alef | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests (Unix) | |
| if: runner.os != 'Windows' | |
| run: alef test --e2e --lang csharp | |
| shell: bash | |
| env: | |
| LD_LIBRARY_PATH: ${{ github.workspace }}/target/release:${{ github.workspace }}/target/debug | |
| DYLD_LIBRARY_PATH: ${{ github.workspace }}/target/release:${{ github.workspace }}/target/debug | |
| - name: Run E2E tests (Windows) | |
| if: runner.os == 'Windows' | |
| # Prepend the target dirs to PATH at runtime (for FFI .dll resolution) | |
| # using the live $PATH rather than the `env:` `${{ env.PATH }}` | |
| # expression, which does not include cargo's $GITHUB_PATH additions on | |
| # Windows Git Bash and broke the before-hook with `cargo: command not found`. | |
| run: | | |
| export PATH="${{ github.workspace }}/target/release:${{ github.workspace }}/target/debug:$PATH" | |
| alef test --e2e --lang csharp | |
| shell: bash | |
| - name: Cleanup Rust cache | |
| if: always() | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| test-go: | |
| needs: [build-ffi, changes] | |
| name: "Test: Go" | |
| if: | | |
| always() && !cancelled() && needs.build-ffi.result != 'skipped' && | |
| (github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.go == 'true' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.core == 'true') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| - name: Setup Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| check-latest: true | |
| - name: Build FFI library | |
| run: cargo build --release --locked -p html-to-markdown-ffi | |
| shell: bash | |
| - name: Detect Go modules | |
| id: set-modules | |
| shell: bash | |
| run: scripts/ci/go/detect-go-modules.sh | |
| - name: Install golangci-lint | |
| if: steps.set-modules.outputs.modules != '[]' | |
| env: | |
| GOTOOLCHAIN: ${{ env.GO_TOOLCHAIN }} | |
| run: scripts/ci/go/install-golangci-lint.sh | |
| shell: bash | |
| - name: Run golangci-lint (all modules) | |
| if: steps.set-modules.outputs.modules != '[]' | |
| shell: bash | |
| run: | | |
| for module in $(echo '${{ steps.set-modules.outputs.modules }}' | jq -r '.[]'); do | |
| echo "=== Linting $module ===" | |
| (cd "$module" && "${{ github.workspace }}/scripts/ci/go/run-golangci-lint.sh") | |
| done | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Install alef | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests | |
| run: alef test --e2e --lang go | |
| shell: bash | |
| test-java: | |
| needs: [build-java] | |
| name: "Test: Java (${{ matrix.os }})" | |
| if: always() && !cancelled() && needs.build-java.result != 'skipped' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| java: ["25"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| - name: Test Java Panama FFI bindings | |
| uses: xberg-io/actions/test-java-ffi@v1 # v1 | |
| with: | |
| ffi-crate-name: html-to-markdown-ffi | |
| ffi-lib-name: html_to_markdown_ffi | |
| java-version: ${{ matrix.java }} | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Install alef | |
| if: matrix.os != 'windows-latest' | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests (Linux + macOS) | |
| # macOS coverage exercises the Java native loader on Apple Silicon so | |
| # macOS-specific binding/RID regressions are caught (alef test is not | |
| # supported on the Windows runner here). | |
| if: matrix.os != 'windows-latest' | |
| run: alef test --e2e --lang java | |
| shell: bash | |
| test-elixir: | |
| needs: [build-ffi, changes] | |
| name: "Test: Elixir" | |
| if: | | |
| always() && !cancelled() && needs.build-ffi.result != 'skipped' && | |
| (github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.elixir == 'true' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.core == 'true') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Elixir | |
| uses: erlef/setup-beam@v1 | |
| with: | |
| elixir-version: "1.19" | |
| otp-version: "28.1" | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| - name: Install Hex/Rebar | |
| run: scripts/ci/elixir/install-hex-rebar.sh | |
| shell: bash | |
| - name: Install dependencies | |
| working-directory: packages/elixir | |
| run: ../../scripts/ci/elixir/install-deps.sh | |
| shell: bash | |
| - name: Run tests | |
| working-directory: packages/elixir | |
| run: ../../scripts/ci/elixir/run-tests.sh | |
| shell: bash | |
| - name: Credo lint | |
| working-directory: packages/elixir | |
| run: ../../scripts/ci/elixir/run-credo.sh | |
| shell: bash | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Install alef | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests | |
| run: alef test --e2e --lang elixir | |
| shell: bash | |
| test-r: | |
| needs: [changes] | |
| name: "Test: R" | |
| if: | | |
| always() && !cancelled() && | |
| (github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.r == 'true' || | |
| needs.changes.outputs.core == 'true') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup R | |
| uses: xberg-io/actions/setup-r@v1 # v1 | |
| with: | |
| install-deps-script: scripts/ci/r/install-deps.sh | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| - name: Run tests | |
| working-directory: packages/r | |
| run: ../../scripts/ci/r/run-tests.sh | |
| shell: bash | |
| - name: Run lintr | |
| working-directory: packages/r | |
| run: ../../scripts/ci/r/run-lintr.sh | |
| shell: bash | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Install alef | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests | |
| run: alef test --e2e --lang r | |
| shell: bash | |
| test-c-ffi: | |
| needs: [build-ffi, changes] | |
| name: "Test: C FFI (${{ matrix.runner }})" | |
| if: | | |
| always() && !cancelled() && needs.build-ffi.result != 'skipped' && | |
| (github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.core == 'true') | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| runner: | |
| - ubuntu-latest | |
| - ubuntu-24.04-arm | |
| - macos-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: c-ffi-${{ matrix.runner }} | |
| use-sccache: false | |
| - name: Build html-to-markdown-ffi | |
| shell: bash | |
| run: cargo build --release --locked -p html-to-markdown-ffi | |
| - name: Run C e2e tests | |
| shell: bash | |
| env: | |
| LD_LIBRARY_PATH: ${{ github.workspace }}/target/release | |
| DYLD_LIBRARY_PATH: ${{ github.workspace }}/target/release | |
| run: cd e2e/c && make test | |
| - name: Verify header exists | |
| shell: bash | |
| run: | | |
| HEADER="crates/html-to-markdown-ffi/include/html_to_markdown.h" | |
| test -f "$HEADER" | |
| echo "Header verified: $HEADER" | |
| - name: Verify pkg-config output | |
| shell: bash | |
| run: | | |
| PC_DIR="$(pwd)/target/release/build" | |
| PC_FILE=$(find "$PC_DIR" -name 'html-to-markdown.pc' -path '*/html-to-markdown-ffi-*/out/*' 2>/dev/null | head -1) | |
| if [ -z "$PC_FILE" ]; then | |
| echo "Warning: html-to-markdown.pc not found in build output" | |
| find "$PC_DIR" -name '*.pc' 2>/dev/null || echo "No .pc files found" | |
| else | |
| echo "Found pkg-config file: $PC_FILE" | |
| cat "$PC_FILE" | |
| fi | |
| test-c-ffi-windows: | |
| needs: [build-ffi, changes] | |
| name: "Test: C FFI (windows-latest)" | |
| if: | | |
| always() && !cancelled() && needs.build-ffi.result != 'skipped' && | |
| (github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.core == 'true') | |
| runs-on: windows-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: c-ffi-windows | |
| use-sccache: false | |
| - name: Build html-to-markdown-ffi | |
| shell: bash | |
| run: cargo build --locked -p html-to-markdown-ffi | |
| - name: Verify header generated | |
| shell: bash | |
| run: | | |
| test -f crates/html-to-markdown-ffi/include/html_to_markdown.h | |
| echo "Header verified on Windows." | |
| test-wasm: | |
| needs: [build-wasm] | |
| name: "Test: WASM" | |
| if: always() && !cancelled() && needs.build-wasm.result != 'skipped' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 120 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| target: wasm32-unknown-unknown | |
| use-sccache: false | |
| - name: Ensure wasm target installed | |
| run: scripts/common/ensure-wasm-target.sh | |
| shell: bash | |
| - name: Install wasm-pack | |
| run: scripts/common/install-wasm-pack.sh | |
| shell: bash | |
| - name: Setup Node workspace | |
| uses: xberg-io/actions/setup-node-workspace@v1 # v1 | |
| - name: Build WASM (all targets) | |
| uses: xberg-io/actions/build-wasm-package@v1 # v1 | |
| with: | |
| crate-dir: crates/html-to-markdown-wasm | |
| - name: Test WASM bundle | |
| working-directory: crates/html-to-markdown-wasm | |
| run: ../../scripts/ci/wasm/test-wasm-bundle.sh | |
| shell: bash | |
| - name: Run Rust WASM tests | |
| working-directory: crates/html-to-markdown-wasm | |
| run: ../../scripts/ci/wasm/test-wasm-rust.sh | |
| shell: bash | |
| build-kotlin-android: | |
| needs: [changes] | |
| name: "Build: Kotlin Android" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.kotlin == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| id: checkout | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| targets: aarch64-linux-android,x86_64-linux-android | |
| cache-key-prefix: kotlin-android | |
| - name: Setup Android SDK/NDK | |
| uses: android-actions/setup-android@v4 | |
| - name: Build Android native libraries | |
| uses: xberg-io/actions/build-android-natives@v1 # v1 | |
| with: | |
| crate-name: html-to-markdown-ffi | |
| lib-name: html_to_markdown_ffi | |
| abis: arm64-v8a,x86_64 | |
| - name: Cleanup Rust cache | |
| if: always() && steps.checkout.outcome == 'success' | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| test-swift: | |
| needs: [changes] | |
| name: "Test: Swift" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.swift == 'true' | |
| runs-on: macos-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: swift | |
| - name: Setup Swift | |
| uses: xberg-io/actions/setup-swift@v1 # v1 | |
| with: | |
| version: "6.0" | |
| - name: Setup PHP | |
| # ext-php-rs's build.rs requires a `php` binary on PATH even when the | |
| # PHP binding crate isn't the one being built — cargo's workspace | |
| # resolver evaluates ALL workspace members for unification. Without | |
| # PHP here, `cargo build -p html-to-markdown-rs-swift` fails inside | |
| # ext-php-rs's build script. | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: "8.3" | |
| - name: Install alef | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests | |
| run: alef test --e2e --lang swift | |
| shell: bash | |
| - name: Cleanup Rust cache | |
| if: always() | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| test-dart: | |
| needs: [changes] | |
| name: "Test: Dart" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.dart == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: dart | |
| - name: Setup Dart | |
| uses: dart-lang/setup-dart@v1 | |
| - name: Install alef | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests | |
| run: alef test --e2e --lang dart | |
| shell: bash | |
| - name: Cleanup Rust cache | |
| if: always() | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 | |
| test-zig: | |
| needs: [changes] | |
| name: "Test: Zig" | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.zig == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install Task | |
| uses: xberg-io/actions/install-task@v1 # v1 | |
| - name: Setup Rust | |
| uses: xberg-io/actions/setup-rust@v1 # v1 | |
| with: | |
| cache-key-prefix: zig | |
| - name: Setup Zig | |
| uses: xberg-io/actions/setup-zig@v1 # v1 | |
| with: | |
| version: "0.16.0" | |
| - name: Install alef | |
| uses: xberg-io/actions/install-alef@v1 # v1 | |
| - name: Run E2E tests | |
| run: alef test --e2e --lang zig | |
| shell: bash | |
| - name: Cleanup Rust cache | |
| if: always() | |
| uses: xberg-io/actions/cleanup-rust-cache@v1 # v1 |