From a8328b74ce1e72e179cd2d3114c579c1b2298926 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Thu, 12 Feb 2026 23:23:55 +0000 Subject: [PATCH] Update --- .github/workflows/cli-release.yml | 331 ++++++++++++++++++++++++++++++ .github/workflows/cli-rust.yml | 49 +++++ libs/cli/.gitignore | 9 + libs/cli/Cargo.toml | 6 + libs/cli/Makefile | 57 ++++- libs/cli/pyproject.toml | 23 +-- libs/cli/scripts/bump-version.sh | 49 +++++ 7 files changed, 504 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/cli-release.yml create mode 100644 .github/workflows/cli-rust.yml create mode 100755 libs/cli/scripts/bump-version.sh diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml new file mode 100644 index 000000000..1986ab449 --- /dev/null +++ b/.github/workflows/cli-release.yml @@ -0,0 +1,331 @@ +--- +name: CLI Release + +on: + push: + tags: + - 'cli-v*' + workflow_dispatch: + inputs: + tag: + description: 'Release tag (e.g., cli-v0.2.10)' + required: true + +permissions: + contents: write + id-token: write # OIDC trusted publishing for PyPI + +concurrency: + group: cli-release + cancel-in-progress: false + +env: + CARGO_TERM_COLOR: always + +jobs: + # ────────────────────────────────────────────── + # Build native binaries for each platform + # ────────────────────────────────────────────── + build: + name: Build - ${{ matrix.name }} + runs-on: ${{ matrix.runner }} + defaults: + run: + working-directory: libs/cli + strategy: + fail-fast: false + matrix: + include: + - name: linux-x64 + runner: ubuntu-latest + target: x86_64-unknown-linux-gnu + binary: langgraph + npm_pkg: langgraph-cli-linux-x64 + + - name: linux-arm64 + runner: ubuntu-24.04-arm + target: aarch64-unknown-linux-gnu + binary: langgraph + npm_pkg: langgraph-cli-linux-arm64 + + - name: darwin-x64 + runner: macos-13 # Intel + target: x86_64-apple-darwin + binary: langgraph + npm_pkg: langgraph-cli-darwin-x64 + + - name: darwin-arm64 + runner: macos-latest # Apple Silicon + target: aarch64-apple-darwin + binary: langgraph + npm_pkg: langgraph-cli-darwin-arm64 + + - name: win32-x64 + runner: windows-latest + target: x86_64-pc-windows-msvc + binary: langgraph.exe + npm_pkg: langgraph-cli-win32-x64 + + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: libs/cli + key: ${{ matrix.target }} + + - name: Build release binary + run: cargo build --release --target ${{ matrix.target }} + + - name: Run tests + if: matrix.name != 'linux-arm64' # skip on ARM (slow QEMU) + run: cargo test --release --target ${{ matrix.target }} + + # Upload raw binary for GitHub release + - name: Prepare binary artifact + shell: bash + run: | + mkdir -p dist + cp target/${{ matrix.target }}/release/${{ matrix.binary }} dist/ + cd dist + if [[ "${{ matrix.name }}" == win32-* ]]; then + 7z a ../langgraph-${{ matrix.name }}.zip ${{ matrix.binary }} + else + tar czf ../langgraph-${{ matrix.name }}.tar.gz ${{ matrix.binary }} + fi + + - name: Upload binary artifact + uses: actions/upload-artifact@v4 + with: + name: binary-${{ matrix.name }} + path: | + libs/cli/langgraph-${{ matrix.name }}.tar.gz + libs/cli/langgraph-${{ matrix.name }}.zip + if-no-files-found: ignore + + # Prepare npm platform package + - name: Prepare npm platform package + shell: bash + run: | + cp target/${{ matrix.target }}/release/${{ matrix.binary }} npm/${{ matrix.npm_pkg }}/bin/ + + - name: Upload npm platform package + uses: actions/upload-artifact@v4 + with: + name: npm-${{ matrix.name }} + path: libs/cli/npm/${{ matrix.npm_pkg }}/ + + # ────────────────────────────────────────────── + # Build Linux musl (Alpine-compatible) binary + # ────────────────────────────────────────────── + build-musl: + name: Build - linux-x64-musl + runs-on: ubuntu-latest + defaults: + run: + working-directory: libs/cli + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + targets: x86_64-unknown-linux-musl + + - name: Install musl tools + run: sudo apt-get update && sudo apt-get install -y musl-tools + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: libs/cli + key: x86_64-unknown-linux-musl + + - name: Build release binary + run: cargo build --release --target x86_64-unknown-linux-musl + + - name: Prepare binary artifact + run: | + mkdir -p dist + cp target/x86_64-unknown-linux-musl/release/langgraph dist/ + cd dist && tar czf ../langgraph-linux-x64-musl.tar.gz langgraph + + - name: Upload binary artifact + uses: actions/upload-artifact@v4 + with: + name: binary-linux-x64-musl + path: libs/cli/langgraph-linux-x64-musl.tar.gz + + # ────────────────────────────────────────────── + # Build PyPI wheels via maturin + # ────────────────────────────────────────────── + pypi-wheels: + name: PyPI wheel - ${{ matrix.name }} + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - name: linux-x64 + runner: ubuntu-latest + target: x86_64-unknown-linux-gnu + manylinux: manylinux_2_17 + + - name: linux-arm64 + runner: ubuntu-24.04-arm + target: aarch64-unknown-linux-gnu + manylinux: manylinux_2_17 + + - name: linux-x64-musl + runner: ubuntu-latest + target: x86_64-unknown-linux-musl + manylinux: musllinux_1_2 + + - name: darwin-x64 + runner: macos-13 + target: x86_64-apple-darwin + manylinux: auto + + - name: darwin-arm64 + runner: macos-latest + target: aarch64-apple-darwin + manylinux: auto + + - name: win32-x64 + runner: windows-latest + target: x86_64-pc-windows-msvc + manylinux: auto + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Build wheel + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.target }} + manylinux: ${{ matrix.manylinux }} + args: --release --manifest-path libs/cli/Cargo.toml --out libs/cli/dist + rust-toolchain: stable + + - name: Upload wheel + uses: actions/upload-artifact@v4 + with: + name: wheel-${{ matrix.name }} + path: libs/cli/dist/*.whl + + # ────────────────────────────────────────────── + # Build sdist + # ────────────────────────────────────────────── + pypi-sdist: + name: PyPI sdist + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build sdist + uses: PyO3/maturin-action@v1 + with: + command: sdist + args: --manifest-path libs/cli/Cargo.toml --out libs/cli/dist + + - name: Upload sdist + uses: actions/upload-artifact@v4 + with: + name: sdist + path: libs/cli/dist/*.tar.gz + + # ────────────────────────────────────────────── + # Publish to PyPI + # ────────────────────────────────────────────── + pypi-publish: + name: Publish to PyPI + needs: [pypi-wheels, pypi-sdist] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/cli-v') + environment: + name: pypi + url: https://pypi.org/project/langgraph-cli/ + steps: + - uses: actions/download-artifact@v4 + with: + pattern: wheel-* + path: dist + merge-multiple: true + + - uses: actions/download-artifact@v4 + with: + name: sdist + path: dist + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + # ────────────────────────────────────────────── + # Publish to npm + # ────────────────────────────────────────────── + npm-publish: + name: Publish to npm + needs: [build] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/cli-v') + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "20" + registry-url: "https://registry.npmjs.org" + + # Download all npm platform packages + - uses: actions/download-artifact@v4 + with: + pattern: npm-* + path: npm-artifacts + + # Publish each platform package + - name: Publish platform packages + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + for dir in npm-artifacts/npm-*/; do + echo "Publishing $(basename $dir)..." + cd "$dir" + npm publish --access public + cd - + done + + # Publish the main package + - name: Publish main package + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + cd libs/cli/npm/langgraph-cli + npm publish --access public + + # ────────────────────────────────────────────── + # Create GitHub Release with standalone binaries + # ────────────────────────────────────────────── + github-release: + name: GitHub Release + needs: [build, build-musl] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/cli-v') + steps: + - uses: actions/download-artifact@v4 + with: + pattern: binary-* + path: release-artifacts + merge-multiple: true + + - name: Create release + uses: softprops/action-gh-release@v2 + with: + files: release-artifacts/* + generate_release_notes: true + draft: false diff --git a/.github/workflows/cli-rust.yml b/.github/workflows/cli-rust.yml new file mode 100644 index 000000000..11f51a5ef --- /dev/null +++ b/.github/workflows/cli-rust.yml @@ -0,0 +1,49 @@ +--- +name: CLI Rust + +on: + push: + branches: + - main + paths: + - 'libs/cli/src/**' + - 'libs/cli/Cargo.toml' + - 'libs/cli/Cargo.lock' + - 'libs/cli/build.rs' + pull_request: + paths: + - 'libs/cli/src/**' + - 'libs/cli/Cargo.toml' + - 'libs/cli/Cargo.lock' + - 'libs/cli/build.rs' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + name: Check / Lint / Test + runs-on: ubuntu-latest + defaults: + run: + working-directory: libs/cli + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + with: + workspaces: libs/cli + - name: Format check + run: cargo fmt --check + - name: Clippy + run: cargo clippy -- -D warnings + - name: Test + run: cargo test + - name: Build release + run: cargo build --release diff --git a/libs/cli/.gitignore b/libs/cli/.gitignore index 132fa2e54..40df3c869 100644 --- a/libs/cli/.gitignore +++ b/libs/cli/.gitignore @@ -1 +1,10 @@ .langgraph_api/ +npm/ + +# Rust build artifacts +/target/ +/dist/ + +# npm platform binaries (added at build time, not checked in) +npm/*/bin/langgraph +npm/*/bin/langgraph.exe diff --git a/libs/cli/Cargo.toml b/libs/cli/Cargo.toml index 1cb46eca1..6ab969e54 100644 --- a/libs/cli/Cargo.toml +++ b/libs/cli/Cargo.toml @@ -30,3 +30,9 @@ which = "7" [dev-dependencies] assert_cmd = "2" predicates = "3" + +[profile.release] +opt-level = 3 +lto = "thin" +codegen-units = 1 +strip = "symbols" diff --git a/libs/cli/Makefile b/libs/cli/Makefile index 60a781d8e..5953098e7 100644 --- a/libs/cli/Makefile +++ b/libs/cli/Makefile @@ -1,7 +1,27 @@ -.PHONY: test lint format test-integration update-schema bump-version +.PHONY: test lint format test-integration update-schema build build-release clean cargo-test cargo-lint ###################### -# TESTING AND COVERAGE +# RUST BUILD +###################### + +build: + cargo build + +build-release: + cargo build --release + +cargo-test: + cargo test + +cargo-lint: + cargo fmt --check + cargo clippy -- -D warnings + +cargo-fmt: + cargo fmt + +###################### +# PYTHON TESTING AND COVERAGE ###################### TEST?= "tests/unit_tests" @@ -11,7 +31,7 @@ test-integration: uv run pytest tests/integration_tests ###################### -# LINTING AND FORMATTING +# PYTHON LINTING AND FORMATTING ###################### # Define a variable for Python and notebook files. @@ -33,8 +53,35 @@ format format_diff: uv run ruff format $(PYTHON_FILES) uv run ruff check --select I --fix $(PYTHON_FILES) +###################### +# PACKAGING +###################### + +# Build maturin wheel for current platform (development) +wheel-dev: + maturin build --release + +# Build maturin wheel for specific target +# Usage: make wheel TARGET=x86_64-unknown-linux-gnu +TARGET?= +wheel: + maturin build --release $(if $(TARGET),--target $(TARGET),) + +# Build sdist +sdist: + maturin sdist + +###################### +# SCHEMA +###################### + update-schema: uv run python generate_schema.py -bump-version: - uv run hatch version patch +###################### +# CLEANUP +###################### + +clean: + cargo clean + rm -rf dist/ target/wheels/ diff --git a/libs/cli/pyproject.toml b/libs/cli/pyproject.toml index ef6d30265..fbda76d18 100644 --- a/libs/cli/pyproject.toml +++ b/libs/cli/pyproject.toml @@ -1,6 +1,6 @@ [build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" +requires = ["maturin>=1.0,<2.0"] +build-backend = "maturin" [project] name = "langgraph-cli" @@ -11,12 +11,8 @@ requires-python = ">=3.10" readme = "README.md" license = "MIT" license-files = ['LICENSE'] -dependencies = [ - "click>=8.1.7", - "langgraph-sdk>=0.1.0 ; python_version >= '3.11'", -] -[tool.hatch.version] -path = "langgraph_cli/__init__.py" +dependencies = [] + [project.optional-dependencies] inmem = [ "langgraph-api>=0.5.35,<0.8.0 ; python_version >= '3.11'", @@ -30,8 +26,10 @@ Twitter = "https://x.com/LangChain" Slack = "https://www.langchain.com/join-community" Reddit = "https://www.reddit.com/r/LangChain/" -[project.scripts] -langgraph = "langgraph_cli.cli:cli" +[tool.maturin] +bindings = "bin" +manifest-path = "Cargo.toml" +strip = true [dependency-groups] test = [ @@ -49,15 +47,11 @@ lint = [ dev = [ {include-group = "test"}, {include-group = "lint"}, - "hatch>=1.16.2", ] [tool.uv] default-groups = ['dev'] -[tool.hatch.build.targets.wheel] -include = ["langgraph_cli"] - [tool.pytest.ini_options] addopts = "--strict-markers --strict-config --durations=5 -vv" asyncio_mode = "auto" @@ -69,7 +63,6 @@ lint.select = [ "UP", # pyupgrade "B", # flake8-bugbear "I", # isort - "UP", # pyupgrade ] lint.ignore = ["E501", "B008"] target-version = "py310" diff --git a/libs/cli/scripts/bump-version.sh b/libs/cli/scripts/bump-version.sh new file mode 100755 index 000000000..11a345d4c --- /dev/null +++ b/libs/cli/scripts/bump-version.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Bumps the version across Cargo.toml and all npm package.json files. +# Usage: ./scripts/bump-version.sh 0.3.0 + +set -euo pipefail + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + echo "Example: $0 0.3.0" + exit 1 +fi + +VERSION="$1" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CLI_DIR="$(dirname "$SCRIPT_DIR")" + +echo "Bumping version to $VERSION" + +# Cargo.toml +sed -i.bak "s/^version = \".*\"/version = \"$VERSION\"/" "$CLI_DIR/Cargo.toml" +rm -f "$CLI_DIR/Cargo.toml.bak" +echo " Updated Cargo.toml" + +# All npm package.json files +for pkg in "$CLI_DIR"/npm/*/package.json; do + # Update the package's own version + sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$pkg" + rm -f "$pkg.bak" + + # Update optionalDependencies versions (main package only) + if grep -q "optionalDependencies" "$pkg" 2>/dev/null; then + sed -i.bak "s/\"@langchain\/langgraph-cli-\([^\"]*\)\": \"[^\"]*\"/\"@langchain\/langgraph-cli-\1\": \"$VERSION\"/" "$pkg" + rm -f "$pkg.bak" + fi + + echo " Updated $(basename "$(dirname "$pkg")")/package.json" +done + +# Update Cargo.lock +cd "$CLI_DIR" +cargo update -p langgraph-cli 2>/dev/null || true +echo " Updated Cargo.lock" + +echo "Done! Version is now $VERSION" +echo "" +echo "Next steps:" +echo " 1. git add -A && git commit -m 'chore(cli): bump version to $VERSION'" +echo " 2. git tag cli-v$VERSION" +echo " 3. git push origin main --tags"