diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 726d6f2450..f1c5b73ad9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,10 +1,16 @@ { "name": "Iceberg Rust", "image": "mcr.microsoft.com/devcontainers/rust:bullseye", + "features": { + "ghcr.io/devcontainers-extra/features/mise:1": { + "version": "2026.6.14" + } + }, "customizations": { "vscode": { "extensions": [ - "rust-lang.rust-analyzer" + "rust-lang.rust-analyzer", + "hverlin.mise-vscode" ], "settings": { "editor.formatOnSave": true, @@ -13,5 +19,19 @@ } } } - } + }, + "mounts": [ + { + "source": "iceberg-rust-mise-data", + "target": "/mnt/mise-data", + "type": "volume" + } + ], + "containerEnv": { + "MISE_DATA_DIR": "/mnt/mise-data" + }, + "remoteEnv": { + "PATH": "${containerEnv:PATH}:/mnt/mise-data/shims" + }, + "postCreateCommand": "sudo chown -R $(id -u):$(id -g) /mnt/mise-data && mise trust --yes mise.toml && mise install" } diff --git a/.github/actions/setup-builder/action.yml b/.github/actions/setup-builder/action.yml index e961ed6335..70b6b0a454 100644 --- a/.github/actions/setup-builder/action.yml +++ b/.github/actions/setup-builder/action.yml @@ -22,11 +22,11 @@ description: 'Prepare Rust Build Environment' inputs: rust-version: description: 'version of rust to install and use' + required: true runs: using: "composite" steps: - name: Setup specified Rust toolchain - if: ${{ inputs.rust-version != '' }} shell: bash env: RUST_VERSION: ${{ inputs.rust-version }} @@ -35,14 +35,7 @@ runs: rustup toolchain install ${RUST_VERSION} rustup override set ${RUST_VERSION} rustup component add rustfmt clippy - - name: Setup Rust toolchain according to rust-toolchain.toml - shell: bash - if: ${{ inputs.rust-version == '' }} - run: | - echo "Installing toolchain according to rust-toolchain.toml" - rustup show - rustup component add rustfmt clippy - name: Fixup git permissions # https://github.com/actions/checkout/issues/766 shell: bash - run: git config --global --add safe.directory "$GITHUB_WORKSPACE" \ No newline at end of file + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" diff --git a/.github/workflows/bindings_python_ci.yml b/.github/workflows/bindings_python_ci.yml index 6980eb909a..a13e9c5e63 100644 --- a/.github/workflows/bindings_python_ci.yml +++ b/.github/workflows/bindings_python_ci.yml @@ -50,42 +50,38 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 with: - version: "0.9.3" - enable-cache: true - - name: Install tools - run: | - uv tool install ruff + version: 2026.6.14 - name: Check format - working-directory: "bindings/python" - run: | - uvx ruff format . --diff + run: mise run python:check-format - name: Check style - working-directory: "bindings/python" - run: | - uvx ruff check . + run: mise run python:check-style test: runs-on: ${{ matrix.os }} strategy: max-parallel: 15 matrix: - os: - - ubuntu-latest - - macos-latest - - windows-latest + include: + - os: ubuntu-latest + python: python3.12 + - os: macos-latest + python: python + - os: windows-latest + python: python steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 with: - python-version: 3.12 + version: 2026.6.14 + - name: Verify shared Python library + run: mise run python:verify-libpython # Linux maturin builds may run inside manylinux Docker, so host Rust caches only help Windows/macOS. - - name: Setup Rust toolchain - if: runner.os != 'Linux' - uses: ./.github/actions/setup-builder - name: Cache Rust artifacts if: runner.os != 'Linux' uses: swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 @@ -96,26 +92,21 @@ jobs: with: working-directory: "bindings/python" command: build - args: --out dist -i python3.12 # Explicitly set interpreter; manylinux containers have multiple Pythons and maturin may pick an older one - - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 - with: - version: "0.9.3" - enable-cache: true + # manylinux containers have multiple Pythons, while host builds use mise's python shim. + args: --out dist -i ${{ matrix.python }} - name: Sync dependencies working-directory: "bindings/python" shell: bash run: | - uv sync --group dev --no-install-project + uv sync --python 3.12 --no-managed-python --no-python-downloads --group dev --no-install-project - name: Install built wheel working-directory: "bindings/python" shell: bash run: | uv pip install --no-build --reinstall --find-links dist/ pyiceberg-core - name: Run tests - working-directory: "bindings/python" shell: bash env: HF_TOKEN: ${{ secrets.HF_TOKEN }} HF_DATASET: ${{ secrets.HF_DATASET }} - run: | - make test + run: mise run python:test diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3c1713484..f3a43cd4c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,23 +51,19 @@ jobs: with: persist-credentials: false - - name: Setup Rust toolchain - uses: ./.github/actions/setup-builder - - - name: Install lint tools - # Keep versions in sync with the local install targets in Makefile. - uses: taiki-e/install-action@9e1e5806d4a4822de933115878265be9aaa786d9 # v2.82.2 + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 with: - tool: taplo@0.9.3,cargo-machete@0.7.0 + version: 2026.6.14 - name: Check License Header uses: apache/skywalking-eyes/header@61275cc80d0798a405cb070f7d3a8aaf7cf2c2c1 # v0.8.0 - name: Check toml format - run: taplo fmt --check + run: mise run check-toml - name: Cargo format - run: make check-fmt + run: mise run check-fmt - name: Check diff run: git diff --exit-code @@ -76,7 +72,7 @@ jobs: run: cargo update --workspace --locked - name: Cargo Machete - run: cargo machete + run: mise run cargo-machete - name: Check typos uses: crate-ci/typos@37bb98842b0d8c4ffebdb75301a13db0267cef89 # v1.47.2 @@ -89,16 +85,13 @@ jobs: with: persist-credentials: false - - name: Setup Rust toolchain - uses: ./.github/actions/setup-builder - - - name: Install protoc - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 with: - repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 2026.6.14 - name: Cargo clippy - run: make check-clippy + run: mise run check-clippy build: needs: lint @@ -118,21 +111,18 @@ jobs: with: persist-credentials: false - - name: Setup Rust toolchain - uses: ./.github/actions/setup-builder + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 + with: + version: 2026.6.14 - name: Cache Rust artifacts uses: swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - - name: Install protoc - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Build - run: make build + run: mise run build # Checks each crate individually to catch missing feature declarations that # are otherwise masked by Cargo's feature unification across the workspace. @@ -144,24 +134,25 @@ jobs: with: persist-credentials: false - - name: Setup Rust toolchain - uses: ./.github/actions/setup-builder + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 + with: + version: 2026.6.14 - name: Cache Rust artifacts uses: swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - - name: Install protoc - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Check each crate standalone + shell: bash run: | - for pkg in $(cargo metadata --no-deps --format-version=1 | jq -r '.packages[].name'); do + set -euo pipefail + packages=$(cargo metadata --no-deps --format-version=1 | python -c \ + 'import json, sys; print("\n".join(package["name"] for package in json.load(sys.stdin)["packages"]))') + for pkg in $packages; do echo "Checking $pkg..." - cargo check -p "$pkg" --all-targets || exit 1 + cargo check -p "$pkg" --all-targets done # Verifies the core iceberg crate compiles without default features, ensuring @@ -184,8 +175,10 @@ jobs: with: persist-credentials: false - - name: Setup Rust toolchain - uses: ./.github/actions/setup-builder + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 + with: + version: 2026.6.14 - name: Cache Rust artifacts uses: swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 @@ -205,37 +198,28 @@ jobs: max-parallel: 15 matrix: test-suite: - - { name: "default", args: "--all-targets --all-features --workspace" } - - { name: "doc", args: "--doc --all-features --workspace" } - name: Tests (${{ matrix.test-suite.name }}) + - default + - doc + name: Tests (${{ matrix.test-suite }}) steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - - name: Setup Rust toolchain - uses: ./.github/actions/setup-builder - - - name: Install protoc - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 with: - repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 2026.6.14 - name: Cache Rust artifacts uses: swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: - key: ${{ matrix.test-suite.name }} + key: ${{ matrix.test-suite }} save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - - name: Install cargo-nextest - if: matrix.test-suite.name == 'default' - uses: taiki-e/install-action@bffeee26d4db9be238a4ea78d8826604ebcb594d # v2.82.5 - with: - tool: cargo-nextest - - name: Start Docker containers - if: matrix.test-suite.name == 'default' - run: make docker-up + if: matrix.test-suite == 'default' + run: mise run docker-up - name: Run tests shell: bash @@ -246,15 +230,15 @@ jobs: HF_BUCKET: ${{ secrets.HF_BUCKET }} HF_DATASET: ${{ secrets.HF_DATASET }} run: | - if [ "${{ matrix.test-suite.name }}" = "default" ]; then - cargo nextest run ${{ matrix.test-suite.args }} + if [ "${{ matrix.test-suite }}" = "default" ]; then + mise run nextest else - cargo test --no-fail-fast ${{ matrix.test-suite.args }} + mise run doc-test fi - name: Stop Docker containers - if: always() && matrix.test-suite.name == 'default' - run: make docker-down + if: always() && matrix.test-suite == 'default' + run: mise run docker-down msrv: name: Verify MSRV @@ -264,18 +248,9 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - - name: Install protoc - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Get MSRV - id: get-msrv - uses: ./.github/actions/get-msrv - - name: Setup MSRV Rust toolchain - uses: ./.github/actions/setup-builder + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 with: - rust-version: ${{ steps.get-msrv.outputs.msrv }} - - name: Setup Nightly Rust toolchain - uses: ./.github/actions/setup-builder + version: 2026.6.14 - name: Check MSRV - run: make check-msrv + run: mise run check-msrv diff --git a/.github/workflows/public-api.yml b/.github/workflows/public-api.yml index f5149d30d4..b785a26782 100644 --- a/.github/workflows/public-api.yml +++ b/.github/workflows/public-api.yml @@ -23,7 +23,9 @@ on: - main pull_request: paths: + - '.github/workflows/public-api.yml' - 'crates/**' + - 'mise.toml' concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} @@ -40,23 +42,15 @@ jobs: with: persist-credentials: false - - name: Setup Rust toolchain - uses: ./.github/actions/setup-builder + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 + with: + version: 2026.6.14 - name: Cache Rust artifacts uses: swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - - name: Install protoc - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Install cargo-public-api - uses: taiki-e/install-action@bffeee26d4db9be238a4ea78d8826604ebcb594d # v2.82.5 - with: - tool: cargo-public-api - - name: Check public API - run: make check-public-api + run: mise run check-public-api diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index f9bc9db79c..6dd55b1ec9 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -24,6 +24,7 @@ on: pull_request: paths: - ".github/workflows/website.yml" + - "mise.toml" - "website/**" concurrency: @@ -43,19 +44,13 @@ jobs: with: persist-credentials: false - - name: Setup mdBook - uses: peaceiris/actions-mdbook@ee69d230fe19748b7abf22df32acaa93833fad08 # v2.0.0 + - name: Setup mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 with: - mdbook-version: "0.4.36" - - - name: Install protoc - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 2026.6.14 - name: Build - working-directory: website - run: mdbook build + run: mise run site-build - name: Copy asf file run: cp .asf.yaml ./website/book/.asf.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1a736ed16..892ef4dc36 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -68,11 +68,15 @@ Currently, iceberg-rust uses GitHub Actions to run tests. The workflows are defi ## Setup -For small or first-time contributions, we recommend the dev container method. Prefer to do it yourself? That's fine too! +For small or first-time contributions, we recommend the dev container method. Prefer to set up the tools on your host? That's fine too. + +The project uses [mise](https://mise.en.dev/) to keep development tool versions and task definitions in one place. The pinned environment makes local and CI runs consistent, installs Rust, Python, protoc, and task-specific utilities automatically, and provides the shared `libpython` needed to compile the Python/DataFusion bindings. + +This does add mise as a bootstrap dependency, and the first installation requires network access and can take some time. The repository configuration must also be reviewed and trusted before mise will use it. mise does not install system applications such as Docker, Podman, or GPG. ### Using a dev container environment -iceberg-rust provides a pre-configured [dev container](https://containers.dev/) that could be used in [Github Codespaces](https://github.com/features/codespaces), [VSCode](https://code.visualstudio.com/), [JetBrains](https://www.jetbrains.com/remote-development/gateway/), [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/). Please pick up your favourite runtime environment. +iceberg-rust provides a pre-configured [dev container](https://containers.dev/) that can be used in [GitHub Codespaces](https://github.com/features/codespaces), [VS Code](https://code.visualstudio.com/), [JetBrains](https://www.jetbrains.com/remote-development/gateway/), or [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/). The container installs mise, trusts this repository's configuration, and installs the pinned development tools automatically. The fastest way is: @@ -80,35 +84,72 @@ The fastest way is: ### Bring your own toolbox -#### Install rust - -iceberg-rust is primarily a Rust project. To build iceberg-rust, you will need to set up Rust development first. We highly recommend using [rustup](https://rustup.rs/) for the setup process. +#### Install mise and project tools -For Linux or MacOS, use the following command: +Install mise 2026.6.14 or newer by following the [official installation guide](https://mise.en.dev/getting-started.html). Clone the repository, change to its root directory, and review `mise.toml` before trusting it. Then install the pinned tools: -```shell -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +```bash +mise trust +mise doctor +mise install +mise run build ``` -For Windows, download `rustup-init.exe` from [here](https://win.rustup.rs/x86_64) instead. +Shell activation is optional. `mise run ...` executes project tasks with the configured tools, and `mise exec -- cargo ...` can be used for ad hoc commands. Use `mise current` to inspect the selected versions. + +#### Verify Python and libpython -Rustup will read iceberg-rust's `rust-toolchain.toml` and set up everything else automatically. To ensure that everything works correctly, run `cargo version` under iceberg-rust's root directory: +Python is a workspace build dependency because the workspace contains the Python bindings and their DataFusion integration. The mise-managed Python is configured with a shared library so PyO3 can link against `libpython` on Linux, macOS, and Windows. + +Verify the selected interpreter and shared library before diagnosing a Cargo or linker failure: ```shell -$ cargo version -cargo 1.69.0 (6e9a83356 2023-04-12) +mise run python:verify-libpython ``` +The Python tasks explicitly use this interpreter, so uv will not silently select or download a different Python. + #### Install Docker or Podman -Currently, iceberg-rust uses Docker to set up environment for integration tests. See [Container Runtimes](website/src/reference/container-runtimes.md) for setup instructions. +iceberg-rust uses containers to set up services for integration tests. Install Docker or Podman separately and see [Container Runtimes](website/src/reference/container-runtimes.md) for setup instructions. ## Build -* To compile the project: `make build` -* To check code styles: `make check` -* To run unit tests only: `make unit-test` -* To run all tests: `make test` +Run all commands from the repository root. `mise tasks` lists every available task. + +| Task | Purpose | +| --- | --- | +| `mise run build` | Compile all workspace targets and features. | +| `mise run check` | Run Rust formatting and clippy, TOML formatting, and dependency checks. | +| `mise run check-msrv` | Check the workspace with the minimum supported Rust version. | +| `mise run unit-test` | Run Rust unit and documentation tests. | +| `mise run nextest` | Run the Rust test suite with cargo-nextest. | +| `mise run test` | Start the integration-test services, run all tests, and tear the services down. | +| `mise run docker-up` | Start the integration-test services without running tests. | +| `mise run docker-down` | Stop and remove the integration-test services. | +| `mise run docker-logs` | Follow logs from the integration-test services. | + +### Python bindings + +The Python tasks run in `bindings/python` while sharing the repository's managed tool versions: + +```shell +mise run python:install +mise run python:build +mise run python:check-format +mise run python:check-style +mise run python:test +``` + +### Website + +Preview the documentation site locally with `mise run site`. Use `mise run site-build` for a non-serving build. + +### Troubleshooting mise + +- Run `mise doctor` to check the installation and `mise current` to confirm the tools selected for this repository. +- If GitHub API rate limits interrupt installation, set `GITHUB_TOKEN` to a GitHub personal access token and retry `mise install`. Verification should remain enabled. +- If `mise run python:verify-libpython` reports a missing shared library, confirm that mise selected the configured Python, remove that mise-managed Python version with `mise uninstall python@3.12.13`, and run `mise install` again. Do not substitute a uv-managed or system interpreter. ## Dependencies diff --git a/Makefile b/Makefile deleted file mode 100644 index c5748718a4..0000000000 --- a/Makefile +++ /dev/null @@ -1,116 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -.EXPORT_ALL_VARIABLES: - -build: - cargo build --all-targets --all-features --workspace - -check-fmt: - cargo fmt --all -- --check - -check-clippy: - cargo clippy --all-targets --all-features --workspace -- -D warnings - -# Keep version in sync with the CI lint install step in .github/workflows/ci.yml. -install-cargo-machete: - cargo install --locked cargo-machete@0.7.0 - -cargo-machete: install-cargo-machete - cargo machete - -install-cargo-nextest: - cargo install --locked cargo-nextest - -nextest: install-cargo-nextest - cargo nextest run --all-targets --all-features --workspace - -# Keep version in sync with the CI lint install step in .github/workflows/ci.yml. -install-taplo-cli: - cargo install --locked taplo-cli@0.9.3 - -fix-toml: install-taplo-cli - taplo fmt - -check-toml: install-taplo-cli - taplo fmt --check - -NIGHTLY_VERSION := $(shell awk -F'"' '/^channel/ {print $$2}' rust-toolchain.toml) -MSRV_VERSION := $(shell awk -F'"' '/^rust-version/ {print $$2}' Cargo.toml) - -check-msrv: - cargo +$(MSRV_VERSION) check --workspace - -PUBLIC_API_CRATES := $(shell cargo metadata --no-deps --format-version 1 | \ - jq -r '.packages[] | select(.publish == null) | "\(.name):\(.manifest_path)"') - -install-cargo-public-api: - cargo install --locked cargo-public-api@0.51.0 - -generate-public-api: install-cargo-public-api - @for entry in $(PUBLIC_API_CRATES); do \ - crate=$${entry%%:*}; \ - manifest=$${entry##*:}; \ - crate_dir=$$(dirname "$$manifest"); \ - echo "Generating public API for $$crate..."; \ - cargo public-api -p "$$crate" --all-features -ss > "$$crate_dir/public-api.txt"; \ - done - -check-public-api: install-cargo-public-api - @fail=0; \ - for entry in $(PUBLIC_API_CRATES); do \ - crate=$${entry%%:*}; \ - manifest=$${entry##*:}; \ - crate_dir=$$(dirname "$$manifest"); \ - echo "Checking public API for $$crate..."; \ - cargo public-api -p "$$crate" --all-features -ss | diff - "$$crate_dir/public-api.txt" || { \ - echo "ERROR: Public API for $$crate has changed. Run 'make generate-public-api' to update."; \ - fail=1; \ - }; \ - done; \ - if [ $$fail -ne 0 ]; then exit 1; fi - -check: check-fmt check-clippy check-toml cargo-machete - -doc-test: - cargo test --no-fail-fast --doc --all-features --workspace - -unit-test: doc-test - cargo test --no-fail-fast --lib --all-features --workspace - -test: docker-up - @trap '$(MAKE) docker-down' EXIT; \ - $(MAKE) nextest - -clean: - cargo clean - -install-mdbook: - cargo install --locked mdbook@0.4.36 - -site: install-mdbook - cd website && mdbook serve - -# Docker targets for integration tests -docker-up: - docker compose -f dev/docker-compose.yaml up -d --build --wait - -docker-down: - docker compose -f dev/docker-compose.yaml down -v --remove-orphans --timeout 0 - -docker-logs: - docker compose -f dev/docker-compose.yaml logs -f diff --git a/README.md b/README.md index 536562b7b0..f4b64ff3ac 100644 --- a/README.md +++ b/README.md @@ -106,10 +106,31 @@ The Apache Iceberg Rust project is composed of the following components: The features that Iceberg Rust currently supports can be found [here](https://iceberg.apache.org/status/). +## Development + +Development tools and tasks are managed with [mise](https://mise.en.dev/). After installing mise, review the repository's [`mise.toml`](mise.toml), then run: + +```shell +mise trust +mise install +mise run build +``` + +Common development commands include: + +```shell +mise run check # Run formatting, lint, and dependency checks +mise run unit-test # Run Rust unit and documentation tests +mise run test # Run all tests, including container-backed tests +``` + +The full test suite also requires Docker or Podman. See the [Contributing Guide](CONTRIBUTING.md) for complete setup instructions, Python binding tasks, and troubleshooting. + ## Supported Rust Version -Iceberg Rust is built and tested with stable rust, and will keep a rolling MSRV (minimum supported rust version). -At least three months from latest rust release is supported. MSRV is updated when we release iceberg-rust. +Iceberg Rust keeps a rolling MSRV (minimum supported Rust version), currently Rust 1.94. The MSRV is updated when we release iceberg-rust and is at least three months behind the latest Rust release. + +Development, formatting, and linting use the nightly toolchain pinned in `mise.toml`; this does not affect downstream users. Run `mise run check-msrv` to validate the workspace with its declared MSRV. Check the current MSRV on [crates.io](https://crates.io/crates/iceberg). diff --git a/bindings/python/Makefile b/bindings/python/Makefile deleted file mode 100644 index 0e8b9632dc..0000000000 --- a/bindings/python/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -.PHONY: build install test - -build: - uv run maturin develop - -# uv sync may remove local editable pyiceberg-core, so install rebuilds it afterwards. -install: - uv sync --group dev --no-install-project - $(MAKE) build - -test: - uv run --no-sync pytest diff --git a/bindings/python/README.md b/bindings/python/README.md index 320a9a401b..8c38be8342 100644 --- a/bindings/python/README.md +++ b/bindings/python/README.md @@ -23,26 +23,31 @@ This project is used to build an Iceberg-rust powered core for [PyIceberg](https ## Setup -Install [uv](https://docs.astral.sh/uv/getting-started/installation/): +The repository uses [mise](https://mise.en.dev/) to install Python, uv, Rust, and the other development tools. Follow the root [contributor setup](../../CONTRIBUTING.md#setup), then run these commands from the repository root: ```shell -pip install uv==0.9.3 +mise install +mise run python:verify-libpython +mise run python:install ``` -Set up the development environment: +The managed Python includes the shared `libpython` required to compile the Python/DataFusion bindings. The install task makes uv use that interpreter and creates the binding's development environment. + +## Build ```shell -make install +mise run python:build ``` -## Build +## Test ```shell -make build +mise run python:test ``` -## Test +## Style checks ```shell -make test +mise run python:check-format +mise run python:check-style ``` diff --git a/crates/catalog/hms/tests/hms_catalog_test.rs b/crates/catalog/hms/tests/hms_catalog_test.rs index d0e6486ad8..cc1452843c 100644 --- a/crates/catalog/hms/tests/hms_catalog_test.rs +++ b/crates/catalog/hms/tests/hms_catalog_test.rs @@ -17,7 +17,7 @@ //! Integration tests for hms catalog. //! -//! These tests assume Docker containers are started externally via `make docker-up`. +//! These tests assume Docker containers are started externally via `mise run docker-up`. //! Each test uses unique namespaces based on module path to avoid conflicts. use std::collections::HashMap; diff --git a/crates/catalog/loader/tests/namespace_suite.rs b/crates/catalog/loader/tests/namespace_suite.rs index 024e8a62b8..f03be317bf 100644 --- a/crates/catalog/loader/tests/namespace_suite.rs +++ b/crates/catalog/loader/tests/namespace_suite.rs @@ -17,7 +17,7 @@ //! Common namespace behavior across catalogs. //! -//! These tests assume Docker containers are started externally via `make docker-up`. +//! These tests assume Docker containers are started externally via `mise run docker-up`. mod common; diff --git a/crates/catalog/loader/tests/schema_update_suite.rs b/crates/catalog/loader/tests/schema_update_suite.rs index 9421bbf0ee..747b2f385b 100644 --- a/crates/catalog/loader/tests/schema_update_suite.rs +++ b/crates/catalog/loader/tests/schema_update_suite.rs @@ -17,7 +17,7 @@ //! Common schema-update behavior across catalogs. //! -//! These tests assume Docker containers are started externally via `make docker-up`. +//! These tests assume Docker containers are started externally via `mise run docker-up`. mod common; diff --git a/crates/catalog/loader/tests/table_register_suite.rs b/crates/catalog/loader/tests/table_register_suite.rs index b43054b833..7f9e0a18a7 100644 --- a/crates/catalog/loader/tests/table_register_suite.rs +++ b/crates/catalog/loader/tests/table_register_suite.rs @@ -17,7 +17,7 @@ //! Common register-table behavior across catalogs. //! -//! These tests assume Docker containers are started externally via `make docker-up`. +//! These tests assume Docker containers are started externally via `mise run docker-up`. mod common; diff --git a/crates/catalog/loader/tests/table_rename_suite.rs b/crates/catalog/loader/tests/table_rename_suite.rs index 757d1cd044..e37ce4f222 100644 --- a/crates/catalog/loader/tests/table_rename_suite.rs +++ b/crates/catalog/loader/tests/table_rename_suite.rs @@ -17,7 +17,7 @@ //! Common rename behavior across catalogs. //! -//! These tests assume Docker containers are started externally via `make docker-up`. +//! These tests assume Docker containers are started externally via `mise run docker-up`. mod common; diff --git a/crates/catalog/loader/tests/table_suite.rs b/crates/catalog/loader/tests/table_suite.rs index cdc9b11043..ac39a8e7b2 100644 --- a/crates/catalog/loader/tests/table_suite.rs +++ b/crates/catalog/loader/tests/table_suite.rs @@ -17,7 +17,7 @@ //! Common table behavior across catalogs. //! -//! These tests assume Docker containers are started externally via `make docker-up`. +//! These tests assume Docker containers are started externally via `mise run docker-up`. mod common; diff --git a/crates/integration_tests/src/lib.rs b/crates/integration_tests/src/lib.rs index feafa3ae9f..02b91b969b 100644 --- a/crates/integration_tests/src/lib.rs +++ b/crates/integration_tests/src/lib.rs @@ -25,7 +25,7 @@ use iceberg_catalog_rest::REST_CATALOG_PROP_URI; use iceberg_test_utils::{get_minio_endpoint, get_rest_catalog_endpoint, set_up}; /// Global test fixture that uses environment-based configuration. -/// This assumes Docker containers are started externally (e.g., via `make docker-up`). +/// This assumes Docker containers are started externally (e.g., via `mise run docker-up`). pub struct GlobalTestFixture { pub catalog_config: HashMap, } diff --git a/crates/storage/opendal/tests/file_io_gcs_test.rs b/crates/storage/opendal/tests/file_io_gcs_test.rs index 5e04491131..3ab7754807 100644 --- a/crates/storage/opendal/tests/file_io_gcs_test.rs +++ b/crates/storage/opendal/tests/file_io_gcs_test.rs @@ -17,7 +17,7 @@ //! Integration tests for FileIO Google Cloud Storage (GCS). //! -//! These tests assume Docker containers are started externally via `make docker-up`. +//! These tests assume Docker containers are started externally via `mise run docker-up`. #[cfg(feature = "opendal-gcs")] mod tests { diff --git a/crates/storage/opendal/tests/file_io_s3_test.rs b/crates/storage/opendal/tests/file_io_s3_test.rs index d5858e18f4..117f3947cf 100644 --- a/crates/storage/opendal/tests/file_io_s3_test.rs +++ b/crates/storage/opendal/tests/file_io_s3_test.rs @@ -17,7 +17,7 @@ //! Integration tests for FileIO S3. //! -//! These tests assume Docker containers are started externally via `make docker-up`. +//! These tests assume Docker containers are started externally via `mise run docker-up`. //! Each test uses unique file paths based on module path to avoid conflicts. #[cfg(feature = "opendal-s3")] mod tests { diff --git a/crates/storage/opendal/tests/resolving_storage_test.rs b/crates/storage/opendal/tests/resolving_storage_test.rs index 1853a796dd..403a98599b 100644 --- a/crates/storage/opendal/tests/resolving_storage_test.rs +++ b/crates/storage/opendal/tests/resolving_storage_test.rs @@ -17,7 +17,7 @@ //! Integration tests for OpenDalResolvingStorage. //! -//! These tests assume Docker containers are started externally via `make docker-up`. +//! These tests assume Docker containers are started externally via `mise run docker-up`. //! Each test uses unique file paths based on module path to avoid conflicts. #[cfg(all( diff --git a/dev/release/verify_rc.sh b/dev/release/verify_rc.sh index c4a8413f54..668781533d 100755 --- a/dev/release/verify_rc.sh +++ b/dev/release/verify_rc.sh @@ -422,23 +422,26 @@ check_license_headers() { } test_source_distribution() { - require_command make + require_command mise ( trap - ERR cd "${ARCHIVE_BASE_NAME}" - make build - make test + mise trust --yes mise.toml + mise install + mise run build + mise run test ) } test_python_distribution() { - require_command make - require_command uv + require_command mise ( trap - ERR - cd "${ARCHIVE_BASE_NAME}/bindings/python" - make install - make test + cd "${ARCHIVE_BASE_NAME}" + mise trust --yes mise.toml + mise install + mise run python:install + mise run python:test ) } diff --git a/dev/verify_libpython.py b/dev/verify_libpython.py new file mode 100644 index 0000000000..22b80a1d93 --- /dev/null +++ b/dev/verify_libpython.py @@ -0,0 +1,128 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Verify that the mise-managed Python installation provides libpython.""" + +from __future__ import annotations + +import os +from pathlib import Path +import subprocess +import sys +import sysconfig + + +def fail(message: str) -> None: + print(f"libpython verification failed: {message}", file=sys.stderr) + raise SystemExit(1) + + +def normalized(path: Path) -> str: + return os.path.normcase(str(path.resolve())) + + +def mise_python_prefix() -> Path: + try: + result = subprocess.run( + ["mise", "where", "python"], + check=True, + capture_output=True, + text=True, + ) + except FileNotFoundError: + fail("mise is not available on PATH") + except subprocess.CalledProcessError as error: + detail = error.stderr.strip() or error.stdout.strip() or str(error) + fail(f"could not locate mise Python: {detail}") + + return Path(result.stdout.strip()) + + +def require_file(description: str, candidates: list[Path]) -> Path: + for candidate in candidates: + if candidate.is_file(): + return candidate + + searched = "\n ".join(str(candidate) for candidate in candidates) + fail(f"{description} was not found; searched:\n {searched}") + + +def verify_windows(prefix: Path) -> list[Path]: + version = f"{sys.version_info.major}{sys.version_info.minor}" + dll_name = sysconfig.get_config_var("LDLIBRARY") or f"python{version}.dll" + if not dll_name.lower().endswith(".dll"): + dll_name = f"python{version}.dll" + + dll = require_file( + "the Python DLL", + [ + prefix / dll_name, + prefix / "DLLs" / dll_name, + Path(sys.executable).parent / dll_name, + ], + ) + + import_name = sysconfig.get_config_var("LIBRARY") or f"python{version}.lib" + if not import_name.lower().endswith(".lib"): + import_name = f"python{version}.lib" + libdir = sysconfig.get_config_var("LIBDIR") + import_candidates = [prefix / "libs" / import_name, prefix / "Libs" / import_name] + if libdir: + import_candidates.insert(0, Path(libdir) / import_name) + import_library = require_file("the Python import library", import_candidates) + + return [dll, import_library] + + +def verify_unix(prefix: Path) -> list[Path]: + library_name = sysconfig.get_config_var("LDLIBRARY") + is_shared = library_name and ( + library_name.endswith((".so", ".dylib")) or ".so." in library_name + ) + if not is_shared: + fail(f"LDLIBRARY does not identify a shared library: {library_name!r}") + + libdir = sysconfig.get_config_var("LIBDIR") + candidates = [prefix / "lib" / library_name] + if libdir: + candidates.insert(0, Path(libdir) / library_name) + return [require_file("the shared Python library", candidates)] + + +def main() -> None: + prefix = mise_python_prefix() + base_prefix = Path(sys.base_prefix) + if normalized(base_prefix) != normalized(prefix): + fail( + "the active interpreter is not the configured mise Python " + f"(active: {base_prefix}; mise: {prefix})" + ) + + # Windows sysconfig does not expose Py_ENABLE_SHARED even though the + # standard CPython layout is DLL-based. The DLL and import-library checks + # below are the authoritative equivalent on that platform. + if os.name != "nt" and sysconfig.get_config_var("Py_ENABLE_SHARED") != 1: + fail("Py_ENABLE_SHARED is not enabled") + + libraries = verify_windows(prefix) if os.name == "nt" else verify_unix(prefix) + print(f"Verified mise Python {sys.version.split()[0]} at {prefix}") + for library in libraries: + print(f"Verified {library}") + + +if __name__ == "__main__": + main() diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000000..f61bb61edb --- /dev/null +++ b/mise.toml @@ -0,0 +1,217 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +min_version = "2026.6.14" + +[settings.python] +# Python is also a build dependency: the DataFusion bindings need libpython. +# Refuse to fall back to a locally compiled interpreter with a different layout. +compile = false +precompiled_flavor = "install_only_stripped" + +[tools] +"cargo:cargo-machete" = { version = "0.7.0", depends = "rust" } +"cargo:cargo-nextest" = { version = "0.9.138", depends = "rust" } +"cargo:cargo-public-api" = { version = "0.51.0", depends = "rust" } +jq = "1.8.2" +mdbook = "0.4.36" +protoc = "35.1" +python = "3.12.13" +ruff = "0.15.20" +rust = [ + { version = "nightly-2026-03-05", components = "rustfmt,clippy" }, + { version = "1.94.0" }, +] +taplo = "0.9.3" +uv = "0.9.3" + +[tasks.build] +depends = ["python:verify-libpython"] +description = "Build all workspace targets and features" +run = "cargo build --all-targets --all-features --workspace" + +[tasks.check-fmt] +description = "Check Rust formatting" +run = "cargo fmt --all -- --check" + +[tasks.check-clippy] +depends = ["python:verify-libpython"] +description = "Run Clippy for all workspace targets and features" +run = "cargo clippy --all-targets --all-features --workspace -- -D warnings" + +[tasks.fix-toml] +description = "Format TOML files" +run = "taplo fmt" + +[tasks.check-toml] +description = "Check TOML formatting" +run = "taplo fmt --check" + +[tasks.cargo-machete] +description = "Find unused Cargo dependencies" +run = "cargo machete" + +[tasks.check-msrv] +depends = ["python:verify-libpython"] +description = "Check the workspace with the minimum supported Rust version" +run = "cargo +1.94.0 check --workspace" + +[tasks.generate-public-api] +description = "Regenerate public API snapshots for publishable crates" +run = ''' +#!/usr/bin/env bash +set -euo pipefail + +while IFS=$'\t' read -r crate manifest; do + crate_dir=$(dirname "$manifest") + echo "Generating public API for $crate..." + cargo public-api -p "$crate" --all-features -ss > "$crate_dir/public-api.txt" +done < <( + cargo metadata --no-deps --format-version 1 | + jq -r '.packages[] | select(.publish == null) | [.name, .manifest_path] | @tsv' +) +''' + +[tasks.check-public-api] +description = "Check public API snapshots for publishable crates" +run = ''' +#!/usr/bin/env bash +set -euo pipefail + +tmp_dir=$(mktemp -d) +trap 'rm -rf "$tmp_dir"' EXIT +failed=0 + +while IFS=$'\t' read -r crate manifest; do + crate_dir=$(dirname "$manifest") + generated="$tmp_dir/$crate.txt" + echo "Checking public API for $crate..." + cargo public-api -p "$crate" --all-features -ss > "$generated" + if ! diff -u "$crate_dir/public-api.txt" "$generated"; then + echo "ERROR: Public API for $crate has changed. Run 'mise run generate-public-api' to update." + failed=1 + fi +done < <( + cargo metadata --no-deps --format-version 1 | + jq -r '.packages[] | select(.publish == null) | [.name, .manifest_path] | @tsv' +) + +exit "$failed" +''' + +[tasks.check] +depends = ["check-fmt", "check-clippy", "check-toml", "cargo-machete"] +description = "Run all formatting and lint checks" + +[tasks.doc-test] +depends = ["python:verify-libpython"] +description = "Run workspace documentation tests" +run = "cargo test --no-fail-fast --doc --all-features --workspace" + +[tasks.unit-test] +depends = ["doc-test"] +description = "Run workspace documentation and library tests" +run = "cargo test --no-fail-fast --lib --all-features --workspace" + +[tasks.nextest] +depends = ["python:verify-libpython"] +description = "Run all workspace tests with cargo-nextest" +run = "cargo nextest run --all-targets --all-features --workspace" + +[tasks.test] +description = "Run Docker-backed integration tests and always clean up" +run = ''' +#!/usr/bin/env bash +set -euo pipefail + +cleanup() { + task_status=$? + trap - EXIT + cleanup_status=0 + mise run docker-down || cleanup_status=$? + if [ "$task_status" -ne 0 ]; then + exit "$task_status" + fi + exit "$cleanup_status" +} +trap cleanup EXIT + +mise run docker-up +mise run nextest +''' + +[tasks.clean] +description = "Remove Cargo build artifacts" +run = "cargo clean" + +[tasks.site] +description = "Serve the documentation website locally" +dir = "website" +run = "mdbook serve" + +[tasks.site-build] +description = "Build the documentation website" +dir = "website" +run = "mdbook build" + +[tasks.docker-up] +description = "Start integration-test services" +run = "docker compose -f dev/docker-compose.yaml up -d --build --wait" + +[tasks.docker-down] +description = "Stop integration-test services and remove their volumes" +run = "docker compose -f dev/docker-compose.yaml down -v --remove-orphans --timeout 0" + +[tasks.docker-logs] +description = "Follow integration-test service logs" +raw = true +run = "docker compose -f dev/docker-compose.yaml logs -f" + +[tasks."python:verify-libpython"] +description = "Verify that mise Python provides a shared libpython" +run = "python dev/verify_libpython.py" + +[tasks."python:build"] +depends = ["python:verify-libpython"] +description = "Build and install the Python extension into its virtual environment" +dir = "bindings/python" +run = "uv run --no-sync maturin develop" + +[tasks."python:install"] +depends = ["python:verify-libpython"] +description = "Install Python development dependencies and rebuild the extension" +dir = "bindings/python" +run = [ + "uv sync --python 3.12 --no-managed-python --no-python-downloads --group dev --no-install-project", + { task = "python:build" }, +] + +[tasks."python:test"] +depends = ["python:verify-libpython"] +description = "Run Python binding tests" +dir = "bindings/python" +run = "uv run --no-sync pytest" + +[tasks."python:check-format"] +description = "Check Python formatting" +dir = "bindings/python" +run = "ruff format --check ." + +[tasks."python:check-style"] +description = "Check Python style" +dir = "bindings/python" +run = "ruff check ." diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 217e2256bd..0000000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# iceberg-rust use unstable rust to run linters, such as `clippy` and `rustfmt`. But this will not affect downstream users, -# and only MSRV is required. -# -# The channel is exactly same day for our MSRV. -[toolchain] -channel = "nightly-2026-03-05" -components = ["rustfmt", "clippy"] diff --git a/website/README.md b/website/README.md index 8d0f50345d..b36d668fe1 100644 --- a/website/README.md +++ b/website/README.md @@ -21,8 +21,10 @@ ## Preview -This will automatically install mdbook if needed. +Complete the root [contributor setup](../CONTRIBUTING.md#setup), then use mise from the repository root to install the pinned mdBook version and start a local preview: ```shell -make site +mise run site ``` + +Run `mise run site-build` to build the site without starting a server. diff --git a/website/src/reference/container-runtimes.md b/website/src/reference/container-runtimes.md index 7b4ac38511..75e8c67bfe 100644 --- a/website/src/reference/container-runtimes.md +++ b/website/src/reference/container-runtimes.md @@ -19,7 +19,7 @@ # Container Runtimes -Iceberg-rust uses containers for integration tests, where `docker` and `docker compose` start containers for MinIO and various catalogs. You can use any of the following container runtimes. +Iceberg-rust uses containers for integration tests, where `docker` and `docker compose` start containers for MinIO and various catalogs. Complete the repository's mise setup first, then use any of the following container runtimes. ## Docker Desktop @@ -40,7 +40,7 @@ Iceberg-rust uses containers for integration tests, where `docker` and `docker c 4. Try some integration tests! ```shell - make test + mise run test ``` ## OrbStack (macOS) @@ -69,7 +69,7 @@ Iceberg-rust uses containers for integration tests, where `docker` and `docker c 4. Try some integration tests! ```shell - make test + mise run test ``` ## Podman @@ -131,7 +131,7 @@ Iceberg-rust uses containers for integration tests, where `docker` and `docker c 8. Try some integration tests! ```shell - cargo test -p iceberg --test file_io_s3_test + mise run test ``` ### Note on rootless containers diff --git a/website/src/release.md b/website/src/release.md index 4115d3e080..85020c3d1b 100644 --- a/website/src/release.md +++ b/website/src/release.md @@ -66,6 +66,7 @@ Install the release tooling used by the local scripts: - `cargo-deny` - `docker` - `gpg` +- `mise` 2026.6.14 or newer - `svn` The local release helpers are under `dev/release/`. They log every step before it runs and after it succeeds. If a step fails, the script prints the failed step and stops. @@ -428,17 +429,18 @@ After downloading them, here are the instructions on how to verify them. ```bash tar -xzf apache-iceberg-rust-*.tar.gz cd apache-iceberg-rust-*/ - make build && make test + # Review mise.toml before trusting the release candidate. + mise trust + mise install + mise run build + mise run test ``` - Verify pyiceberg-core build and tests: ```bash - ( - cd bindings/python - make install - make test - ) + mise run python:install + mise run python:test ``` - Verify license headers: