graph-agents-cli 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- graph_agents_cli/__init__.py +26 -0
- graph_agents_cli/_api_policy.py +2145 -0
- graph_agents_cli/_approvals.py +400 -0
- graph_agents_cli/_build.py +186 -0
- graph_agents_cli/_build_info.json +7 -0
- graph_agents_cli/_chat_client.py +462 -0
- graph_agents_cli/_click.py +157 -0
- graph_agents_cli/_defaults.py +139 -0
- graph_agents_cli/_experiments.py +64 -0
- graph_agents_cli/_http.py +192 -0
- graph_agents_cli/_output.py +83 -0
- graph_agents_cli/_project.py +462 -0
- graph_agents_cli/_remote.py +220 -0
- graph_agents_cli/_response_schema.py +264 -0
- graph_agents_cli/_runner.py +319 -0
- graph_agents_cli/_skills_check.py +274 -0
- graph_agents_cli/_tools.py +189 -0
- graph_agents_cli/_trust.py +66 -0
- graph_agents_cli/api/__init__.py +15 -0
- graph_agents_cli/api/_changes.py +506 -0
- graph_agents_cli/api/_files.py +658 -0
- graph_agents_cli/api/cmd_api.py +2480 -0
- graph_agents_cli/deploy/__init__.py +15 -0
- graph_agents_cli/deploy/_config.py +171 -0
- graph_agents_cli/deploy/_image.py +128 -0
- graph_agents_cli/deploy/_kube.py +286 -0
- graph_agents_cli/deploy/_modes.py +234 -0
- graph_agents_cli/deploy/_preflight.py +370 -0
- graph_agents_cli/deploy/_values.py +168 -0
- graph_agents_cli/deploy/cmd_deploy.py +1866 -0
- graph_agents_cli/deploy/gitops.py +562 -0
- graph_agents_cli/deploy/local_load.py +273 -0
- graph_agents_cli/dev/__init__.py +13 -0
- graph_agents_cli/dev/cmd_build.py +131 -0
- graph_agents_cli/dev/cmd_install.py +78 -0
- graph_agents_cli/dev/cmd_lint.py +119 -0
- graph_agents_cli/dev/cmd_playground.py +297 -0
- graph_agents_cli/dev/policy_check.py +1287 -0
- graph_agents_cli/eval/__init__.py +22 -0
- graph_agents_cli/eval/_client.py +670 -0
- graph_agents_cli/eval/_common.py +177 -0
- graph_agents_cli/eval/_judge.py +168 -0
- graph_agents_cli/eval/_judge_runner.py +238 -0
- graph_agents_cli/eval/_paths.py +212 -0
- graph_agents_cli/eval/checks.py +581 -0
- graph_agents_cli/eval/cmd_analyze.py +278 -0
- graph_agents_cli/eval/cmd_compare.py +284 -0
- graph_agents_cli/eval/cmd_eval_group.py +80 -0
- graph_agents_cli/eval/cmd_generate.py +558 -0
- graph_agents_cli/eval/cmd_grade.py +466 -0
- graph_agents_cli/eval/cmd_metric.py +156 -0
- graph_agents_cli/eval/cmd_run.py +370 -0
- graph_agents_cli/eval/cmd_submit.py +400 -0
- graph_agents_cli/eval/config.py +435 -0
- graph_agents_cli/eval/dataset.py +350 -0
- graph_agents_cli/eval/gate.py +420 -0
- graph_agents_cli/eval/transcript.py +192 -0
- graph_agents_cli/extension/__init__.py +13 -0
- graph_agents_cli/extension/_compat.py +86 -0
- graph_agents_cli/extension/_loader.py +293 -0
- graph_agents_cli/extension/_manifest.py +135 -0
- graph_agents_cli/extension/_overrides.py +195 -0
- graph_agents_cli/extension/_paths.py +91 -0
- graph_agents_cli/extension/_refs.py +193 -0
- graph_agents_cli/extension/_resolver.py +453 -0
- graph_agents_cli/extension/_schema.py +106 -0
- graph_agents_cli/extension/_spec.py +253 -0
- graph_agents_cli/extension/_sync.py +102 -0
- graph_agents_cli/extension/_trust.py +58 -0
- graph_agents_cli/extension/cmd_extension_add.py +259 -0
- graph_agents_cli/extension/cmd_extension_group.py +57 -0
- graph_agents_cli/extension/cmd_extension_list.py +56 -0
- graph_agents_cli/extension/cmd_extension_remove.py +61 -0
- graph_agents_cli/extension/cmd_extension_update.py +195 -0
- graph_agents_cli/info/__init__.py +13 -0
- graph_agents_cli/info/cmd_info.py +222 -0
- graph_agents_cli/infra/__init__.py +15 -0
- graph_agents_cli/infra/checks.py +1169 -0
- graph_agents_cli/infra/cmd_infra.py +103 -0
- graph_agents_cli/main.py +591 -0
- graph_agents_cli/peer/__init__.py +15 -0
- graph_agents_cli/peer/_generate.py +254 -0
- graph_agents_cli/peer/cmd_peer.py +1151 -0
- graph_agents_cli/run/__init__.py +13 -0
- graph_agents_cli/run/_local_server.py +1157 -0
- graph_agents_cli/run/_signals.py +141 -0
- graph_agents_cli/run/cmd_approvals.py +530 -0
- graph_agents_cli/run/cmd_run.py +1421 -0
- graph_agents_cli/scaffold/__init__.py +19 -0
- graph_agents_cli/scaffold/agents/README.md +24 -0
- graph_agents_cli/scaffold/agents/empty_py/.template/templateconfig.yaml +22 -0
- graph_agents_cli/scaffold/agents/langgraph/.env.example +292 -0
- graph_agents_cli/scaffold/agents/langgraph/.template/templateconfig.yaml +28 -0
- graph_agents_cli/scaffold/agents/langgraph/Dockerfile +59 -0
- graph_agents_cli/scaffold/agents/langgraph/Dockerfile.langgraph-server +59 -0
- graph_agents_cli/scaffold/agents/langgraph/README.md +571 -0
- graph_agents_cli/scaffold/agents/langgraph/api-policy.yaml +60 -0
- graph_agents_cli/scaffold/agents/langgraph/app/__init__.py +20 -0
- graph_agents_cli/scaffold/agents/langgraph/app/agent.py +174 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/__init__.py +15 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a.py +2162 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a_client.py +1167 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/api_client.py +4220 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/approvals.py +1349 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/auth.py +1986 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/chat.py +2962 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/checkpointer.py +432 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/content.py +569 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/db.py +580 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/limits.py +203 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/metrics.py +231 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/middleware.py +361 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/model.py +611 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/playground.py +230 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/run_locks.py +459 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/structured.py +755 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/telemetry.py +681 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/threads.py +493 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/token_exchange.py +959 -0
- graph_agents_cli/scaffold/agents/langgraph/app/fast_api_app.py +770 -0
- graph_agents_cli/scaffold/agents/langgraph/app/policies/__init__.py +55 -0
- graph_agents_cli/scaffold/agents/langgraph/app/policies/custom.py +97 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/__init__.py +46 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/example_api.py +92 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/weather.py +33 -0
- graph_agents_cli/scaffold/agents/langgraph/langgraph.json +14 -0
- graph_agents_cli/scaffold/agents/langgraph/pyproject.toml +78 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/conftest.py +376 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/eval/datasets/basic-dataset.json +53 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/eval/eval_config.yaml +32 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/approval_graph.py +137 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_issuer.py +216 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_openai.py +357 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_outcomes.py +569 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_relay.py +479 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_api_surface.py +812 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals.py +1367 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals_server.py +794 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor.py +497 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor_server.py +247 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_history_repair.py +278 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_model_apis.py +242 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_postgres.py +637 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_resilience_postgres.py +770 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_runtime_guardrails.py +854 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_e2e.py +340 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_runtime.py +989 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_answers.py +584 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_server.py +222 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_token_exchange_issuer.py +650 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/.results/.placeholder +0 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/README.md +22 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/conftest.py +21 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/load_test.py +81 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_client.py +824 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_scoping.py +724 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client.py +1214 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client_hardening.py +716 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_policy_rpc.py +767 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_approval_ledger.py +1536 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_fake_model.py +115 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_jwt_policy.py +991 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_limits.py +310 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging.py +148 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging_hardening.py +271 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_policy.py +378 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_resilience.py +610 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_server_auth.py +702 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_structured.py +673 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_telemetry.py +404 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_thread_listing.py +255 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_threads.py +268 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_token_exchange.py +1320 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_untrusted_content.py +393 -0
- graph_agents_cli/scaffold/agents/langgraph/uv-fastapi.lock +2084 -0
- graph_agents_cli/scaffold/agents/langgraph/uv-langgraph-server.lock +2106 -0
- graph_agents_cli/scaffold/agents/langgraph/{{cookiecutter.agent_guidance_filename}} +129 -0
- graph_agents_cli/scaffold/base_templates/_shared/graph-agents-cli-manifest.yaml +36 -0
- graph_agents_cli/scaffold/base_templates/python/.dockerignore +32 -0
- graph_agents_cli/scaffold/base_templates/python/.github/CODEOWNERS +30 -0
- graph_agents_cli/scaffold/base_templates/python/.github/agent.env +7 -0
- graph_agents_cli/scaffold/base_templates/python/.github/workflows/pr_checks.yaml +214 -0
- graph_agents_cli/scaffold/base_templates/python/.gitignore +209 -0
- graph_agents_cli/scaffold/base_templates/python/tests/unit/test_dummy.py +23 -0
- graph_agents_cli/scaffold/base_templates/python/{{cookiecutter.agent_guidance_filename}} +35 -0
- graph_agents_cli/scaffold/cmd_scaffold_group.py +49 -0
- graph_agents_cli/scaffold/commands/__init__.py +13 -0
- graph_agents_cli/scaffold/commands/create.py +1424 -0
- graph_agents_cli/scaffold/commands/enhance.py +1652 -0
- graph_agents_cli/scaffold/commands/upgrade.py +570 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/agent.env +12 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/promote-to-prod.yaml +371 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/staging.yaml +450 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-dev.yaml +43 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-prod.yaml +41 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-staging.yaml +43 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/.helmignore +14 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/Chart.yaml +21 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/examples/networkpolicy.yaml +103 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/NOTES.txt +48 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/_helpers.tpl +189 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/certificate.yaml +15 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/configmap.yaml +10 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/deployment.yaml +199 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/hpa.yaml +22 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/httproute.yaml +30 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/ingress.yaml +39 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/networkpolicy.yaml +48 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/pdb.yaml +13 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/postgresql-secret.yaml +37 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/service.yaml +15 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/serviceaccount.yaml +13 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/servicemonitor.yaml +42 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-dev.yaml +22 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-prod.yaml +45 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-staging.yaml +29 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values.yaml +396 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/tests/integration/test_chart.py +269 -0
- graph_agents_cli/scaffold/deployment_targets/none/README.md +5 -0
- graph_agents_cli/scaffold/deployment_targets/none/python/README.md +6 -0
- graph_agents_cli/scaffold/utils/__init__.py +13 -0
- graph_agents_cli/scaffold/utils/backup.py +212 -0
- graph_agents_cli/scaffold/utils/build_record.py +257 -0
- graph_agents_cli/scaffold/utils/cli_options.py +184 -0
- graph_agents_cli/scaffold/utils/fs.py +83 -0
- graph_agents_cli/scaffold/utils/generate_locks.py +214 -0
- graph_agents_cli/scaffold/utils/generation_metadata.py +88 -0
- graph_agents_cli/scaffold/utils/keyedit.py +768 -0
- graph_agents_cli/scaffold/utils/keymerge.py +537 -0
- graph_agents_cli/scaffold/utils/language.py +138 -0
- graph_agents_cli/scaffold/utils/lock_utils.py +94 -0
- graph_agents_cli/scaffold/utils/logging.py +77 -0
- graph_agents_cli/scaffold/utils/manifest.py +292 -0
- graph_agents_cli/scaffold/utils/merge.py +970 -0
- graph_agents_cli/scaffold/utils/merge3.py +216 -0
- graph_agents_cli/scaffold/utils/openapi_seed.py +199 -0
- graph_agents_cli/scaffold/utils/remote_template.py +376 -0
- graph_agents_cli/scaffold/utils/template.py +1352 -0
- graph_agents_cli/scaffold/utils/upgrade.py +894 -0
- graph_agents_cli/scaffold/utils/version.py +438 -0
- graph_agents_cli/secrets/__init__.py +15 -0
- graph_agents_cli/secrets/_apply.py +954 -0
- graph_agents_cli/secrets/_required.py +188 -0
- graph_agents_cli/secrets/cmd_secrets.py +211 -0
- graph_agents_cli/setup/__init__.py +13 -0
- graph_agents_cli/setup/_antigravity.py +221 -0
- graph_agents_cli/setup/cmd_auth.py +1030 -0
- graph_agents_cli/setup/cmd_dev_token.py +513 -0
- graph_agents_cli/setup/cmd_setup.py +428 -0
- graph_agents_cli/setup/cmd_update.py +140 -0
- graph_agents_cli/skills/__init__.py +13 -0
- graph_agents_cli/skills/_bundle.py +65 -0
- graph_agents_cli/skills/data/README.md +19 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/SKILL.md +357 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/github-settings.md +113 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/gitops.md +137 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/kubernetes.md +315 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/secrets.md +160 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/SKILL.md +303 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/references/dataset_schema.md +282 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/references/metrics-guide.md +143 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/SKILL.md +659 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langchain-models.md +124 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langgraph.md +235 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/template-contract.md +477 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/SKILL.md +231 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/references/langsmith.md +46 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/references/otel.md +59 -0
- graph_agents_cli/skills/data/graph-agents-cli-scaffold/SKILL.md +414 -0
- graph_agents_cli/skills/data/graph-agents-cli-scaffold/references/flags.md +134 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/SKILL.md +478 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/brainstorming.md +118 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/commands.md +419 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/extension.md +156 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/internals.md +67 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/spec-template.md +56 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/terminology.md +119 -0
- graph_agents_cli/system/__init__.py +15 -0
- graph_agents_cli/system/_apply.py +519 -0
- graph_agents_cli/system/_checks.py +1023 -0
- graph_agents_cli/system/_deploy.py +215 -0
- graph_agents_cli/system/_model.py +363 -0
- graph_agents_cli/system/_system.py +664 -0
- graph_agents_cli/system/_views.py +208 -0
- graph_agents_cli/system/cmd_system.py +423 -0
- graph_agents_cli-0.3.1.dist-info/METADATA +162 -0
- graph_agents_cli-0.3.1.dist-info/RECORD +291 -0
- graph_agents_cli-0.3.1.dist-info/WHEEL +4 -0
- graph_agents_cli-0.3.1.dist-info/entry_points.txt +2 -0
- graph_agents_cli-0.3.1.dist-info/licenses/LICENSE +201 -0
- graph_agents_cli-0.3.1.dist-info/licenses/NOTICE +19 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
# Copyright 2026 Google LLC
|
|
2
|
+
# Modifications Copyright 2026 graph-agents-cli contributors
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
# On every push to main: build and push the image tagged with the SHORT commit
|
|
17
|
+
# SHA (${GITHUB_SHA::7}, the same value `git rev-parse --short HEAD` gives a
|
|
18
|
+
# workstation `graph-agents-cli deploy --env <env>` in argocd mode), then land
|
|
19
|
+
# it in staging according to CD in .github/agent.env:
|
|
20
|
+
# argocd: update values-staging.yaml image.tag and open a PR with auto-merge
|
|
21
|
+
# (closing older staging PRs it supersedes); Argo CD rolls it out
|
|
22
|
+
# and its health checks (the readiness probe, /ready) show whether
|
|
23
|
+
# it landed (`graph-agents-cli deploy --env staging --status`).
|
|
24
|
+
# helm-push: run `graph-agents-cli deploy --env staging --image ...` on a
|
|
25
|
+
# self-hosted runner with the kubeconfig of the `staging`
|
|
26
|
+
# environment, then verify the rollout (rollout status, /health
|
|
27
|
+
# and /ready through a port-forward), both in one kube context
|
|
28
|
+
# (environments.staging.context, else the kubeconfig's current one).
|
|
29
|
+
# Pushes that only change the per-environment values files (the image tags
|
|
30
|
+
# this workflow, promote-to-prod and `graph-agents-cli deploy` write in argocd
|
|
31
|
+
# mode) do not start it, so a merged staging PR never triggers another build.
|
|
32
|
+
# Run it by hand (workflow_dispatch, main only) to re-deploy main, e.g. after
|
|
33
|
+
# changing only values-staging.yaml in helm-push mode.
|
|
34
|
+
# This file is copied verbatim into the project (not rendered).
|
|
35
|
+
|
|
36
|
+
name: staging
|
|
37
|
+
|
|
38
|
+
on:
|
|
39
|
+
push:
|
|
40
|
+
branches:
|
|
41
|
+
- main
|
|
42
|
+
paths-ignore:
|
|
43
|
+
- '**.md'
|
|
44
|
+
- 'docs/**'
|
|
45
|
+
- 'deployment/helm/*/values-dev.yaml'
|
|
46
|
+
- 'deployment/helm/*/values-staging.yaml'
|
|
47
|
+
- 'deployment/helm/*/values-prod.yaml'
|
|
48
|
+
workflow_dispatch:
|
|
49
|
+
|
|
50
|
+
concurrency:
|
|
51
|
+
group: staging
|
|
52
|
+
cancel-in-progress: false
|
|
53
|
+
|
|
54
|
+
jobs:
|
|
55
|
+
build:
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
# A manual run from another branch would deploy that branch to staging.
|
|
58
|
+
if: github.ref == 'refs/heads/main'
|
|
59
|
+
permissions:
|
|
60
|
+
contents: read
|
|
61
|
+
packages: write
|
|
62
|
+
outputs:
|
|
63
|
+
cd: ${{ steps.settings.outputs.cd }}
|
|
64
|
+
tag: ${{ steps.settings.outputs.tag }}
|
|
65
|
+
image: ${{ steps.settings.outputs.image }}
|
|
66
|
+
chart_path: ${{ steps.settings.outputs.chart_path }}
|
|
67
|
+
release: ${{ steps.settings.outputs.release }}
|
|
68
|
+
namespace: ${{ steps.settings.outputs.namespace }}
|
|
69
|
+
kube_context: ${{ steps.settings.outputs.kube_context }}
|
|
70
|
+
graph_agents_cli_spec: ${{ steps.settings.outputs.graph_agents_cli_spec }}
|
|
71
|
+
steps:
|
|
72
|
+
- name: Checkout code
|
|
73
|
+
uses: actions/checkout@v4
|
|
74
|
+
|
|
75
|
+
- name: Load project settings
|
|
76
|
+
run: |
|
|
77
|
+
# .github/agent.env is data and is never sourced: each NAME=VALUE line is
|
|
78
|
+
# checked and copied to GITHUB_ENV, so a value may hold spaces or shell
|
|
79
|
+
# metacharacters (a PEP 508 install spec, for example). Only the settings
|
|
80
|
+
# listed in `known` are accepted: any other name (BASH_ENV, SHELLOPTS, PS4,
|
|
81
|
+
# PATH, PYTHONPATH, ...) could change how later steps run. To add a setting,
|
|
82
|
+
# extend `known` in all three workflows. Comment and blank lines are skipped;
|
|
83
|
+
# blanks around the value, one pair of quotes around it and a trailing
|
|
84
|
+
# " # comment" are dropped (no escapes, no expansion). Nothing reaches
|
|
85
|
+
# GITHUB_ENV unless the whole file is valid.
|
|
86
|
+
file=.github/agent.env
|
|
87
|
+
known="IMAGE_REPOSITORY RELEASE_NAME CHART_PATH RUNTIME CD GRAPH_AGENTS_CLI_SPEC"
|
|
88
|
+
if [ ! -f "$file" ]; then
|
|
89
|
+
echo "::error file=$file::$file is missing: it holds the project settings these workflows read." >&2
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
lineno=0
|
|
93
|
+
seen=" "
|
|
94
|
+
settings=()
|
|
95
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
96
|
+
lineno=$((lineno + 1))
|
|
97
|
+
line="${line%$'\r'}"
|
|
98
|
+
if [ "$lineno" -eq 1 ]; then
|
|
99
|
+
line="${line#$'\xef\xbb\xbf'}"
|
|
100
|
+
fi
|
|
101
|
+
if [[ "$line" =~ ^[[:space:]]*(#|$) ]]; then
|
|
102
|
+
continue
|
|
103
|
+
fi
|
|
104
|
+
if ! [[ "$line" =~ ^[[:space:]]*([A-Za-z_][A-Za-z0-9_]*)[[:space:]]*=(.*)$ ]]; then
|
|
105
|
+
echo "::error file=$file,line=$lineno::expected NAME=VALUE, got: $line" >&2
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
name="${BASH_REMATCH[1]}"
|
|
109
|
+
value="${BASH_REMATCH[2]}"
|
|
110
|
+
case " $known " in
|
|
111
|
+
*" $name "*) ;;
|
|
112
|
+
*)
|
|
113
|
+
hint=""
|
|
114
|
+
if [ "$name" = CLI_VERSION_PIN ]; then
|
|
115
|
+
hint=" (replaced by GRAPH_AGENTS_CLI_SPEC=<install spec>)"
|
|
116
|
+
fi
|
|
117
|
+
echo "::error file=$file,line=$lineno::$name is not a setting these workflows read${hint}; known: $known." >&2
|
|
118
|
+
exit 1
|
|
119
|
+
;;
|
|
120
|
+
esac
|
|
121
|
+
case "$seen" in
|
|
122
|
+
*" $name "*)
|
|
123
|
+
echo "::error file=$file,line=$lineno::$name is set twice." >&2
|
|
124
|
+
exit 1
|
|
125
|
+
;;
|
|
126
|
+
esac
|
|
127
|
+
seen="$seen$name "
|
|
128
|
+
value="${value#"${value%%[![:space:]]*}"}"
|
|
129
|
+
quote="${value:0:1}"
|
|
130
|
+
if [ "$quote" = '"' ] || [ "$quote" = "'" ]; then
|
|
131
|
+
rest="${value:1}"
|
|
132
|
+
if [[ "$rest" != *"$quote"* ]]; then
|
|
133
|
+
echo "::error file=$file,line=$lineno::$name: unterminated $quote quote." >&2
|
|
134
|
+
exit 1
|
|
135
|
+
fi
|
|
136
|
+
value="${rest%%"$quote"*}"
|
|
137
|
+
else
|
|
138
|
+
value="${value%%[[:space:]]#*}"
|
|
139
|
+
value="${value%"${value##*[![:space:]]}"}"
|
|
140
|
+
fi
|
|
141
|
+
if [[ "$value" == *[[:cntrl:]]* ]]; then
|
|
142
|
+
echo "::error file=$file,line=$lineno::$name: control characters are not allowed in a value." >&2
|
|
143
|
+
exit 1
|
|
144
|
+
fi
|
|
145
|
+
settings+=("$name=$value")
|
|
146
|
+
done < "$file"
|
|
147
|
+
if [ "${#settings[@]}" -gt 0 ]; then
|
|
148
|
+
printf '%s\n' "${settings[@]}" >> "$GITHUB_ENV"
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
- name: Resolve the image and the target
|
|
152
|
+
id: settings
|
|
153
|
+
run: |
|
|
154
|
+
for var in IMAGE_REPOSITORY RELEASE_NAME CHART_PATH CD GRAPH_AGENTS_CLI_SPEC; do
|
|
155
|
+
if [ -z "${!var:-}" ]; then
|
|
156
|
+
echo "::error file=.github/agent.env::$var is not set in .github/agent.env." >&2
|
|
157
|
+
exit 1
|
|
158
|
+
fi
|
|
159
|
+
done
|
|
160
|
+
if [ "$CD" != argocd ] && [ "$CD" != helm-push ]; then
|
|
161
|
+
echo "::error file=.github/agent.env::CD must be argocd or helm-push for this workflow, got '$CD'." >&2
|
|
162
|
+
exit 1
|
|
163
|
+
fi
|
|
164
|
+
if [[ "$IMAGE_REPOSITORY" == *CHANGE-ME* ]] || ! [[ "$IMAGE_REPOSITORY" =~ ^[A-Za-z0-9.-]+(:[0-9]+)?(/[a-z0-9._-]+)+$ ]]; then
|
|
165
|
+
echo "::error file=.github/agent.env::IMAGE_REPOSITORY must be <registry>/<path> in lowercase with no placeholder, got '$IMAGE_REPOSITORY'." >&2
|
|
166
|
+
exit 1
|
|
167
|
+
fi
|
|
168
|
+
TAG="${GITHUB_SHA::7}"
|
|
169
|
+
manifest=graph-agents-cli-manifest.yaml
|
|
170
|
+
NAMESPACE="$(yq -r '.environments.staging.namespace // ""' "$manifest")"
|
|
171
|
+
if [ -z "$NAMESPACE" ]; then
|
|
172
|
+
NAMESPACE="$(yq -r '.name // ""' "$manifest")-staging"
|
|
173
|
+
fi
|
|
174
|
+
if ! [[ "$NAMESPACE" =~ ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$ ]]; then
|
|
175
|
+
echo "::error file=$manifest::Invalid staging namespace '$NAMESPACE'." >&2
|
|
176
|
+
exit 1
|
|
177
|
+
fi
|
|
178
|
+
# The kube context `deploy` uses; empty = the kubeconfig's current one.
|
|
179
|
+
KUBE_CONTEXT="$(yq -r '.environments.staging.context // ""' "$manifest")"
|
|
180
|
+
if [ -n "$KUBE_CONTEXT" ] && { ! [[ "$KUBE_CONTEXT" =~ ^[[:graph:]]+$ ]] || [[ "$KUBE_CONTEXT" == -* ]]; }; then
|
|
181
|
+
echo "::error file=$manifest::Invalid staging kube context '$KUBE_CONTEXT'." >&2
|
|
182
|
+
exit 1
|
|
183
|
+
fi
|
|
184
|
+
if ! [[ "$RELEASE_NAME" =~ ^[a-z0-9]([-a-z0-9]{0,51}[a-z0-9])?$ ]]; then
|
|
185
|
+
echo "::error file=.github/agent.env::Invalid RELEASE_NAME '$RELEASE_NAME'." >&2
|
|
186
|
+
exit 1
|
|
187
|
+
fi
|
|
188
|
+
{
|
|
189
|
+
echo "cd=${CD}"
|
|
190
|
+
echo "tag=${TAG}"
|
|
191
|
+
echo "image=${IMAGE_REPOSITORY}:${TAG}"
|
|
192
|
+
echo "chart_path=${CHART_PATH}"
|
|
193
|
+
echo "release=${RELEASE_NAME}"
|
|
194
|
+
echo "namespace=${NAMESPACE}"
|
|
195
|
+
echo "kube_context=${KUBE_CONTEXT}"
|
|
196
|
+
echo "graph_agents_cli_spec=${GRAPH_AGENTS_CLI_SPEC}"
|
|
197
|
+
} >> "$GITHUB_OUTPUT"
|
|
198
|
+
echo "REGISTRY_HOST=${IMAGE_REPOSITORY%%/*}" >> "$GITHUB_ENV"
|
|
199
|
+
echo "IMAGE=${IMAGE_REPOSITORY}:${TAG}" >> "$GITHUB_ENV"
|
|
200
|
+
|
|
201
|
+
- name: Set up Docker Buildx
|
|
202
|
+
uses: docker/setup-buildx-action@v3
|
|
203
|
+
|
|
204
|
+
- name: Log in to the registry
|
|
205
|
+
# GHCR works with the workflow token; other registries take REGISTRY_USERNAME / REGISTRY_PASSWORD secrets.
|
|
206
|
+
uses: docker/login-action@v3
|
|
207
|
+
with:
|
|
208
|
+
registry: ${{ env.REGISTRY_HOST }}
|
|
209
|
+
username: ${{ secrets.REGISTRY_USERNAME || github.actor }}
|
|
210
|
+
password: ${{ secrets.REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
|
|
211
|
+
|
|
212
|
+
- name: Build and push
|
|
213
|
+
uses: docker/build-push-action@v6
|
|
214
|
+
with:
|
|
215
|
+
context: .
|
|
216
|
+
file: Dockerfile
|
|
217
|
+
push: true
|
|
218
|
+
tags: ${{ env.IMAGE }}
|
|
219
|
+
cache-from: type=gha
|
|
220
|
+
cache-to: type=gha,mode=max
|
|
221
|
+
|
|
222
|
+
land_argocd:
|
|
223
|
+
# Pull-based: write the desired state and let Argo CD reconcile from main.
|
|
224
|
+
needs: build
|
|
225
|
+
if: needs.build.outputs.cd == 'argocd'
|
|
226
|
+
runs-on: ubuntu-latest
|
|
227
|
+
permissions:
|
|
228
|
+
contents: write
|
|
229
|
+
pull-requests: write
|
|
230
|
+
env:
|
|
231
|
+
# A pull request opened with the workflow token does not trigger pr_checks
|
|
232
|
+
# (GitHub never starts workflows from GITHUB_TOKEN events), so auto-merge
|
|
233
|
+
# would wait forever on a required check. Store a fine-grained PAT or a
|
|
234
|
+
# GitHub App token as the GH_PR_TOKEN repository secret to lift that limit.
|
|
235
|
+
# The merge it enables is a push to main that changes only
|
|
236
|
+
# values-staging.yaml, which paths-ignore above keeps from re-running this
|
|
237
|
+
# workflow.
|
|
238
|
+
GH_TOKEN: ${{ secrets.GH_PR_TOKEN || secrets.GITHUB_TOKEN }}
|
|
239
|
+
TAG: ${{ needs.build.outputs.tag }}
|
|
240
|
+
IMAGE: ${{ needs.build.outputs.image }}
|
|
241
|
+
CHART_PATH: ${{ needs.build.outputs.chart_path }}
|
|
242
|
+
steps:
|
|
243
|
+
- name: Checkout code
|
|
244
|
+
uses: actions/checkout@v4
|
|
245
|
+
with:
|
|
246
|
+
# Full history: the next step orders staging builds by commit ancestry.
|
|
247
|
+
fetch-depth: 0
|
|
248
|
+
# Branch pushes with the PR token too, so a regenerated branch re-runs
|
|
249
|
+
# pr_checks (a push made with the workflow token starts no workflow).
|
|
250
|
+
token: ${{ secrets.GH_PR_TOKEN || secrets.GITHUB_TOKEN }}
|
|
251
|
+
|
|
252
|
+
- name: Open the staging PR with auto-merge
|
|
253
|
+
# Same branch name as a workstation `graph-agents-cli deploy --env staging`
|
|
254
|
+
# (deploy/<env>/<short sha>). Requires branch protection on main to permit
|
|
255
|
+
# auto-merge for the token and pr_checks to be green.
|
|
256
|
+
# Every staging PR edits the same line, so two quick pushes would leave
|
|
257
|
+
# the second PR conflicting once the first merged. Instead each run
|
|
258
|
+
# closes the older staging PRs still open (staging only needs the newest
|
|
259
|
+
# build), then builds its branch on the latest main, and does nothing
|
|
260
|
+
# when main, or an open PR, already carries this build or a newer one:
|
|
261
|
+
# a re-run of an older build never moves staging back. The branch is
|
|
262
|
+
# bot-owned, so a re-run replaces it (the PR is created only when none
|
|
263
|
+
# is open).
|
|
264
|
+
run: |
|
|
265
|
+
values="${CHART_PATH}/values-staging.yaml"
|
|
266
|
+
BRANCH="deploy/staging/${TAG}"
|
|
267
|
+
git config user.name "github-actions[bot]"
|
|
268
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
269
|
+
|
|
270
|
+
# True when commit $1 is an older ancestor of commit $2 (both known here).
|
|
271
|
+
older() {
|
|
272
|
+
local a b
|
|
273
|
+
a="$(git rev-parse --verify --quiet "${1}^{commit}")" || return 1
|
|
274
|
+
b="$(git rev-parse --verify --quiet "${2}^{commit}")" || return 1
|
|
275
|
+
[ "$a" != "$b" ] && git merge-base --is-ancestor "$a" "$b"
|
|
276
|
+
}
|
|
277
|
+
# Put the branch on the latest main; stop when main already deploys
|
|
278
|
+
# this build or a newer one.
|
|
279
|
+
sync_with_main() {
|
|
280
|
+
git fetch --quiet --no-tags origin +refs/heads/main:refs/remotes/origin/main
|
|
281
|
+
git checkout --quiet -B "$BRANCH" refs/remotes/origin/main
|
|
282
|
+
current="$(yq -r '.image.tag // ""' "$values")"
|
|
283
|
+
if [ "$current" = "$TAG" ]; then
|
|
284
|
+
echo "values-staging.yaml on main already deploys ${IMAGE}; nothing to open."
|
|
285
|
+
exit 0
|
|
286
|
+
fi
|
|
287
|
+
if [ -n "$current" ] && older "$GITHUB_SHA" "$current"; then
|
|
288
|
+
echo "main already deploys a newer build (${current}) to staging; nothing to open."
|
|
289
|
+
exit 0
|
|
290
|
+
fi
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
sync_with_main
|
|
294
|
+
open_prs="$(gh pr list --base main --state open --limit 200 --json number,headRefName --jq '.[] | "\(.number) \(.headRefName)"')"
|
|
295
|
+
while read -r number head; do
|
|
296
|
+
case "$head" in
|
|
297
|
+
deploy/staging/*) ;;
|
|
298
|
+
*) continue ;;
|
|
299
|
+
esac
|
|
300
|
+
if [ "$head" = "$BRANCH" ]; then
|
|
301
|
+
continue
|
|
302
|
+
fi
|
|
303
|
+
other="${head#deploy/staging/}"
|
|
304
|
+
if older "$GITHUB_SHA" "$other"; then
|
|
305
|
+
echo "A newer staging build is pending (#${number}, ${head}); nothing to open."
|
|
306
|
+
exit 0
|
|
307
|
+
fi
|
|
308
|
+
# A branch this step cannot order (a workstation tag) is left alone.
|
|
309
|
+
if older "$other" "$GITHUB_SHA"; then
|
|
310
|
+
gh pr close "$number" --delete-branch --comment "Superseded by ${IMAGE} (${BRANCH})." \
|
|
311
|
+
|| echo "::warning::Could not close the superseded staging PR #${number} (${head})."
|
|
312
|
+
fi
|
|
313
|
+
done <<< "$open_prs"
|
|
314
|
+
# Whatever merged before those PRs closed is on main now.
|
|
315
|
+
sync_with_main
|
|
316
|
+
yq -i '.image.tag = strenv(TAG) | .image.tag style="double"' "$values"
|
|
317
|
+
git add "$values"
|
|
318
|
+
git commit --quiet -m "deploy(staging): image ${IMAGE}"
|
|
319
|
+
git push --force origin "$BRANCH"
|
|
320
|
+
if [ -z "$(gh pr list --head "$BRANCH" --base main --state open --json number --jq '.[].number')" ]; then
|
|
321
|
+
gh pr create --base main --head "$BRANCH" \
|
|
322
|
+
--title "deploy(staging): ${TAG}" \
|
|
323
|
+
--body "Automated staging promotion of ${IMAGE}. Merges automatically once pr_checks passes."
|
|
324
|
+
fi
|
|
325
|
+
# --auto merges directly when already mergeable and is a no-op once merged;
|
|
326
|
+
# an "already enabled" rejection of the enable mutation is a success too.
|
|
327
|
+
gh pr merge --auto --squash "$BRANCH" \
|
|
328
|
+
|| [ -n "$(gh pr view "$BRANCH" --json autoMergeRequest --jq '.autoMergeRequest.enabledAt // empty')" ]
|
|
329
|
+
|
|
330
|
+
deploy_helm_push:
|
|
331
|
+
# Push-based: a self-hosted runner inside the network runs helm through the
|
|
332
|
+
# CLI (helm and kubectl on its PATH). The cluster credentials are the
|
|
333
|
+
# DEPLOY_KUBECONFIG secret of the `staging` environment: an environment
|
|
334
|
+
# secret, never a repository secret, so only jobs that run in that
|
|
335
|
+
# environment (main only, per its deployment-branch rule) can read it.
|
|
336
|
+
needs: build
|
|
337
|
+
if: needs.build.outputs.cd == 'helm-push'
|
|
338
|
+
runs-on: self-hosted
|
|
339
|
+
environment: staging
|
|
340
|
+
permissions:
|
|
341
|
+
contents: read
|
|
342
|
+
env:
|
|
343
|
+
GRAPH_AGENTS_CLI_NO_UPDATE_CHECK: "1"
|
|
344
|
+
# The CLI's own `deploy`: no extension (committed, or installed on the
|
|
345
|
+
# runner) can replace it while it holds the cluster credentials.
|
|
346
|
+
GRAPH_AGENTS_CLI_DISABLE_OVERRIDES: "1"
|
|
347
|
+
IMAGE: ${{ needs.build.outputs.image }}
|
|
348
|
+
RELEASE: ${{ needs.build.outputs.release }}
|
|
349
|
+
NAMESPACE: ${{ needs.build.outputs.namespace }}
|
|
350
|
+
MANIFEST_CONTEXT: ${{ needs.build.outputs.kube_context }}
|
|
351
|
+
GRAPH_AGENTS_CLI_SPEC: ${{ needs.build.outputs.graph_agents_cli_spec }}
|
|
352
|
+
steps:
|
|
353
|
+
- name: Checkout code
|
|
354
|
+
uses: actions/checkout@v4
|
|
355
|
+
|
|
356
|
+
- name: Install uv
|
|
357
|
+
uses: astral-sh/setup-uv@v6
|
|
358
|
+
with:
|
|
359
|
+
python-version: "3.12"
|
|
360
|
+
|
|
361
|
+
- name: Configure kubeconfig
|
|
362
|
+
# Written to the job's temporary directory (owner-only) and removed by
|
|
363
|
+
# the last step, whatever happens: nothing is left on the runner.
|
|
364
|
+
env:
|
|
365
|
+
DEPLOY_KUBECONFIG: ${{ secrets.DEPLOY_KUBECONFIG }}
|
|
366
|
+
run: |
|
|
367
|
+
if [ -z "$DEPLOY_KUBECONFIG" ]; then
|
|
368
|
+
echo "::error::DEPLOY_KUBECONFIG is empty: store the cluster credentials as the DEPLOY_KUBECONFIG secret of the staging environment (Settings > Environments > staging)." >&2
|
|
369
|
+
exit 1
|
|
370
|
+
fi
|
|
371
|
+
umask 077
|
|
372
|
+
printf '%s\n' "$DEPLOY_KUBECONFIG" > "$RUNNER_TEMP/kubeconfig"
|
|
373
|
+
echo "KUBECONFIG=$RUNNER_TEMP/kubeconfig" >> "$GITHUB_ENV"
|
|
374
|
+
|
|
375
|
+
- name: Resolve the kube context
|
|
376
|
+
# One context for the deploy and the checks after it, passed to both:
|
|
377
|
+
# the manifest's environments.staging.context when set, else the current
|
|
378
|
+
# context of DEPLOY_KUBECONFIG (what `deploy` itself would pick).
|
|
379
|
+
run: |
|
|
380
|
+
if ! command -v kubectl >/dev/null 2>&1; then
|
|
381
|
+
echo "::error::kubectl is not on the runner's PATH; the deploy and its checks need it." >&2
|
|
382
|
+
exit 1
|
|
383
|
+
fi
|
|
384
|
+
context="${MANIFEST_CONTEXT:-}"
|
|
385
|
+
if [ -z "$context" ]; then
|
|
386
|
+
context="$(kubectl config current-context 2>/dev/null || true)"
|
|
387
|
+
fi
|
|
388
|
+
if [ -z "$context" ]; then
|
|
389
|
+
echo "::error::No kube context: set environments.staging.context in graph-agents-cli-manifest.yaml or a current-context in DEPLOY_KUBECONFIG." >&2
|
|
390
|
+
exit 1
|
|
391
|
+
fi
|
|
392
|
+
if ! [[ "$context" =~ ^[[:graph:]]+$ ]] || [[ "$context" == -* ]]; then
|
|
393
|
+
echo "::error::Invalid kube context name '$context'." >&2
|
|
394
|
+
exit 1
|
|
395
|
+
fi
|
|
396
|
+
if ! kubectl config get-contexts "$context" >/dev/null 2>&1; then
|
|
397
|
+
echo "::error::Kube context '$context' is not in the DEPLOY_KUBECONFIG of the staging environment." >&2
|
|
398
|
+
exit 1
|
|
399
|
+
fi
|
|
400
|
+
echo "Kube context: $context"
|
|
401
|
+
echo "KUBE_CONTEXT=$context" >> "$GITHUB_ENV"
|
|
402
|
+
|
|
403
|
+
- name: Deploy to staging
|
|
404
|
+
# `deploy --image` in helm-push mode runs helm only (the image is already
|
|
405
|
+
# pushed), in the context resolved above; --yes: no prompt.
|
|
406
|
+
run: |
|
|
407
|
+
uvx --from "$GRAPH_AGENTS_CLI_SPEC" graph-agents-cli deploy --env staging --image "$IMAGE" --context "$KUBE_CONTEXT" --yes
|
|
408
|
+
|
|
409
|
+
- name: Verify the rollout
|
|
410
|
+
run: |
|
|
411
|
+
: "${NAMESPACE:?the build job resolved no namespace}" "${RELEASE:?the build job resolved no release}"
|
|
412
|
+
: "${KUBE_CONTEXT:?no kube context was resolved}"
|
|
413
|
+
# The cluster `deploy` just used (the same context).
|
|
414
|
+
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" rollout status "deployment/$RELEASE" --timeout=300s
|
|
415
|
+
log="$RUNNER_TEMP/port-forward.log"
|
|
416
|
+
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" port-forward "service/$RELEASE" :http > "$log" 2>&1 &
|
|
417
|
+
forward=$!
|
|
418
|
+
trap 'kill "$forward" 2>/dev/null || true' EXIT
|
|
419
|
+
port=""
|
|
420
|
+
for _ in $(seq 1 30); do
|
|
421
|
+
port="$(sed -n 's/^Forwarding from 127\.0\.0\.1:\([0-9][0-9]*\) .*/\1/p' "$log" | head -n 1)"
|
|
422
|
+
if [ -n "$port" ] || ! kill -0 "$forward" 2>/dev/null; then
|
|
423
|
+
break
|
|
424
|
+
fi
|
|
425
|
+
sleep 1
|
|
426
|
+
done
|
|
427
|
+
if [ -z "$port" ]; then
|
|
428
|
+
echo "::error::kubectl port-forward to service/$RELEASE failed: $(cat "$log")" >&2
|
|
429
|
+
exit 1
|
|
430
|
+
fi
|
|
431
|
+
for path in /health /ready; do
|
|
432
|
+
ok=""
|
|
433
|
+
for _ in $(seq 1 10); do
|
|
434
|
+
if curl --fail --silent --show-error --max-time 5 "http://127.0.0.1:${port}${path}"; then
|
|
435
|
+
ok=1
|
|
436
|
+
break
|
|
437
|
+
fi
|
|
438
|
+
sleep 3
|
|
439
|
+
done
|
|
440
|
+
echo
|
|
441
|
+
if [ -z "$ok" ]; then
|
|
442
|
+
echo "::error::${path} did not answer 2xx on the staging deployment ($NAMESPACE/$RELEASE)." >&2
|
|
443
|
+
exit 1
|
|
444
|
+
fi
|
|
445
|
+
done
|
|
446
|
+
echo "staging runs ${IMAGE} and answers /health and /ready."
|
|
447
|
+
|
|
448
|
+
- name: Remove kubeconfig
|
|
449
|
+
if: always()
|
|
450
|
+
run: rm -f "$RUNNER_TEMP/kubeconfig" "$RUNNER_TEMP/port-forward.log"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Argo CD Application for the dev environment.
|
|
2
|
+
# Argo reconciles from main, so nothing reaches the cluster until a PR merges.
|
|
3
|
+
# The chart refuses to render until values-dev.yaml names an image tag
|
|
4
|
+
# (`graph-agents-cli deploy --env dev` opens the PR that sets it): until then
|
|
5
|
+
# Argo CD reports a comparison error and deploys nothing.
|
|
6
|
+
apiVersion: argoproj.io/v1alpha1
|
|
7
|
+
kind: Application
|
|
8
|
+
metadata:
|
|
9
|
+
name: {{cookiecutter.project_name}}-dev
|
|
10
|
+
namespace: argocd
|
|
11
|
+
finalizers:
|
|
12
|
+
- resources-finalizer.argocd.argoproj.io
|
|
13
|
+
spec:
|
|
14
|
+
project: default
|
|
15
|
+
source:
|
|
16
|
+
# CHANGE-ME: the git URL of this repository.
|
|
17
|
+
repoURL: https://github.com/CHANGE-ME/{{cookiecutter.project_name}}.git
|
|
18
|
+
targetRevision: main
|
|
19
|
+
path: deployment/helm/{{cookiecutter.project_name}}
|
|
20
|
+
helm:
|
|
21
|
+
releaseName: {{cookiecutter.project_name}}
|
|
22
|
+
valueFiles:
|
|
23
|
+
- values.yaml
|
|
24
|
+
- values-dev.yaml
|
|
25
|
+
destination:
|
|
26
|
+
server: https://kubernetes.default.svc
|
|
27
|
+
namespace: {{cookiecutter.project_name}}-dev
|
|
28
|
+
# The bundled Postgres's credentials Secret is generated on the first sync
|
|
29
|
+
# (Argo CD renders without cluster access, so every render would otherwise
|
|
30
|
+
# produce a new password the database volume no longer accepts): keep the
|
|
31
|
+
# live values. Only exists when postgresql.enabled (dev by default).
|
|
32
|
+
ignoreDifferences:
|
|
33
|
+
- kind: Secret
|
|
34
|
+
name: {{cookiecutter.project_name}}-postgresql-auth
|
|
35
|
+
jsonPointers:
|
|
36
|
+
- /data
|
|
37
|
+
syncPolicy:
|
|
38
|
+
automated:
|
|
39
|
+
prune: true
|
|
40
|
+
selfHeal: true
|
|
41
|
+
syncOptions:
|
|
42
|
+
- CreateNamespace=true
|
|
43
|
+
- RespectIgnoreDifferences=true
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Argo CD Application for the prod environment.
|
|
2
|
+
# Argo reconciles from main, so nothing reaches the cluster until a PR merges.
|
|
3
|
+
# The chart refuses to render until values-prod.yaml names an image tag
|
|
4
|
+
# (promote-to-prod opens the PR that sets it).
|
|
5
|
+
apiVersion: argoproj.io/v1alpha1
|
|
6
|
+
kind: Application
|
|
7
|
+
metadata:
|
|
8
|
+
name: {{cookiecutter.project_name}}-prod
|
|
9
|
+
namespace: argocd
|
|
10
|
+
finalizers:
|
|
11
|
+
- resources-finalizer.argocd.argoproj.io
|
|
12
|
+
spec:
|
|
13
|
+
project: default
|
|
14
|
+
source:
|
|
15
|
+
# CHANGE-ME: the git URL of this repository.
|
|
16
|
+
repoURL: https://github.com/CHANGE-ME/{{cookiecutter.project_name}}.git
|
|
17
|
+
targetRevision: main
|
|
18
|
+
path: deployment/helm/{{cookiecutter.project_name}}
|
|
19
|
+
helm:
|
|
20
|
+
releaseName: {{cookiecutter.project_name}}
|
|
21
|
+
valueFiles:
|
|
22
|
+
- values.yaml
|
|
23
|
+
- values-prod.yaml
|
|
24
|
+
destination:
|
|
25
|
+
server: https://kubernetes.default.svc
|
|
26
|
+
namespace: {{cookiecutter.project_name}}-prod
|
|
27
|
+
# The bundled Postgres's credentials Secret is generated on the first sync
|
|
28
|
+
# (Argo CD renders without cluster access, so every render would otherwise
|
|
29
|
+
# produce a new password the database volume no longer accepts): keep the
|
|
30
|
+
# live values. Only exists when postgresql.enabled (dev by default).
|
|
31
|
+
ignoreDifferences:
|
|
32
|
+
- kind: Secret
|
|
33
|
+
name: {{cookiecutter.project_name}}-postgresql-auth
|
|
34
|
+
jsonPointers:
|
|
35
|
+
- /data
|
|
36
|
+
# Production has NO automated sync (a human syncs it): after the values-prod.yaml
|
|
37
|
+
# PR merges, an operator syncs the application in Argo CD.
|
|
38
|
+
syncPolicy:
|
|
39
|
+
syncOptions:
|
|
40
|
+
- CreateNamespace=true
|
|
41
|
+
- RespectIgnoreDifferences=true
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Argo CD Application for the staging environment.
|
|
2
|
+
# Argo reconciles from main, so nothing reaches the cluster until a PR merges.
|
|
3
|
+
# The chart refuses to render until values-staging.yaml names an image tag
|
|
4
|
+
# (the staging workflow opens the PR that sets it): until then Argo CD reports
|
|
5
|
+
# a comparison error and deploys nothing.
|
|
6
|
+
apiVersion: argoproj.io/v1alpha1
|
|
7
|
+
kind: Application
|
|
8
|
+
metadata:
|
|
9
|
+
name: {{cookiecutter.project_name}}-staging
|
|
10
|
+
namespace: argocd
|
|
11
|
+
finalizers:
|
|
12
|
+
- resources-finalizer.argocd.argoproj.io
|
|
13
|
+
spec:
|
|
14
|
+
project: default
|
|
15
|
+
source:
|
|
16
|
+
# CHANGE-ME: the git URL of this repository.
|
|
17
|
+
repoURL: https://github.com/CHANGE-ME/{{cookiecutter.project_name}}.git
|
|
18
|
+
targetRevision: main
|
|
19
|
+
path: deployment/helm/{{cookiecutter.project_name}}
|
|
20
|
+
helm:
|
|
21
|
+
releaseName: {{cookiecutter.project_name}}
|
|
22
|
+
valueFiles:
|
|
23
|
+
- values.yaml
|
|
24
|
+
- values-staging.yaml
|
|
25
|
+
destination:
|
|
26
|
+
server: https://kubernetes.default.svc
|
|
27
|
+
namespace: {{cookiecutter.project_name}}-staging
|
|
28
|
+
# The bundled Postgres's credentials Secret is generated on the first sync
|
|
29
|
+
# (Argo CD renders without cluster access, so every render would otherwise
|
|
30
|
+
# produce a new password the database volume no longer accepts): keep the
|
|
31
|
+
# live values. Only exists when postgresql.enabled (dev by default).
|
|
32
|
+
ignoreDifferences:
|
|
33
|
+
- kind: Secret
|
|
34
|
+
name: {{cookiecutter.project_name}}-postgresql-auth
|
|
35
|
+
jsonPointers:
|
|
36
|
+
- /data
|
|
37
|
+
syncPolicy:
|
|
38
|
+
automated:
|
|
39
|
+
prune: true
|
|
40
|
+
selfHeal: true
|
|
41
|
+
syncOptions:
|
|
42
|
+
- CreateNamespace=true
|
|
43
|
+
- RespectIgnoreDifferences=true
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
apiVersion: v2
|
|
2
|
+
name: {{cookiecutter.project_name}}
|
|
3
|
+
description: Helm chart for the {{cookiecutter.project_name}} LangGraph agent (graph-agents-cli)
|
|
4
|
+
type: application
|
|
5
|
+
version: 0.1.0
|
|
6
|
+
appVersion: "0.1.0"
|
|
7
|
+
# Exact versions, so every `helm dependency build` resolves the same charts.
|
|
8
|
+
# Their images are pinned by digest in values.yaml (see the note there on the
|
|
9
|
+
# Bitnami catalogue and how to use another chart or an external database).
|
|
10
|
+
dependencies:
|
|
11
|
+
# Optional in-cluster Postgres for dev (values-dev.yaml enables it). Staging
|
|
12
|
+
# and prod use an external database supplied through the Secret.
|
|
13
|
+
- name: postgresql
|
|
14
|
+
version: "18.11.6"
|
|
15
|
+
repository: oci://registry-1.docker.io/bitnamicharts
|
|
16
|
+
condition: postgresql.enabled
|
|
17
|
+
# Redis is only needed by the langgraph-server runtime.
|
|
18
|
+
- name: redis
|
|
19
|
+
version: "28.2.3"
|
|
20
|
+
repository: oci://registry-1.docker.io/bitnamicharts
|
|
21
|
+
condition: redis.enabled
|