agent-starter-pack 0.3.3__py3-none-any.whl → 0.21.0__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.
- agent_starter_pack/agents/README.md +7 -0
- agents/langgraph_base_react/template/.templateconfig.yaml → agent_starter_pack/agents/adk_a2a_base/.template/templateconfig.yaml +5 -10
- agent_starter_pack/agents/adk_a2a_base/README.md +37 -0
- src/deployment_targets/cloud_run/Dockerfile → agent_starter_pack/agents/adk_a2a_base/app/__init__.py +2 -14
- agent_starter_pack/agents/adk_a2a_base/app/agent.py +70 -0
- agent_starter_pack/agents/adk_a2a_base/notebooks/adk_a2a_app_testing.ipynb +583 -0
- agents/crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb → agent_starter_pack/agents/adk_a2a_base/notebooks/evaluating_adk_agent.ipynb +163 -199
- {agents/adk_base → agent_starter_pack/agents/adk_a2a_base}/tests/integration/test_agent.py +2 -2
- agents/adk_base/template/.templateconfig.yaml → agent_starter_pack/agents/adk_base/.template/templateconfig.yaml +4 -1
- {agents → agent_starter_pack/agents}/adk_base/README.md +1 -1
- agent_starter_pack/agents/adk_base/app/__init__.py +17 -0
- {agents → agent_starter_pack/agents}/adk_base/app/agent.py +5 -2
- {agents → agent_starter_pack/agents}/adk_base/notebooks/adk_app_testing.ipynb +128 -82
- agents/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb → agent_starter_pack/agents/adk_base/notebooks/evaluating_adk_agent.ipynb +181 -207
- agent_starter_pack/agents/adk_base/tests/integration/test_agent.py +58 -0
- agents/crewai_coding_crew/template/.templateconfig.yaml → agent_starter_pack/agents/adk_live/.template/templateconfig.yaml +5 -9
- agent_starter_pack/agents/adk_live/README.md +32 -0
- agent_starter_pack/agents/adk_live/app/__init__.py +17 -0
- agent_starter_pack/agents/adk_live/app/agent.py +51 -0
- agent_starter_pack/agents/adk_live/tests/unit/test_dummy.py +38 -0
- agents/agentic_rag/template/.templateconfig.yaml → agent_starter_pack/agents/agentic_rag/.template/templateconfig.yaml +7 -3
- {agents → agent_starter_pack/agents}/agentic_rag/README.md +1 -1
- agent_starter_pack/agents/agentic_rag/app/__init__.py +17 -0
- {agents → agent_starter_pack/agents}/agentic_rag/app/agent.py +8 -4
- {agents → agent_starter_pack/agents}/agentic_rag/notebooks/adk_app_testing.ipynb +128 -82
- agent_starter_pack/agents/agentic_rag/notebooks/evaluating_adk_agent.ipynb +1535 -0
- {agents → agent_starter_pack/agents}/agentic_rag/tests/integration/test_agent.py +3 -3
- agent_starter_pack/agents/langgraph_base/.template/templateconfig.yaml +31 -0
- agent_starter_pack/agents/langgraph_base/README.md +30 -0
- agent_starter_pack/agents/langgraph_base/app/__init__.py +17 -0
- agent_starter_pack/agents/langgraph_base/app/agent.py +34 -0
- {agents/crewai_coding_crew → agent_starter_pack/agents/langgraph_base}/notebooks/evaluating_langgraph_agent.ipynb +30 -17
- {agents/langgraph_base_react → agent_starter_pack/agents/langgraph_base}/tests/integration/test_agent.py +2 -2
- {src → agent_starter_pack}/base_template/.gitignore +5 -3
- agent_starter_pack/base_template/GEMINI.md +5 -0
- agent_starter_pack/base_template/Makefile +339 -0
- agent_starter_pack/base_template/README.md +267 -0
- agent_starter_pack/base_template/deployment/README.md +11 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/apis.tf +2 -2
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/apis.tf +6 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/iam.tf +12 -11
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/providers.tf +5 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/storage.tf +1 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/variables.tf +10 -10
- agent_starter_pack/base_template/deployment/terraform/dev/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +193 -0
- agent_starter_pack/base_template/deployment/terraform/github.tf +337 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/iam.tf +20 -41
- {src → agent_starter_pack}/base_template/deployment/terraform/locals.tf +10 -3
- {src/resources/setup_cicd → agent_starter_pack/base_template/deployment/terraform}/providers.tf +8 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/service_accounts.tf +7 -8
- agent_starter_pack/base_template/deployment/terraform/sql/completions.sql +138 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/storage.tf +7 -16
- {src → agent_starter_pack}/base_template/deployment/terraform/variables.tf +61 -28
- {src → agent_starter_pack}/base_template/deployment/terraform/vars/env.tfvars +6 -1
- agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'github_actions' %}wif.tf{% else %}unused_wif.tf{% endif %} +43 -0
- src/base_template/deployment/terraform/build_triggers.tf → agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}build_triggers.tf{% else %}unused_build_triggers.tf{% endif %} +55 -38
- agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +206 -0
- {src → agent_starter_pack}/base_template/pyproject.toml +24 -37
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +132 -0
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/pr_checks.yaml +65 -0
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +259 -0
- src/base_template/deployment/cd/deploy-to-prod.yaml → agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/deploy-to-prod.yaml +38 -30
- src/base_template/deployment/ci/pr_checks.yaml → agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/pr_checks.yaml +5 -5
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +322 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/telemetry.py +96 -0
- {src/base_template/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/typing.py +7 -9
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/__init__.py +25 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/part_converter.py +138 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/__init__.py +13 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/a2a_agent_executor.py +265 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/task_result_aggregator.py +152 -0
- agent_starter_pack/cli/commands/create.py +1256 -0
- agent_starter_pack/cli/commands/enhance.py +611 -0
- agent_starter_pack/cli/commands/list.py +203 -0
- agent_starter_pack/cli/commands/register_gemini_enterprise.py +1070 -0
- agent_starter_pack/cli/commands/setup_cicd.py +862 -0
- {src → agent_starter_pack}/cli/main.py +10 -2
- {src → agent_starter_pack}/cli/utils/cicd.py +139 -48
- agent_starter_pack/cli/utils/gcp.py +263 -0
- agent_starter_pack/cli/utils/logging.py +103 -0
- agent_starter_pack/cli/utils/remote_template.py +677 -0
- agent_starter_pack/cli/utils/template.py +1466 -0
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/process_data.py +1 -1
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/submit_pipeline.py +20 -6
- {src → agent_starter_pack}/data_ingestion/pyproject.toml +1 -0
- {src → agent_starter_pack}/data_ingestion/uv.lock +602 -494
- agent_starter_pack/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +484 -0
- agent_starter_pack/deployment_targets/agent_engine/tests/load_test/README.md +84 -0
- agent_starter_pack/deployment_targets/agent_engine/tests/load_test/load_test.py +424 -0
- agent_starter_pack/deployment_targets/agent_engine/tests/{% if cookiecutter.is_a2a %}helpers.py{% else %}unused_helpers.py{% endif %} +138 -0
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/agent_engine_app.py +263 -0
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/deploy.py +414 -0
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_adk_live %}expose_app.py{% else %}unused_expose_app.py{% endif %} +519 -0
- agent_starter_pack/deployment_targets/cloud_run/Dockerfile +51 -0
- agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +243 -0
- agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/service.tf +417 -0
- agent_starter_pack/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +705 -0
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +321 -0
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/README.md +165 -0
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/load_test.py +329 -0
- agent_starter_pack/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/fast_api_app.py +556 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package-lock.json +79 -1044
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package.json +1 -9
- agent_starter_pack/frontends/adk_live_react/frontend/src/App.tsx +65 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/Logger.tsx +8 -3
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/logger.scss +26 -0
- agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/SidePanel.tsx +516 -0
- agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/side-panel.scss +563 -0
- agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/TranscriptionPreview.tsx +106 -0
- agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/transcription-preview.scss +150 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-live-api.ts +8 -2
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/multimodal-live-types.ts +40 -2
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-recorder.ts +1 -1
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-streamer.ts +1 -1
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/multimodal-live-client.ts +210 -24
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/utils.ts +27 -5
- agent_starter_pack/resources/docs/adk-cheatsheet.md +1628 -0
- agent_starter_pack/resources/locks/uv-adk_a2a_base-agent_engine.lock +4966 -0
- agent_starter_pack/resources/locks/uv-adk_a2a_base-cloud_run.lock +5011 -0
- agent_starter_pack/resources/locks/uv-adk_base-agent_engine.lock +4946 -0
- agent_starter_pack/resources/locks/uv-adk_base-cloud_run.lock +4991 -0
- agent_starter_pack/resources/locks/uv-adk_live-agent_engine.lock +4963 -0
- agent_starter_pack/resources/locks/uv-adk_live-cloud_run.lock +5006 -0
- agent_starter_pack/resources/locks/uv-agentic_rag-agent_engine.lock +5487 -0
- agent_starter_pack/resources/locks/uv-agentic_rag-cloud_run.lock +5532 -0
- agent_starter_pack/resources/locks/uv-langgraph_base-agent_engine.lock +5788 -0
- agent_starter_pack/resources/locks/uv-langgraph_base-cloud_run.lock +5811 -0
- {src → agent_starter_pack}/utils/generate_locks.py +15 -12
- {src → agent_starter_pack}/utils/lock_utils.py +4 -7
- {src → agent_starter_pack}/utils/watch_and_rebuild.py +2 -2
- agent_starter_pack-0.21.0.dist-info/METADATA +182 -0
- agent_starter_pack-0.21.0.dist-info/RECORD +171 -0
- agent_starter_pack-0.21.0.dist-info/entry_points.txt +2 -0
- llm.txt +362 -0
- agent_starter_pack-0.3.3.dist-info/METADATA +0 -164
- agent_starter_pack-0.3.3.dist-info/RECORD +0 -176
- agent_starter_pack-0.3.3.dist-info/entry_points.txt +0 -2
- agents/crewai_coding_crew/README.md +0 -34
- agents/crewai_coding_crew/app/agent.py +0 -86
- agents/crewai_coding_crew/app/crew/config/agents.yaml +0 -39
- agents/crewai_coding_crew/app/crew/config/tasks.yaml +0 -37
- agents/crewai_coding_crew/app/crew/crew.py +0 -71
- agents/crewai_coding_crew/tests/integration/test_agent.py +0 -47
- agents/langgraph_base_react/README.md +0 -9
- agents/langgraph_base_react/app/agent.py +0 -73
- agents/live_api/README.md +0 -37
- agents/live_api/app/agent.py +0 -78
- agents/live_api/app/server.py +0 -196
- agents/live_api/app/templates.py +0 -51
- agents/live_api/app/vector_store.py +0 -55
- agents/live_api/template/.templateconfig.yaml +0 -29
- agents/live_api/tests/integration/test_server_e2e.py +0 -254
- agents/live_api/tests/load_test/load_test.py +0 -40
- agents/live_api/tests/unit/test_server.py +0 -143
- src/base_template/Makefile +0 -72
- src/base_template/README.md +0 -208
- src/base_template/app/__init__.py +0 -3
- src/base_template/app/utils/tracing.py +0 -155
- src/base_template/deployment/README.md +0 -126
- src/base_template/deployment/cd/staging.yaml +0 -216
- src/base_template/deployment/terraform/dev/log_sinks.tf +0 -63
- src/base_template/deployment/terraform/log_sinks.tf +0 -70
- src/base_template/deployment/terraform/providers.tf +0 -37
- src/cli/commands/create.py +0 -664
- src/cli/commands/setup_cicd.py +0 -829
- src/cli/utils/gcp.py +0 -117
- src/cli/utils/logging.py +0 -51
- src/cli/utils/template.py +0 -737
- src/deployment_targets/agent_engine/app/agent_engine_app.py +0 -336
- src/deployment_targets/agent_engine/notebooks/intro_agent_engine.ipynb +0 -1025
- src/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +0 -183
- src/deployment_targets/agent_engine/tests/load_test/README.md +0 -42
- src/deployment_targets/agent_engine/tests/load_test/load_test.py +0 -107
- src/deployment_targets/cloud_run/app/server.py +0 -154
- src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +0 -249
- src/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +0 -0
- src/deployment_targets/cloud_run/tests/load_test/README.md +0 -83
- src/deployment_targets/cloud_run/tests/load_test/load_test.py +0 -118
- src/deployment_targets/cloud_run/uv.lock +0 -6952
- src/frontends/live_api_react/frontend/src/App.tsx +0 -205
- src/frontends/live_api_react/frontend/src/components/control-tray/ControlTray.tsx +0 -217
- src/frontends/live_api_react/frontend/src/components/control-tray/control-tray.scss +0 -201
- src/frontends/live_api_react/frontend/src/components/side-panel/SidePanel.tsx +0 -161
- src/frontends/live_api_react/frontend/src/components/side-panel/side-panel.scss +0 -285
- src/frontends/streamlit/frontend/side_bar.py +0 -214
- src/frontends/streamlit/frontend/streamlit_app.py +0 -265
- src/frontends/streamlit/frontend/style/app_markdown.py +0 -37
- src/frontends/streamlit/frontend/utils/chat_utils.py +0 -67
- src/frontends/streamlit/frontend/utils/local_chat_history.py +0 -125
- src/frontends/streamlit/frontend/utils/message_editing.py +0 -59
- src/frontends/streamlit/frontend/utils/multimodal_utils.py +0 -217
- src/frontends/streamlit/frontend/utils/stream_handler.py +0 -301
- src/frontends/streamlit/frontend/utils/title_summary.py +0 -94
- src/frontends/streamlit_adk/frontend/side_bar.py +0 -214
- src/frontends/streamlit_adk/frontend/streamlit_app.py +0 -314
- src/frontends/streamlit_adk/frontend/style/app_markdown.py +0 -37
- src/frontends/streamlit_adk/frontend/utils/chat_utils.py +0 -84
- src/frontends/streamlit_adk/frontend/utils/local_chat_history.py +0 -110
- src/frontends/streamlit_adk/frontend/utils/message_editing.py +0 -61
- src/frontends/streamlit_adk/frontend/utils/multimodal_utils.py +0 -223
- src/frontends/streamlit_adk/frontend/utils/stream_handler.py +0 -311
- src/frontends/streamlit_adk/frontend/utils/title_summary.py +0 -129
- src/resources/containers/data_processing/Dockerfile +0 -27
- src/resources/containers/e2e-tests/Dockerfile +0 -19
- src/resources/idx/.idx/dev.nix +0 -57
- src/resources/idx/idx-template.json +0 -21
- src/resources/idx/idx-template.nix +0 -26
- src/resources/locks/uv-adk_base-agent_engine.lock +0 -5338
- src/resources/locks/uv-adk_base-cloud_run.lock +0 -5930
- src/resources/locks/uv-agentic_rag-agent_engine.lock +0 -5528
- src/resources/locks/uv-agentic_rag-cloud_run.lock +0 -6120
- src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +0 -6231
- src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +0 -6839
- src/resources/locks/uv-langgraph_base_react-agent_engine.lock +0 -5233
- src/resources/locks/uv-langgraph_base_react-cloud_run.lock +0 -5862
- src/resources/locks/uv-live_api-cloud_run.lock +0 -5832
- src/resources/setup_cicd/cicd_variables.tf +0 -41
- src/resources/setup_cicd/github.tf +0 -87
- {agents → agent_starter_pack/agents}/agentic_rag/app/retrievers.py +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/app/templates.py +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/vars/env.tfvars +0 -0
- {src → agent_starter_pack}/base_template/tests/unit/test_dummy.py +0 -0
- {src/deployment_targets/agent_engine/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/gcs.py +0 -0
- {src → agent_starter_pack}/cli/utils/__init__.py +0 -0
- {src → agent_starter_pack}/cli/utils/datastores.py +0 -0
- {src → agent_starter_pack}/cli/utils/version.py +0 -0
- {src → agent_starter_pack}/data_ingestion/README.md +0 -0
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/ingest_data.py +0 -0
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/pipeline.py +0 -0
- {src → agent_starter_pack}/deployment_targets/agent_engine/deployment_metadata.json +0 -0
- {src → agent_starter_pack}/deployment_targets/agent_engine/tests/load_test/.results/.placeholder +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/favicon.ico +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/index.html +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/robots.txt +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.scss +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.test.tsx +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/AudioPulse.tsx +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/audio-pulse.scss +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/mock-logs.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/contexts/LiveAPIContext.tsx +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-media-stream-mux.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-screen-capture.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-webcam.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.css +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.tsx +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/react-app-env.d.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/reportWebVitals.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/setupTests.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audioworklet-registry.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/store-logger.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/audio-processing.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/vol-meter.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/tsconfig.json +0 -0
- {agent_starter_pack-0.3.3.dist-info → agent_starter_pack-0.21.0.dist-info}/WHEEL +0 -0
- {agent_starter_pack-0.3.3.dist-info → agent_starter_pack-0.21.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,862 @@
|
|
|
1
|
+
# Copyright 2025 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
import re
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
19
|
+
import tempfile
|
|
20
|
+
import time
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
import backoff
|
|
24
|
+
import click
|
|
25
|
+
from rich.console import Console
|
|
26
|
+
|
|
27
|
+
from agent_starter_pack.cli.utils.cicd import (
|
|
28
|
+
ProjectConfig,
|
|
29
|
+
create_github_connection,
|
|
30
|
+
handle_github_authentication,
|
|
31
|
+
is_github_authenticated,
|
|
32
|
+
run_command,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
console = Console()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def display_intro_message() -> None:
|
|
39
|
+
"""Display introduction and warning messages about the setup-cicd command."""
|
|
40
|
+
console.print(
|
|
41
|
+
"\n⚠️ WARNING: The setup-cicd command is experimental and may have unexpected behavior.",
|
|
42
|
+
style="bold yellow",
|
|
43
|
+
)
|
|
44
|
+
console.print("Please report any issues you encounter.\n")
|
|
45
|
+
|
|
46
|
+
console.print("\n📋 About this command:", style="bold blue")
|
|
47
|
+
console.print(
|
|
48
|
+
"This command helps set up a basic CI/CD pipeline for development and testing purposes."
|
|
49
|
+
)
|
|
50
|
+
console.print("It will:")
|
|
51
|
+
console.print("- Create a GitHub repository and connect it to your CI/CD runner")
|
|
52
|
+
console.print("- Set up development environment infrastructure")
|
|
53
|
+
console.print("- Configure basic CI/CD triggers for PR checks and deployments")
|
|
54
|
+
console.print(
|
|
55
|
+
"- Configure remote Terraform state in GCS (use --local-state to use local state instead)"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def display_production_note() -> None:
|
|
60
|
+
"""Display important note about production setup."""
|
|
61
|
+
console.print("\n⚡ Setup Note:", style="bold yellow")
|
|
62
|
+
console.print("For maximum flexibility, we recommend following")
|
|
63
|
+
console.print("the manual setup instructions in deployment/README.md")
|
|
64
|
+
console.print("This will give you more control over:")
|
|
65
|
+
console.print("- Security configurations")
|
|
66
|
+
console.print("- Custom deployment workflows")
|
|
67
|
+
console.print("- Environment-specific settings")
|
|
68
|
+
console.print("- Advanced CI/CD pipeline customization\n")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def check_gh_cli_installed() -> bool:
|
|
72
|
+
"""Check if GitHub CLI is installed.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
bool: True if GitHub CLI is installed, False otherwise
|
|
76
|
+
"""
|
|
77
|
+
try:
|
|
78
|
+
run_command(["gh", "--version"], capture_output=True, check=True)
|
|
79
|
+
return True
|
|
80
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def check_github_scopes(cicd_runner: str) -> None:
|
|
85
|
+
"""Check if GitHub CLI has required scopes for the CI/CD runner.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
cicd_runner: Either 'github_actions' or 'google_cloud_build'
|
|
89
|
+
|
|
90
|
+
Raises:
|
|
91
|
+
click.ClickException: If required scopes are missing
|
|
92
|
+
"""
|
|
93
|
+
try:
|
|
94
|
+
# Get scopes from gh auth status
|
|
95
|
+
result = run_command(["gh", "auth", "status"], capture_output=True, check=True)
|
|
96
|
+
|
|
97
|
+
# Parse scopes from the output
|
|
98
|
+
scopes = []
|
|
99
|
+
for line in result.stdout.split("\n"):
|
|
100
|
+
if "Token scopes:" in line:
|
|
101
|
+
# Extract scopes from line like "- Token scopes: 'gist', 'read:org', 'repo', 'workflow'"
|
|
102
|
+
scopes_part = line.split("Token scopes:")[1].strip()
|
|
103
|
+
# Remove quotes and split by comma
|
|
104
|
+
scopes = [
|
|
105
|
+
s.strip().strip("'\"") for s in scopes_part.split(",") if s.strip()
|
|
106
|
+
]
|
|
107
|
+
break
|
|
108
|
+
|
|
109
|
+
# Define required scopes based on CI/CD runner
|
|
110
|
+
if cicd_runner == "github_actions":
|
|
111
|
+
required_scopes = ["repo", "workflow"]
|
|
112
|
+
missing_scopes = [scope for scope in required_scopes if scope not in scopes]
|
|
113
|
+
|
|
114
|
+
if missing_scopes:
|
|
115
|
+
console.print(
|
|
116
|
+
f"❌ Missing required GitHub scopes: {', '.join(missing_scopes)}",
|
|
117
|
+
style="bold red",
|
|
118
|
+
)
|
|
119
|
+
console.print("To fix this: gh auth login --scopes repo,workflow")
|
|
120
|
+
raise click.ClickException(
|
|
121
|
+
"GitHub CLI authentication lacks required scopes"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
elif cicd_runner == "google_cloud_build":
|
|
125
|
+
required_scopes = ["repo"]
|
|
126
|
+
missing_scopes = [scope for scope in required_scopes if scope not in scopes]
|
|
127
|
+
|
|
128
|
+
if missing_scopes:
|
|
129
|
+
console.print(
|
|
130
|
+
f"❌ Missing required GitHub scopes: {', '.join(missing_scopes)}",
|
|
131
|
+
style="bold red",
|
|
132
|
+
)
|
|
133
|
+
console.print("To fix this: gh auth login --scopes repo")
|
|
134
|
+
raise click.ClickException(
|
|
135
|
+
"GitHub CLI authentication lacks required scopes"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
console.print("✅ GitHub CLI scopes verified")
|
|
139
|
+
|
|
140
|
+
except subprocess.CalledProcessError:
|
|
141
|
+
console.print("⚠️ Could not verify GitHub CLI scopes", style="yellow")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def prompt_gh_cli_installation() -> None:
|
|
145
|
+
"""Display instructions for installing GitHub CLI and exit."""
|
|
146
|
+
console.print("\n❌ GitHub CLI not found", style="bold red")
|
|
147
|
+
console.print("This command requires the GitHub CLI (gh) to be installed.")
|
|
148
|
+
console.print("\nPlease install GitHub CLI from: https://cli.github.com/")
|
|
149
|
+
console.print("\nAfter installation, run this command again.")
|
|
150
|
+
sys.exit(1)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def setup_git_repository(config: ProjectConfig) -> str:
|
|
154
|
+
"""Set up Git repository and remote.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
config: Project configuration containing repository details
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
str: Repository owner from the config
|
|
161
|
+
"""
|
|
162
|
+
console.print("\n🔧 Setting up Git repository...")
|
|
163
|
+
|
|
164
|
+
# Initialize git if not already initialized
|
|
165
|
+
if not (Path.cwd() / ".git").exists():
|
|
166
|
+
run_command(["git", "init", "-b", "main"])
|
|
167
|
+
console.print("✅ Git repository initialized")
|
|
168
|
+
|
|
169
|
+
# Add remote if it doesn't exist
|
|
170
|
+
remote_url = (
|
|
171
|
+
f"https://github.com/{config.repository_owner}/{config.repository_name}.git"
|
|
172
|
+
)
|
|
173
|
+
try:
|
|
174
|
+
run_command(
|
|
175
|
+
["git", "remote", "get-url", "origin"], capture_output=True, check=True
|
|
176
|
+
)
|
|
177
|
+
console.print("✅ Git remote already configured")
|
|
178
|
+
except subprocess.CalledProcessError:
|
|
179
|
+
try:
|
|
180
|
+
run_command(
|
|
181
|
+
["git", "remote", "add", "origin", remote_url],
|
|
182
|
+
capture_output=True,
|
|
183
|
+
check=True,
|
|
184
|
+
)
|
|
185
|
+
console.print(f"✅ Added git remote: {remote_url}")
|
|
186
|
+
except subprocess.CalledProcessError as e:
|
|
187
|
+
console.print(f"❌ Failed to add git remote: {e}", style="bold red")
|
|
188
|
+
raise click.ClickException(f"Failed to add git remote: {e}") from e
|
|
189
|
+
|
|
190
|
+
console.print(
|
|
191
|
+
"\n💡 Tip: Don't forget to commit and push your changes to the repository!"
|
|
192
|
+
)
|
|
193
|
+
return config.repository_owner
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def prompt_for_git_provider() -> str:
|
|
197
|
+
"""Interactively prompt user for git provider selection."""
|
|
198
|
+
providers = ["github"] # Currently only GitHub is supported
|
|
199
|
+
console.print("\n🔄 Git Provider Selection", style="bold blue")
|
|
200
|
+
for i, provider in enumerate(providers, 1):
|
|
201
|
+
console.print(f"{i}. {provider}")
|
|
202
|
+
|
|
203
|
+
while True:
|
|
204
|
+
choice = click.prompt(
|
|
205
|
+
"\nSelect git provider",
|
|
206
|
+
type=click.Choice(["1"]), # Only allow '1' since GitHub is the only option
|
|
207
|
+
default="1",
|
|
208
|
+
)
|
|
209
|
+
return providers[int(choice) - 1]
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def validate_working_directory() -> None:
|
|
213
|
+
"""Ensure we're in the project root directory."""
|
|
214
|
+
if not Path("pyproject.toml").exists():
|
|
215
|
+
raise click.UsageError(
|
|
216
|
+
"This command must be run from the project root directory containing pyproject.toml. "
|
|
217
|
+
"Make sure you are in the folder created by agent-starter-pack."
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def detect_region_from_terraform_vars() -> str | None:
|
|
222
|
+
"""Detect region from Terraform vars file.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
str | None: The detected region, or None if not found or is default
|
|
226
|
+
"""
|
|
227
|
+
try:
|
|
228
|
+
tf_vars_path = Path("deployment/terraform/vars/env.tfvars")
|
|
229
|
+
if not tf_vars_path.exists():
|
|
230
|
+
return None
|
|
231
|
+
|
|
232
|
+
with open(tf_vars_path, encoding="utf-8") as f:
|
|
233
|
+
content = f.read()
|
|
234
|
+
|
|
235
|
+
# Look for region = "value" pattern
|
|
236
|
+
region_match = re.search(r'region\s*=\s*"([^"]+)"', content)
|
|
237
|
+
if region_match:
|
|
238
|
+
detected_region = region_match.group(1)
|
|
239
|
+
# Don't auto-detect if it's the default value
|
|
240
|
+
if detected_region != "us-central1":
|
|
241
|
+
return detected_region
|
|
242
|
+
|
|
243
|
+
return None
|
|
244
|
+
except Exception:
|
|
245
|
+
# If any error occurs, return None to use default
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def update_build_triggers(tf_dir: Path) -> None:
|
|
250
|
+
"""Update build triggers configuration."""
|
|
251
|
+
build_triggers_path = tf_dir / "build_triggers.tf"
|
|
252
|
+
if build_triggers_path.exists():
|
|
253
|
+
with open(build_triggers_path, encoding="utf-8") as f:
|
|
254
|
+
content = f.read()
|
|
255
|
+
|
|
256
|
+
# Add repository dependency to all trigger resources
|
|
257
|
+
modified_content = content.replace(
|
|
258
|
+
"depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]",
|
|
259
|
+
"depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services, google_cloudbuildv2_repository.repo]",
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# Update repository reference in all triggers
|
|
263
|
+
modified_content = modified_content.replace(
|
|
264
|
+
'repository = "projects/${var.cicd_runner_project_id}/locations/${var.region}/connections/${var.host_connection_name}/repositories/${var.repository_name}"',
|
|
265
|
+
"repository = google_cloudbuildv2_repository.repo.id",
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
with open(build_triggers_path, "w", encoding="utf-8") as f:
|
|
269
|
+
f.write(modified_content)
|
|
270
|
+
|
|
271
|
+
console.print("✅ Updated build triggers with repository dependency")
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def prompt_for_repository_details(
|
|
275
|
+
repository_name: str | None = None,
|
|
276
|
+
repository_owner: str | None = None,
|
|
277
|
+
create_repository: bool = False,
|
|
278
|
+
use_existing_repository: bool = False,
|
|
279
|
+
) -> tuple[str, str, bool]:
|
|
280
|
+
"""Interactive prompt for repository details with option to use existing repo."""
|
|
281
|
+
# Get current GitHub username as default owner
|
|
282
|
+
result = run_command(["gh", "api", "user", "--jq", ".login"], capture_output=True)
|
|
283
|
+
default_owner = result.stdout.strip()
|
|
284
|
+
|
|
285
|
+
# Step 1: Determine create_repository value
|
|
286
|
+
if create_repository and use_existing_repository:
|
|
287
|
+
raise ValueError(
|
|
288
|
+
"Cannot specify both create_repository and use_existing_repository"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# If neither flag is set, prompt for the choice
|
|
292
|
+
if not create_repository and not use_existing_repository:
|
|
293
|
+
console.print("\n📦 Repository Configuration", style="bold blue")
|
|
294
|
+
console.print("Choose an option:")
|
|
295
|
+
console.print("1. Create new repository")
|
|
296
|
+
console.print("2. Use existing empty repository")
|
|
297
|
+
|
|
298
|
+
choice = click.prompt(
|
|
299
|
+
"Select option", type=click.Choice(["1", "2"]), default="1"
|
|
300
|
+
)
|
|
301
|
+
create_repository = choice == "1"
|
|
302
|
+
# If use_existing_repository is True, create_repository should be False
|
|
303
|
+
elif use_existing_repository:
|
|
304
|
+
create_repository = False
|
|
305
|
+
# Otherwise create_repository is already True from the flag
|
|
306
|
+
|
|
307
|
+
# Step 2: Get repository name if missing
|
|
308
|
+
if not repository_name:
|
|
309
|
+
# Get project name from pyproject.toml as default
|
|
310
|
+
try:
|
|
311
|
+
with open("pyproject.toml", encoding="utf-8") as f:
|
|
312
|
+
for line in f:
|
|
313
|
+
if line.strip().startswith("name ="):
|
|
314
|
+
default_name = line.split("=")[1].strip().strip("\"'")
|
|
315
|
+
break
|
|
316
|
+
else:
|
|
317
|
+
default_name = f"genai-app-{int(time.time())}"
|
|
318
|
+
except FileNotFoundError:
|
|
319
|
+
default_name = f"genai-app-{int(time.time())}"
|
|
320
|
+
|
|
321
|
+
prompt_text = (
|
|
322
|
+
"Enter new repository name"
|
|
323
|
+
if create_repository
|
|
324
|
+
else "Enter existing repository name"
|
|
325
|
+
)
|
|
326
|
+
repository_name = click.prompt(prompt_text, default=default_name)
|
|
327
|
+
|
|
328
|
+
# Step 3: Get repository owner if missing
|
|
329
|
+
if not repository_owner:
|
|
330
|
+
prompt_text = (
|
|
331
|
+
"Enter repository owner"
|
|
332
|
+
if create_repository
|
|
333
|
+
else "Enter existing repository owner"
|
|
334
|
+
)
|
|
335
|
+
repository_owner = click.prompt(prompt_text, default=default_owner)
|
|
336
|
+
|
|
337
|
+
if repository_name is None or repository_owner is None:
|
|
338
|
+
raise ValueError("Repository name and owner must be provided")
|
|
339
|
+
return repository_name, repository_owner, create_repository
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def setup_terraform_backend(
|
|
343
|
+
tf_dir: Path, project_id: str, region: str, repository_name: str
|
|
344
|
+
) -> None:
|
|
345
|
+
"""Setup terraform backend configuration with GCS bucket"""
|
|
346
|
+
console.print("\n🔧 Setting up Terraform backend...")
|
|
347
|
+
|
|
348
|
+
bucket_name = f"{project_id}-terraform-state"
|
|
349
|
+
|
|
350
|
+
# Ensure bucket exists
|
|
351
|
+
try:
|
|
352
|
+
result = run_command(
|
|
353
|
+
["gsutil", "ls", "-b", f"gs://{bucket_name}"],
|
|
354
|
+
check=False,
|
|
355
|
+
capture_output=True,
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
if result.returncode != 0:
|
|
359
|
+
console.print(f"\n📦 Creating Terraform state bucket: {bucket_name}")
|
|
360
|
+
# Create bucket
|
|
361
|
+
run_command(
|
|
362
|
+
["gsutil", "mb", "-p", project_id, "-l", region, f"gs://{bucket_name}"]
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
# Enable versioning
|
|
366
|
+
run_command(["gsutil", "versioning", "set", "on", f"gs://{bucket_name}"])
|
|
367
|
+
except subprocess.CalledProcessError as e:
|
|
368
|
+
console.print(f"\n❌ Failed to setup state bucket: {e}")
|
|
369
|
+
raise
|
|
370
|
+
|
|
371
|
+
# Create backend.tf in both root and dev directories
|
|
372
|
+
tf_dirs = [
|
|
373
|
+
tf_dir, # Root terraform directory
|
|
374
|
+
tf_dir / "dev", # Dev terraform directory
|
|
375
|
+
]
|
|
376
|
+
|
|
377
|
+
for dir_path in tf_dirs:
|
|
378
|
+
if dir_path.exists():
|
|
379
|
+
# Use different state prefixes for dev and prod
|
|
380
|
+
is_dev_dir = str(dir_path).endswith("/dev")
|
|
381
|
+
state_prefix = f"{repository_name}/{(is_dev_dir and 'dev') or 'prod'}"
|
|
382
|
+
|
|
383
|
+
backend_file = dir_path / "backend.tf"
|
|
384
|
+
backend_content = f'''terraform {{
|
|
385
|
+
backend "gcs" {{
|
|
386
|
+
bucket = "{bucket_name}"
|
|
387
|
+
prefix = "{state_prefix}"
|
|
388
|
+
}}
|
|
389
|
+
}}
|
|
390
|
+
'''
|
|
391
|
+
with open(backend_file, "w", encoding="utf-8") as f:
|
|
392
|
+
f.write(backend_content)
|
|
393
|
+
|
|
394
|
+
console.print(
|
|
395
|
+
f"✅ Terraform backend configured in {dir_path} to use bucket: {bucket_name} with prefix: {state_prefix}"
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def create_or_update_secret(secret_id: str, secret_value: str, project_id: str) -> None:
|
|
400
|
+
"""Create or update a secret in Google Cloud Secret Manager.
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
secret_id: The ID of the secret to create/update
|
|
404
|
+
secret_value: The value to store in the secret
|
|
405
|
+
project_id: The Google Cloud project ID
|
|
406
|
+
|
|
407
|
+
Raises:
|
|
408
|
+
subprocess.CalledProcessError: If secret creation/update fails
|
|
409
|
+
"""
|
|
410
|
+
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8") as temp_file:
|
|
411
|
+
temp_file.write(secret_value)
|
|
412
|
+
temp_file.flush()
|
|
413
|
+
|
|
414
|
+
# First try to add a new version to existing secret
|
|
415
|
+
try:
|
|
416
|
+
run_command(
|
|
417
|
+
[
|
|
418
|
+
"gcloud",
|
|
419
|
+
"secrets",
|
|
420
|
+
"versions",
|
|
421
|
+
"add",
|
|
422
|
+
secret_id,
|
|
423
|
+
"--data-file",
|
|
424
|
+
temp_file.name,
|
|
425
|
+
f"--project={project_id}",
|
|
426
|
+
]
|
|
427
|
+
)
|
|
428
|
+
console.print("✅ Updated existing GitHub PAT secret")
|
|
429
|
+
except subprocess.CalledProcessError:
|
|
430
|
+
# If adding version fails (secret doesn't exist), try to create it
|
|
431
|
+
try:
|
|
432
|
+
run_command(
|
|
433
|
+
[
|
|
434
|
+
"gcloud",
|
|
435
|
+
"secrets",
|
|
436
|
+
"create",
|
|
437
|
+
secret_id,
|
|
438
|
+
"--data-file",
|
|
439
|
+
temp_file.name,
|
|
440
|
+
f"--project={project_id}",
|
|
441
|
+
"--replication-policy",
|
|
442
|
+
"automatic",
|
|
443
|
+
]
|
|
444
|
+
)
|
|
445
|
+
console.print("✅ Created new GitHub PAT secret")
|
|
446
|
+
except subprocess.CalledProcessError as e:
|
|
447
|
+
console.print(
|
|
448
|
+
f"❌ Failed to create/update GitHub PAT secret: {e!s}",
|
|
449
|
+
style="bold red",
|
|
450
|
+
)
|
|
451
|
+
raise
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
console = Console()
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
@click.command()
|
|
458
|
+
@click.option("--dev-project", help="Development project ID")
|
|
459
|
+
@click.option("--staging-project", help="Staging project ID")
|
|
460
|
+
@click.option("--prod-project", help="Production project ID")
|
|
461
|
+
@click.option(
|
|
462
|
+
"--cicd-project", help="CICD project ID (defaults to prod project if not specified)"
|
|
463
|
+
)
|
|
464
|
+
@click.option(
|
|
465
|
+
"--region", help="GCP region (auto-detects from Terraform vars if not specified)"
|
|
466
|
+
)
|
|
467
|
+
@click.option("--repository-name", help="Repository name (optional)")
|
|
468
|
+
@click.option(
|
|
469
|
+
"--repository-owner",
|
|
470
|
+
help="Repository owner (optional, defaults to current GitHub user)",
|
|
471
|
+
)
|
|
472
|
+
@click.option("--host-connection-name", help="Host connection name (optional)")
|
|
473
|
+
@click.option("--github-pat", help="GitHub Personal Access Token for programmatic auth")
|
|
474
|
+
@click.option(
|
|
475
|
+
"--github-app-installation-id",
|
|
476
|
+
help="GitHub App Installation ID for programmatic auth",
|
|
477
|
+
)
|
|
478
|
+
@click.option(
|
|
479
|
+
"--local-state",
|
|
480
|
+
is_flag=True,
|
|
481
|
+
default=False,
|
|
482
|
+
help="Use local Terraform state instead of remote GCS backend (defaults to remote)",
|
|
483
|
+
)
|
|
484
|
+
@click.option("--debug", is_flag=True, help="Enable debug logging")
|
|
485
|
+
@click.option(
|
|
486
|
+
"--auto-approve",
|
|
487
|
+
is_flag=True,
|
|
488
|
+
help="Skip confirmation prompts and proceed automatically",
|
|
489
|
+
)
|
|
490
|
+
@click.option(
|
|
491
|
+
"--create-repository",
|
|
492
|
+
is_flag=True,
|
|
493
|
+
default=False,
|
|
494
|
+
help="Flag indicating whether to create a new repository",
|
|
495
|
+
)
|
|
496
|
+
@click.option(
|
|
497
|
+
"--use-existing-repository",
|
|
498
|
+
is_flag=True,
|
|
499
|
+
default=False,
|
|
500
|
+
help="Flag indicating whether to use an existing repository",
|
|
501
|
+
)
|
|
502
|
+
@backoff.on_exception(
|
|
503
|
+
backoff.expo,
|
|
504
|
+
(subprocess.CalledProcessError, click.ClickException),
|
|
505
|
+
max_tries=3,
|
|
506
|
+
jitter=backoff.full_jitter,
|
|
507
|
+
)
|
|
508
|
+
def setup_cicd(
|
|
509
|
+
dev_project: str | None,
|
|
510
|
+
staging_project: str | None,
|
|
511
|
+
prod_project: str | None,
|
|
512
|
+
cicd_project: str | None,
|
|
513
|
+
region: str | None,
|
|
514
|
+
repository_name: str | None,
|
|
515
|
+
repository_owner: str | None,
|
|
516
|
+
host_connection_name: str | None,
|
|
517
|
+
github_pat: str | None,
|
|
518
|
+
github_app_installation_id: str | None,
|
|
519
|
+
local_state: bool,
|
|
520
|
+
debug: bool,
|
|
521
|
+
auto_approve: bool,
|
|
522
|
+
create_repository: bool,
|
|
523
|
+
use_existing_repository: bool,
|
|
524
|
+
) -> None:
|
|
525
|
+
"""Set up CI/CD infrastructure using Terraform."""
|
|
526
|
+
|
|
527
|
+
# Validate mutually exclusive flags
|
|
528
|
+
if create_repository and use_existing_repository:
|
|
529
|
+
raise click.UsageError(
|
|
530
|
+
"Cannot specify both --create-repository and --use-existing-repository flags"
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
# Check if we're in the root folder by looking for pyproject.toml
|
|
534
|
+
if not Path("pyproject.toml").exists():
|
|
535
|
+
raise click.UsageError(
|
|
536
|
+
"This command must be run from the project root directory containing pyproject.toml. "
|
|
537
|
+
"Make sure you are in the folder created by agent-starter-pack."
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
# Prompt for staging and prod projects if not provided
|
|
541
|
+
if staging_project is None:
|
|
542
|
+
staging_project = click.prompt(
|
|
543
|
+
"Enter your staging project ID (where tests will be run)", type=str
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
if prod_project is None:
|
|
547
|
+
prod_project = click.prompt("Enter your production project ID", type=str)
|
|
548
|
+
|
|
549
|
+
# If cicd_project is not provided, default to prod_project
|
|
550
|
+
if cicd_project is None:
|
|
551
|
+
cicd_project = prod_project
|
|
552
|
+
console.print(f"Using production project '{prod_project}' for CI/CD resources")
|
|
553
|
+
|
|
554
|
+
# Auto-detect region if not provided
|
|
555
|
+
if region is None:
|
|
556
|
+
detected_region = detect_region_from_terraform_vars()
|
|
557
|
+
if detected_region:
|
|
558
|
+
region = detected_region
|
|
559
|
+
console.print(f"Auto-detected region from Terraform vars: {region}")
|
|
560
|
+
else:
|
|
561
|
+
region = "us-central1"
|
|
562
|
+
console.print(f"Using default region: {region}")
|
|
563
|
+
else:
|
|
564
|
+
console.print(f"Using provided region: {region}")
|
|
565
|
+
|
|
566
|
+
# Auto-detect CI/CD runner based on Terraform files (moved earlier)
|
|
567
|
+
tf_dir = Path("deployment/terraform")
|
|
568
|
+
is_github_actions = (tf_dir / "wif.tf").exists() and (tf_dir / "github.tf").exists()
|
|
569
|
+
cicd_runner = "github_actions" if is_github_actions else "google_cloud_build"
|
|
570
|
+
|
|
571
|
+
display_intro_message()
|
|
572
|
+
|
|
573
|
+
console.print("\n⚡ Production Setup Note:", style="bold yellow")
|
|
574
|
+
console.print(
|
|
575
|
+
"For production deployments and maximum flexibility, we recommend following"
|
|
576
|
+
)
|
|
577
|
+
console.print("the manual setup instructions in deployment/README.md")
|
|
578
|
+
console.print("This will give you more control over:")
|
|
579
|
+
console.print("- Security configurations")
|
|
580
|
+
console.print("- Custom deployment workflows")
|
|
581
|
+
console.print("- Environment-specific settings")
|
|
582
|
+
console.print("- Advanced CI/CD pipeline customization\n")
|
|
583
|
+
|
|
584
|
+
# Add the confirmation prompt
|
|
585
|
+
if not auto_approve:
|
|
586
|
+
if not click.confirm("\nDo you want to continue with the setup?", default=True):
|
|
587
|
+
console.print("\n🛑 Setup cancelled by user", style="bold yellow")
|
|
588
|
+
return
|
|
589
|
+
|
|
590
|
+
if debug:
|
|
591
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
592
|
+
console.print("> Debug mode enabled")
|
|
593
|
+
|
|
594
|
+
# Auto-detect CI/CD runner based on Terraform files
|
|
595
|
+
tf_dir = Path("deployment/terraform")
|
|
596
|
+
is_github_actions = (tf_dir / "wif.tf").exists() and (tf_dir / "github.tf").exists()
|
|
597
|
+
cicd_runner = "github_actions" if is_github_actions else "google_cloud_build"
|
|
598
|
+
if debug:
|
|
599
|
+
logging.debug(f"Detected CI/CD runner: {cicd_runner}")
|
|
600
|
+
|
|
601
|
+
# Ensure GitHub CLI is available and authenticated
|
|
602
|
+
if not check_gh_cli_installed():
|
|
603
|
+
prompt_gh_cli_installation()
|
|
604
|
+
if not is_github_authenticated():
|
|
605
|
+
console.print("\n⚠️ Not authenticated with GitHub CLI", style="yellow")
|
|
606
|
+
handle_github_authentication()
|
|
607
|
+
else:
|
|
608
|
+
console.print("✅ GitHub CLI authentication verified")
|
|
609
|
+
|
|
610
|
+
# Check if GitHub CLI has required scopes for the CI/CD runner
|
|
611
|
+
console.print("\n🔍 Checking GitHub CLI scopes...")
|
|
612
|
+
check_github_scopes(cicd_runner)
|
|
613
|
+
|
|
614
|
+
# Gather repository details
|
|
615
|
+
if auto_approve:
|
|
616
|
+
# Auto-generate repository details when auto-approve is used
|
|
617
|
+
if not repository_owner:
|
|
618
|
+
repository_owner = run_command(
|
|
619
|
+
["gh", "api", "user", "--jq", ".login"], capture_output=True
|
|
620
|
+
).stdout.strip()
|
|
621
|
+
if not repository_name:
|
|
622
|
+
# Get project name from pyproject.toml or generate one
|
|
623
|
+
try:
|
|
624
|
+
with open("pyproject.toml", encoding="utf-8") as f:
|
|
625
|
+
for line in f:
|
|
626
|
+
if line.strip().startswith("name ="):
|
|
627
|
+
repository_name = line.split("=")[1].strip().strip("\"'")
|
|
628
|
+
break
|
|
629
|
+
else:
|
|
630
|
+
repository_name = f"genai-app-{int(time.time())}"
|
|
631
|
+
except FileNotFoundError:
|
|
632
|
+
repository_name = f"genai-app-{int(time.time())}"
|
|
633
|
+
console.print(
|
|
634
|
+
f"✅ Auto-generated repository: {repository_owner}/{repository_name}"
|
|
635
|
+
)
|
|
636
|
+
# Keep the CLI argument value for create_repository
|
|
637
|
+
else:
|
|
638
|
+
# Use prompt_for_repository_details to fill in any missing information
|
|
639
|
+
repository_name, repository_owner, create_repository = (
|
|
640
|
+
prompt_for_repository_details(
|
|
641
|
+
repository_name,
|
|
642
|
+
repository_owner,
|
|
643
|
+
create_repository,
|
|
644
|
+
use_existing_repository,
|
|
645
|
+
)
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
assert repository_name is not None, "Repository name must be provided"
|
|
649
|
+
assert repository_owner is not None, "Repository owner must be provided"
|
|
650
|
+
|
|
651
|
+
# Set default host connection name if not provided
|
|
652
|
+
if not host_connection_name:
|
|
653
|
+
host_connection_name = f"git-{repository_name}"
|
|
654
|
+
|
|
655
|
+
# For Cloud Build, determine mode and handle connection creation
|
|
656
|
+
oauth_token_secret_id = None
|
|
657
|
+
# Track original repository state for Terraform (before we create it)
|
|
658
|
+
terraform_create_repository = create_repository
|
|
659
|
+
|
|
660
|
+
if cicd_runner == "google_cloud_build":
|
|
661
|
+
# Determine if we're in programmatic or interactive mode based on provided credentials
|
|
662
|
+
detected_mode = (
|
|
663
|
+
"programmatic"
|
|
664
|
+
if github_pat and github_app_installation_id
|
|
665
|
+
else "interactive"
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
if detected_mode == "interactive":
|
|
669
|
+
console.print(
|
|
670
|
+
"\n🔗 Interactive mode: Creating GitHub connection using gcloud CLI..."
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
# Create connection using gcloud CLI (interactive approach)
|
|
674
|
+
try:
|
|
675
|
+
oauth_token_secret_id, github_app_installation_id = (
|
|
676
|
+
create_github_connection(
|
|
677
|
+
project_id=cicd_project,
|
|
678
|
+
region=region,
|
|
679
|
+
connection_name=host_connection_name,
|
|
680
|
+
)
|
|
681
|
+
)
|
|
682
|
+
create_cb_connection = (
|
|
683
|
+
True # Connection created by gcloud, Terraform will reference it
|
|
684
|
+
)
|
|
685
|
+
console.print("✅ GitHub connection created successfully")
|
|
686
|
+
except Exception as e:
|
|
687
|
+
console.print(
|
|
688
|
+
f"❌ Failed to create GitHub connection: {e}", style="red"
|
|
689
|
+
)
|
|
690
|
+
raise
|
|
691
|
+
|
|
692
|
+
elif detected_mode == "programmatic":
|
|
693
|
+
console.print(
|
|
694
|
+
"\n🔐 Programmatic mode: Creating GitHub PAT secret using gcloud CLI..."
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
oauth_token_secret_id = "github-pat" # Use fixed secret ID like main branch
|
|
698
|
+
|
|
699
|
+
if github_pat is None:
|
|
700
|
+
raise ValueError("GitHub PAT is required for programmatic mode")
|
|
701
|
+
|
|
702
|
+
# Create GitHub PAT secret using gcloud CLI instead of Terraform
|
|
703
|
+
console.print("📝 Creating GitHub PAT secret using gcloud CLI...")
|
|
704
|
+
create_or_update_secret(oauth_token_secret_id, github_pat, cicd_project)
|
|
705
|
+
create_cb_connection = False # Terraform will not create connection, will reference existing secret
|
|
706
|
+
console.print("✅ GitHub PAT secret created using gcloud CLI")
|
|
707
|
+
|
|
708
|
+
# For GitHub Actions, no connection management needed
|
|
709
|
+
if cicd_runner == "github_actions":
|
|
710
|
+
create_cb_connection = False
|
|
711
|
+
|
|
712
|
+
console.print("\n📦 Starting CI/CD Infrastructure Setup", style="bold blue")
|
|
713
|
+
console.print("=====================================")
|
|
714
|
+
|
|
715
|
+
# Setup Terraform backend if not using local state
|
|
716
|
+
if not local_state:
|
|
717
|
+
console.print("\n🔧 Setting up remote Terraform backend...")
|
|
718
|
+
setup_terraform_backend(
|
|
719
|
+
tf_dir=tf_dir,
|
|
720
|
+
project_id=cicd_project,
|
|
721
|
+
region=region,
|
|
722
|
+
repository_name=repository_name,
|
|
723
|
+
)
|
|
724
|
+
console.print("✅ Remote Terraform backend configured")
|
|
725
|
+
else:
|
|
726
|
+
console.print("\n📝 Using local Terraform state (remote backend disabled)")
|
|
727
|
+
|
|
728
|
+
# Prepare Terraform variables
|
|
729
|
+
env_vars_path = tf_dir / "vars" / "env.tfvars"
|
|
730
|
+
terraform_vars = {
|
|
731
|
+
"staging_project_id": staging_project,
|
|
732
|
+
"prod_project_id": prod_project,
|
|
733
|
+
"cicd_runner_project_id": cicd_project,
|
|
734
|
+
"region": region,
|
|
735
|
+
"repository_name": repository_name,
|
|
736
|
+
"repository_owner": repository_owner
|
|
737
|
+
or run_command(
|
|
738
|
+
["gh", "api", "user", "--jq", ".login"], capture_output=True
|
|
739
|
+
).stdout.strip(),
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
# Add CI/CD runner specific variables
|
|
743
|
+
if cicd_runner == "google_cloud_build":
|
|
744
|
+
terraform_vars.update(
|
|
745
|
+
{
|
|
746
|
+
"host_connection_name": host_connection_name,
|
|
747
|
+
"create_cb_connection": str(create_cb_connection).lower(),
|
|
748
|
+
"create_repository": str(
|
|
749
|
+
terraform_create_repository
|
|
750
|
+
).lower(), # Use original state
|
|
751
|
+
"github_app_installation_id": github_app_installation_id,
|
|
752
|
+
"github_pat_secret_id": oauth_token_secret_id,
|
|
753
|
+
}
|
|
754
|
+
)
|
|
755
|
+
else: # github_actions
|
|
756
|
+
terraform_vars["create_repository"] = str(
|
|
757
|
+
terraform_create_repository
|
|
758
|
+
).lower() # Use original state
|
|
759
|
+
|
|
760
|
+
# Write Terraform variables
|
|
761
|
+
with open(env_vars_path, "w", encoding="utf-8") as f:
|
|
762
|
+
for var_name, var_value in terraform_vars.items():
|
|
763
|
+
if var_value in ("true", "false"): # Boolean values
|
|
764
|
+
f.write(f"{var_name} = {var_value}\n")
|
|
765
|
+
elif var_value is not None: # String values
|
|
766
|
+
f.write(f'{var_name} = "{var_value}"\n')
|
|
767
|
+
|
|
768
|
+
console.print("✅ Updated env.tfvars with variables")
|
|
769
|
+
|
|
770
|
+
# Update dev environment vars if dev project provided
|
|
771
|
+
if dev_project:
|
|
772
|
+
dev_tf_vars_path = tf_dir / "dev" / "vars" / "env.tfvars"
|
|
773
|
+
if dev_tf_vars_path.exists():
|
|
774
|
+
with open(dev_tf_vars_path, "w", encoding="utf-8") as f:
|
|
775
|
+
f.write(f'dev_project_id = "{dev_project}"\n')
|
|
776
|
+
console.print("✅ Updated dev env.tfvars")
|
|
777
|
+
|
|
778
|
+
# Apply dev Terraform if dev project is provided
|
|
779
|
+
if dev_project:
|
|
780
|
+
dev_tf_dir = tf_dir / "dev"
|
|
781
|
+
if dev_tf_dir.exists():
|
|
782
|
+
console.print("\n🏗️ Applying dev Terraform configuration...")
|
|
783
|
+
if local_state:
|
|
784
|
+
run_command(["terraform", "init", "-backend=false"], cwd=dev_tf_dir)
|
|
785
|
+
else:
|
|
786
|
+
run_command(["terraform", "init"], cwd=dev_tf_dir)
|
|
787
|
+
run_command(
|
|
788
|
+
[
|
|
789
|
+
"terraform",
|
|
790
|
+
"apply",
|
|
791
|
+
"-auto-approve",
|
|
792
|
+
"--var-file",
|
|
793
|
+
"vars/env.tfvars",
|
|
794
|
+
],
|
|
795
|
+
cwd=dev_tf_dir,
|
|
796
|
+
)
|
|
797
|
+
console.print("✅ Dev environment deployed")
|
|
798
|
+
else:
|
|
799
|
+
console.print("ℹ️ No dev Terraform directory found")
|
|
800
|
+
|
|
801
|
+
# Apply prod Terraform
|
|
802
|
+
console.print("\n🚀 Applying prod Terraform configuration...")
|
|
803
|
+
if local_state:
|
|
804
|
+
run_command(["terraform", "init", "-backend=false"], cwd=tf_dir)
|
|
805
|
+
else:
|
|
806
|
+
run_command(["terraform", "init"], cwd=tf_dir)
|
|
807
|
+
|
|
808
|
+
# Prepare environment variables for Terraform
|
|
809
|
+
terraform_env_vars = {}
|
|
810
|
+
if (
|
|
811
|
+
cicd_runner == "google_cloud_build"
|
|
812
|
+
and detected_mode == "programmatic"
|
|
813
|
+
and github_pat
|
|
814
|
+
):
|
|
815
|
+
terraform_env_vars["GITHUB_TOKEN"] = (
|
|
816
|
+
github_pat # For GitHub provider authentication
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
run_command(
|
|
820
|
+
["terraform", "apply", "-auto-approve", "--var-file", "vars/env.tfvars"],
|
|
821
|
+
cwd=tf_dir,
|
|
822
|
+
env_vars=terraform_env_vars if terraform_env_vars else None,
|
|
823
|
+
)
|
|
824
|
+
console.print("✅ Prod/Staging infrastructure deployed")
|
|
825
|
+
|
|
826
|
+
config = ProjectConfig(
|
|
827
|
+
staging_project_id=staging_project,
|
|
828
|
+
prod_project_id=prod_project,
|
|
829
|
+
cicd_project_id=cicd_project,
|
|
830
|
+
agent="", # Not used in git setup
|
|
831
|
+
deployment_target="", # Not used in git setup
|
|
832
|
+
region=region,
|
|
833
|
+
repository_name=repository_name,
|
|
834
|
+
repository_owner=repository_owner,
|
|
835
|
+
)
|
|
836
|
+
|
|
837
|
+
setup_git_repository(config)
|
|
838
|
+
|
|
839
|
+
console.print("\n✅ CI/CD infrastructure setup complete!")
|
|
840
|
+
|
|
841
|
+
# Print useful information
|
|
842
|
+
repo_url = f"https://github.com/{repository_owner}/{repository_name}"
|
|
843
|
+
|
|
844
|
+
console.print("\n📋 Summary:")
|
|
845
|
+
console.print(f"• Repository: {repo_url}")
|
|
846
|
+
console.print(f"• CI/CD Runner: {cicd_runner.replace('_', ' ').title()}")
|
|
847
|
+
|
|
848
|
+
if cicd_runner == "google_cloud_build":
|
|
849
|
+
console.print(
|
|
850
|
+
f"• Cloud Build: https://console.cloud.google.com/cloud-build/builds?project={cicd_project}"
|
|
851
|
+
)
|
|
852
|
+
else:
|
|
853
|
+
console.print(f"• GitHub Actions: {repo_url}/actions")
|
|
854
|
+
|
|
855
|
+
if not local_state:
|
|
856
|
+
console.print(f"• Terraform State: gs://{cicd_project}-terraform-state")
|
|
857
|
+
else:
|
|
858
|
+
console.print("• Terraform State: Local")
|
|
859
|
+
|
|
860
|
+
console.print("\n💡 Next steps:")
|
|
861
|
+
console.print("1. Commit and push your code to the repository")
|
|
862
|
+
console.print("2. Your CI/CD pipeline will automatically trigger on pushes")
|