Add Go CLI CI smoke coverage

This commit is contained in:
Will Fu-Hinthorn
2026-04-08 16:07:25 -07:00
parent fa2a8f0a92
commit c53a91376c
5 changed files with 193 additions and 0 deletions
+45
View File
@@ -9,6 +9,9 @@ on:
permissions:
contents: read
env:
GO_VERSION: "1.23"
jobs:
build:
runs-on: ubuntu-latest
@@ -51,12 +54,23 @@ jobs:
python-version: ${{ matrix.python-version }}
enable-cache: "false"
working-directory: libs/cli
- name: Set up Go
if: (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch')
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Install cli globally
if: (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch')
run: pip install -e .
- name: Build Go CLI binary
if: (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch')
run: make build-go
- name: Build service ${{ matrix.example.name }}
if: (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch')
working-directory: ${{ matrix.example.workdir }}
env:
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
langgraph build -t ${{ matrix.example.tag }}
- name: Test service ${{ matrix.example.name }}
@@ -64,6 +78,8 @@ jobs:
working-directory: ${{ matrix.example.workdir }}
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
# Prepare environment file from local or parent example directory
if [ -f .env.example ]; then cp .env.example .env; elif [ -f ../.env.example ]; then cp ../.env.example .env && cp ../.env.example ../.env; fi
@@ -76,18 +92,27 @@ jobs:
- name: Build JS service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
working-directory: libs/cli/js-examples
env:
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
langgraph build -t langgraph-test-e
- name: Build JS monorepo service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
working-directory: libs/cli/js-monorepo-example
env:
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
langgraph build -t langgraph-test-f -c apps/agent/langgraph.json --build-command "yarn run turbo build" --install-command "yarn install"
- name: Build Python monorepo service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
working-directory: libs/cli/python-monorepo-example
env:
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
langgraph build -t langgraph-test-g -c apps/agent/langgraph.json
- name: Test Python monorepo service
@@ -95,6 +120,8 @@ jobs:
working-directory: libs/cli/python-monorepo-example
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
cp apps/agent/.env.example apps/agent/.env
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> apps/agent/.env
@@ -103,6 +130,9 @@ jobs:
- name: Build prerelease reqs service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
working-directory: libs/cli/examples/graph_prerelease_reqs
env:
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
langgraph build -t langgraph-test-h
- name: Test prerelease reqs service
@@ -110,6 +140,8 @@ jobs:
working-directory: libs/cli/examples/graph_prerelease_reqs
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
cp ../.env.example .env
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
@@ -134,12 +166,18 @@ jobs:
- name: Build and test prerelease reqs fail service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
working-directory: libs/cli/examples/graph_prerelease_reqs_fail
env:
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
langgraph build -t langgraph-test-i || [ $? -eq 1 ]
- name: Build uv simple service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
working-directory: libs/cli/uv-examples/simple
env:
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
langgraph build -t langgraph-test-uv-simple
- name: Test uv simple service
@@ -147,6 +185,8 @@ jobs:
working-directory: libs/cli/uv-examples/simple
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
cp .env.example .env
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
@@ -155,6 +195,9 @@ jobs:
- name: Build uv monorepo service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
working-directory: libs/cli/uv-examples/monorepo/apps/agent
env:
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
langgraph build -t langgraph-test-uv-monorepo
- name: Test uv monorepo service
@@ -162,6 +205,8 @@ jobs:
working-directory: libs/cli/uv-examples/monorepo/apps/agent
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: |
cp .env.example .env
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
+29
View File
@@ -11,6 +11,9 @@ on:
permissions:
contents: read
env:
GO_VERSION: "1.23"
jobs:
build:
runs-on: ubuntu-latest
@@ -26,12 +29,23 @@ jobs:
name: "test #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v6
- name: Get changed files
id: changed-files
if: ${{ inputs.working-directory == 'libs/cli' && github.event_name != 'workflow_dispatch' }}
uses: Ana06/get-changed-files@25f79e676e7ea1868813e21465014798211fad8c # v2.3.0
with:
filter: "libs/cli/**"
- name: Set up Python ${{ matrix.python-version }}
uses: ./.github/actions/uv_setup
with:
python-version: ${{ matrix.python-version }}
cache-suffix: test-${{ inputs.working-directory }}
working-directory: ${{ inputs.working-directory }}
- name: Set up Go
if: ${{ inputs.working-directory == 'libs/cli' && (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') }}
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Login to Docker Hub
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
if: ${{ !github.event.pull_request.head.repo.fork }}
@@ -44,11 +58,26 @@ jobs:
working-directory: ${{ inputs.working-directory }}
run: uv sync --frozen --group test --no-dev
- name: Build Go CLI binary
if: ${{ inputs.working-directory == 'libs/cli' && (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') }}
shell: bash
working-directory: ${{ inputs.working-directory }}
run: make build-go
- name: Run tests
shell: bash
working-directory: ${{ inputs.working-directory }}
run: make test
- name: Run Go CLI smoke tests
if: ${{ inputs.working-directory == 'libs/cli' && (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') }}
shell: bash
working-directory: ${{ inputs.working-directory }}
env:
LANGGRAPH_USE_GO_CLI: "1"
LANGGRAPH_GO_CLI_PATH: ${{ github.workspace }}/libs/cli/langgraph_cli/bin/langgraph
run: TEST='tests/unit_tests/test_go_cli_smoke.py' make test
- name: Ensure the tests did not create any additional files
shell: bash
working-directory: ${{ inputs.working-directory }}
+45
View File
@@ -10,6 +10,7 @@ on:
env:
PYTHON_VERSION: "3.10"
GO_VERSION: "1.23"
permissions:
contents: read
@@ -32,6 +33,17 @@ jobs:
cache-suffix: "release"
working-directory: ${{ inputs.working-directory }}
- name: Set up Go
if: inputs.working-directory == 'libs/cli'
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Cross-compile Go binaries
if: inputs.working-directory == 'libs/cli'
working-directory: ${{ inputs.working-directory }}
run: make build-go-all GO_BIN_DIR=build/go-bin
# We want to keep this build stage *separate* from the release stage,
# so that there's no sharing of permissions between them.
# The release stage has trusted publishing and GitHub repo contents write access,
@@ -43,7 +55,40 @@ jobs:
# > It is strongly advised to separate jobs for building [...]
# > from the publish job.
# https://github.com/pypa/gh-action-pypi-publish#non-goals
- name: Build CLI platform wheels
if: inputs.working-directory == 'libs/cli'
working-directory: ${{ inputs.working-directory }}
run: |
TARGETS=(
"linux-amd64 manylinux_2_17_x86_64.manylinux2014_x86_64"
"linux-arm64 manylinux_2_17_aarch64.manylinux2014_aarch64"
"linux-arm manylinux_2_17_armv7l.manylinux2014_armv7l"
"linux-386 manylinux_2_17_i686.manylinux2014_i686"
"linux-ppc64le manylinux_2_17_ppc64le.manylinux2014_ppc64le"
"linux-s390x manylinux_2_17_s390x.manylinux2014_s390x"
"linux-amd64 musllinux_1_2_x86_64"
"linux-arm64 musllinux_1_2_aarch64"
"linux-arm musllinux_1_2_armv7l"
"linux-386 musllinux_1_2_i686"
"darwin-amd64 macosx_11_0_x86_64"
"darwin-arm64 macosx_11_0_arm64"
"windows-amd64 win_amd64"
"windows-arm64 win_arm64"
"windows-386 win32"
)
for entry in "${TARGETS[@]}"; do
key=$(echo "$entry" | awk '{print $1}')
plat=$(echo "$entry" | awk '{print $2}')
ext=""
if [[ "$key" == windows-* ]]; then ext=".exe"; fi
binary="build/go-bin/langgraph-${key}${ext}"
LANGGRAPH_GO_BINARY="$binary" LANGGRAPH_WHEEL_PLAT="$plat" uv build --wheel
done
rm -rf langgraph_cli/bin
uv build
- name: Build project for distribution
if: inputs.working-directory != 'libs/cli'
run: uv build
working-directory: ${{ inputs.working-directory }}
+7
View File
@@ -308,6 +308,13 @@ jobs:
run: make test
working-directory: ${{ inputs.working-directory }}
- name: Run Go CLI smoke tests
if: inputs.working-directory == 'libs/cli'
working-directory: ${{ inputs.working-directory }}
env:
LANGGRAPH_USE_GO_CLI: "1"
run: uv run pytest tests/unit_tests/test_go_cli_smoke.py
publish:
needs:
- build
@@ -0,0 +1,67 @@
import os
import shutil
import subprocess
import pytest
@pytest.fixture
def go_cli_env():
if os.environ.get("LANGGRAPH_USE_GO_CLI") != "1":
pytest.skip("Go CLI smoke tests only run when LANGGRAPH_USE_GO_CLI=1")
langgraph = shutil.which("langgraph")
assert langgraph is not None, "langgraph executable is not installed"
env = os.environ.copy()
env["LANGGRAPH_USE_GO_CLI"] = "1"
return langgraph, env
def test_go_cli_help(go_cli_env):
langgraph, env = go_cli_env
result = subprocess.run(
[langgraph, "--help"],
capture_output=True,
text=True,
env=env,
check=False,
)
assert result.returncode == 0, result.stderr
assert "Usage: langgraph" in result.stdout
def test_go_cli_validate(go_cli_env, tmp_path):
langgraph, env = go_cli_env
config_path = tmp_path / "langgraph.json"
config_path.write_text(
'{"dependencies": ["langchain"], "graphs": {"agent": "./agent.py:graph"}}'
)
result = subprocess.run(
[langgraph, "validate", "-c", str(config_path)],
capture_output=True,
text=True,
env=env,
check=False,
)
assert result.returncode == 0, result.stderr
assert "is valid" in result.stdout
def test_go_cli_dev_help(go_cli_env):
langgraph, env = go_cli_env
result = subprocess.run(
[langgraph, "dev", "--help"],
capture_output=True,
text=True,
env=env,
check=False,
)
assert result.returncode == 0, result.stderr
assert "Run LangGraph API server in development mode" in result.stdout