mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-23 18:15:08 +02:00
1afaca35a0
Adds `--image-uri <uri>` to `langgraph deploy` so self-hosted LangSmith customers can build, push, and deploy in one command without needing to script the three steps manually. When `--image-uri` is provided the CLI: - Builds the image tagged to the provided URI (same Docker build path as the local build flow) - Pushes using whatever Docker credentials are already in the environment (e.g. WIF, `aws ecr get-login-password`) — no auth handling in the CLI - PATCHes the deployment with `source_revision_config.image_uri` (no `revision_source`, which the self-hosted control plane rejects for `external_docker` deployments) Also fixes two self-hosted-specific issues uncovered during testing: - `LANGSMITH_ENDPOINT` is now used as a fallback when `LANGGRAPH_HOST_URL` isn't set — the CLI strips the `/api/v1` path and appends `/api-host` to reach the control plane - The httpx client now builds full URLs via string concatenation rather than relying on httpx base_url merging, which silently dropped the `/api-host` path prefix when paths started with `/` - The "Check status at" URL after a deploy now correctly points to the self-hosted LangSmith UI instead of `smith.langchain.com` **How did you verify your code works?** Tested end-to-end against a self-hosted LangSmith instance using ECR as the registry. `langgraph deploy --image-uri <ecr-uri>` successfully built, pushed, and triggered a deployment revision. Confirmed the existing SaaS flow (`langgraph deploy` without `--image-uri`) is unaffected — the new flag is opt-in and the `LANGSMITH_ENDPOINT` fallback only activates when `LANGGRAPH_HOST_URL` is unset and `LANGSMITH_ENDPOINT` is present. --------- Co-authored-by: Hari Dhanushkodi <hari-dhanushkodi@users.noreply.github.com> Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> Co-authored-by: Hugo Durand <hugo.durand@langchain.dev>
72 lines
2.1 KiB
Python
72 lines
2.1 KiB
Python
import pytest
|
|
|
|
from langgraph_cli.image_reference import ImageReference
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("reference", "repository", "tag"),
|
|
[
|
|
pytest.param(
|
|
"registry.example.com/team/app:v1",
|
|
"registry.example.com/team/app",
|
|
"v1",
|
|
id="tag_after_last_slash",
|
|
),
|
|
pytest.param(
|
|
"registry.example.com/team/app",
|
|
"registry.example.com/team/app",
|
|
None,
|
|
id="no_tag",
|
|
),
|
|
pytest.param(
|
|
"localhost:5000/app",
|
|
"localhost:5000/app",
|
|
None,
|
|
id="registry_port_is_not_a_tag",
|
|
),
|
|
pytest.param(
|
|
"localhost:5000/app:latest",
|
|
"localhost:5000/app",
|
|
"latest",
|
|
id="registry_port_with_tag",
|
|
),
|
|
pytest.param("app:dev", "app", "dev", id="bare_name_with_tag"),
|
|
],
|
|
)
|
|
def test_parse_splits_repository_and_tag(reference, repository, tag):
|
|
assert ImageReference.parse(reference) == ImageReference(repository, tag)
|
|
|
|
|
|
def test_with_tag_replaces_the_tag():
|
|
assert ImageReference("r/app", "v1").with_tag("v2") == ImageReference("r/app", "v2")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("reference", "expected"),
|
|
[
|
|
pytest.param(ImageReference("r/app", "v1"), "r/app:v1", id="tagged"),
|
|
pytest.param(ImageReference("r/app"), "r/app", id="untagged"),
|
|
],
|
|
)
|
|
def test_str_renders_the_docker_reference(reference, expected):
|
|
assert str(reference) == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("repo_digest", "expected"),
|
|
[
|
|
pytest.param("localhost:5000/app@sha256:abc", True, id="same_repository"),
|
|
pytest.param("localhost:5000/app-2@sha256:abc", False, id="other_repository"),
|
|
pytest.param("mirror.example.com/app@sha256:abc", False, id="other_registry"),
|
|
],
|
|
)
|
|
def test_matches_digest_only_for_the_same_repository(repo_digest, expected):
|
|
assert ImageReference("localhost:5000/app", "v1").matches_digest(repo_digest) is (
|
|
expected
|
|
)
|
|
|
|
|
|
def test_parse_rejects_a_digest_reference():
|
|
with pytest.raises(ValueError, match="digest"):
|
|
ImageReference.parse("registry.example.com/app@sha256:abc")
|