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.
Files changed (255) hide show
  1. agent_starter_pack/agents/README.md +7 -0
  2. agents/langgraph_base_react/template/.templateconfig.yaml → agent_starter_pack/agents/adk_a2a_base/.template/templateconfig.yaml +5 -10
  3. agent_starter_pack/agents/adk_a2a_base/README.md +37 -0
  4. src/deployment_targets/cloud_run/Dockerfile → agent_starter_pack/agents/adk_a2a_base/app/__init__.py +2 -14
  5. agent_starter_pack/agents/adk_a2a_base/app/agent.py +70 -0
  6. agent_starter_pack/agents/adk_a2a_base/notebooks/adk_a2a_app_testing.ipynb +583 -0
  7. agents/crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb → agent_starter_pack/agents/adk_a2a_base/notebooks/evaluating_adk_agent.ipynb +163 -199
  8. {agents/adk_base → agent_starter_pack/agents/adk_a2a_base}/tests/integration/test_agent.py +2 -2
  9. agents/adk_base/template/.templateconfig.yaml → agent_starter_pack/agents/adk_base/.template/templateconfig.yaml +4 -1
  10. {agents → agent_starter_pack/agents}/adk_base/README.md +1 -1
  11. agent_starter_pack/agents/adk_base/app/__init__.py +17 -0
  12. {agents → agent_starter_pack/agents}/adk_base/app/agent.py +5 -2
  13. {agents → agent_starter_pack/agents}/adk_base/notebooks/adk_app_testing.ipynb +128 -82
  14. agents/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb → agent_starter_pack/agents/adk_base/notebooks/evaluating_adk_agent.ipynb +181 -207
  15. agent_starter_pack/agents/adk_base/tests/integration/test_agent.py +58 -0
  16. agents/crewai_coding_crew/template/.templateconfig.yaml → agent_starter_pack/agents/adk_live/.template/templateconfig.yaml +5 -9
  17. agent_starter_pack/agents/adk_live/README.md +32 -0
  18. agent_starter_pack/agents/adk_live/app/__init__.py +17 -0
  19. agent_starter_pack/agents/adk_live/app/agent.py +51 -0
  20. agent_starter_pack/agents/adk_live/tests/unit/test_dummy.py +38 -0
  21. agents/agentic_rag/template/.templateconfig.yaml → agent_starter_pack/agents/agentic_rag/.template/templateconfig.yaml +7 -3
  22. {agents → agent_starter_pack/agents}/agentic_rag/README.md +1 -1
  23. agent_starter_pack/agents/agentic_rag/app/__init__.py +17 -0
  24. {agents → agent_starter_pack/agents}/agentic_rag/app/agent.py +8 -4
  25. {agents → agent_starter_pack/agents}/agentic_rag/notebooks/adk_app_testing.ipynb +128 -82
  26. agent_starter_pack/agents/agentic_rag/notebooks/evaluating_adk_agent.ipynb +1535 -0
  27. {agents → agent_starter_pack/agents}/agentic_rag/tests/integration/test_agent.py +3 -3
  28. agent_starter_pack/agents/langgraph_base/.template/templateconfig.yaml +31 -0
  29. agent_starter_pack/agents/langgraph_base/README.md +30 -0
  30. agent_starter_pack/agents/langgraph_base/app/__init__.py +17 -0
  31. agent_starter_pack/agents/langgraph_base/app/agent.py +34 -0
  32. {agents/crewai_coding_crew → agent_starter_pack/agents/langgraph_base}/notebooks/evaluating_langgraph_agent.ipynb +30 -17
  33. {agents/langgraph_base_react → agent_starter_pack/agents/langgraph_base}/tests/integration/test_agent.py +2 -2
  34. {src → agent_starter_pack}/base_template/.gitignore +5 -3
  35. agent_starter_pack/base_template/GEMINI.md +5 -0
  36. agent_starter_pack/base_template/Makefile +339 -0
  37. agent_starter_pack/base_template/README.md +267 -0
  38. agent_starter_pack/base_template/deployment/README.md +11 -0
  39. {src → agent_starter_pack}/base_template/deployment/terraform/apis.tf +2 -2
  40. {src → agent_starter_pack}/base_template/deployment/terraform/dev/apis.tf +6 -1
  41. {src → agent_starter_pack}/base_template/deployment/terraform/dev/iam.tf +12 -11
  42. {src → agent_starter_pack}/base_template/deployment/terraform/dev/providers.tf +5 -1
  43. {src → agent_starter_pack}/base_template/deployment/terraform/dev/storage.tf +1 -1
  44. {src → agent_starter_pack}/base_template/deployment/terraform/dev/variables.tf +10 -10
  45. agent_starter_pack/base_template/deployment/terraform/dev/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +193 -0
  46. agent_starter_pack/base_template/deployment/terraform/github.tf +337 -0
  47. {src → agent_starter_pack}/base_template/deployment/terraform/iam.tf +20 -41
  48. {src → agent_starter_pack}/base_template/deployment/terraform/locals.tf +10 -3
  49. {src/resources/setup_cicd → agent_starter_pack/base_template/deployment/terraform}/providers.tf +8 -1
  50. {src → agent_starter_pack}/base_template/deployment/terraform/service_accounts.tf +7 -8
  51. agent_starter_pack/base_template/deployment/terraform/sql/completions.sql +138 -0
  52. {src → agent_starter_pack}/base_template/deployment/terraform/storage.tf +7 -16
  53. {src → agent_starter_pack}/base_template/deployment/terraform/variables.tf +61 -28
  54. {src → agent_starter_pack}/base_template/deployment/terraform/vars/env.tfvars +6 -1
  55. agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'github_actions' %}wif.tf{% else %}unused_wif.tf{% endif %} +43 -0
  56. 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
  57. agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +206 -0
  58. {src → agent_starter_pack}/base_template/pyproject.toml +24 -37
  59. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +132 -0
  60. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/pr_checks.yaml +65 -0
  61. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +259 -0
  62. 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
  63. 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
  64. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +322 -0
  65. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/telemetry.py +96 -0
  66. {src/base_template/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/typing.py +7 -9
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. agent_starter_pack/cli/commands/create.py +1256 -0
  73. agent_starter_pack/cli/commands/enhance.py +611 -0
  74. agent_starter_pack/cli/commands/list.py +203 -0
  75. agent_starter_pack/cli/commands/register_gemini_enterprise.py +1070 -0
  76. agent_starter_pack/cli/commands/setup_cicd.py +862 -0
  77. {src → agent_starter_pack}/cli/main.py +10 -2
  78. {src → agent_starter_pack}/cli/utils/cicd.py +139 -48
  79. agent_starter_pack/cli/utils/gcp.py +263 -0
  80. agent_starter_pack/cli/utils/logging.py +103 -0
  81. agent_starter_pack/cli/utils/remote_template.py +677 -0
  82. agent_starter_pack/cli/utils/template.py +1466 -0
  83. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/process_data.py +1 -1
  84. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/submit_pipeline.py +20 -6
  85. {src → agent_starter_pack}/data_ingestion/pyproject.toml +1 -0
  86. {src → agent_starter_pack}/data_ingestion/uv.lock +602 -494
  87. agent_starter_pack/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +484 -0
  88. agent_starter_pack/deployment_targets/agent_engine/tests/load_test/README.md +84 -0
  89. agent_starter_pack/deployment_targets/agent_engine/tests/load_test/load_test.py +424 -0
  90. agent_starter_pack/deployment_targets/agent_engine/tests/{% if cookiecutter.is_a2a %}helpers.py{% else %}unused_helpers.py{% endif %} +138 -0
  91. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/agent_engine_app.py +263 -0
  92. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/deploy.py +414 -0
  93. 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
  94. agent_starter_pack/deployment_targets/cloud_run/Dockerfile +51 -0
  95. agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +243 -0
  96. agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/service.tf +417 -0
  97. agent_starter_pack/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +705 -0
  98. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +321 -0
  99. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/README.md +165 -0
  100. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/load_test.py +329 -0
  101. agent_starter_pack/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/fast_api_app.py +556 -0
  102. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package-lock.json +79 -1044
  103. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package.json +1 -9
  104. agent_starter_pack/frontends/adk_live_react/frontend/src/App.tsx +65 -0
  105. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/Logger.tsx +8 -3
  106. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/logger.scss +26 -0
  107. agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/SidePanel.tsx +516 -0
  108. agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/side-panel.scss +563 -0
  109. agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/TranscriptionPreview.tsx +106 -0
  110. agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/transcription-preview.scss +150 -0
  111. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-live-api.ts +8 -2
  112. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/multimodal-live-types.ts +40 -2
  113. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-recorder.ts +1 -1
  114. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-streamer.ts +1 -1
  115. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/multimodal-live-client.ts +210 -24
  116. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/utils.ts +27 -5
  117. agent_starter_pack/resources/docs/adk-cheatsheet.md +1628 -0
  118. agent_starter_pack/resources/locks/uv-adk_a2a_base-agent_engine.lock +4966 -0
  119. agent_starter_pack/resources/locks/uv-adk_a2a_base-cloud_run.lock +5011 -0
  120. agent_starter_pack/resources/locks/uv-adk_base-agent_engine.lock +4946 -0
  121. agent_starter_pack/resources/locks/uv-adk_base-cloud_run.lock +4991 -0
  122. agent_starter_pack/resources/locks/uv-adk_live-agent_engine.lock +4963 -0
  123. agent_starter_pack/resources/locks/uv-adk_live-cloud_run.lock +5006 -0
  124. agent_starter_pack/resources/locks/uv-agentic_rag-agent_engine.lock +5487 -0
  125. agent_starter_pack/resources/locks/uv-agentic_rag-cloud_run.lock +5532 -0
  126. agent_starter_pack/resources/locks/uv-langgraph_base-agent_engine.lock +5788 -0
  127. agent_starter_pack/resources/locks/uv-langgraph_base-cloud_run.lock +5811 -0
  128. {src → agent_starter_pack}/utils/generate_locks.py +15 -12
  129. {src → agent_starter_pack}/utils/lock_utils.py +4 -7
  130. {src → agent_starter_pack}/utils/watch_and_rebuild.py +2 -2
  131. agent_starter_pack-0.21.0.dist-info/METADATA +182 -0
  132. agent_starter_pack-0.21.0.dist-info/RECORD +171 -0
  133. agent_starter_pack-0.21.0.dist-info/entry_points.txt +2 -0
  134. llm.txt +362 -0
  135. agent_starter_pack-0.3.3.dist-info/METADATA +0 -164
  136. agent_starter_pack-0.3.3.dist-info/RECORD +0 -176
  137. agent_starter_pack-0.3.3.dist-info/entry_points.txt +0 -2
  138. agents/crewai_coding_crew/README.md +0 -34
  139. agents/crewai_coding_crew/app/agent.py +0 -86
  140. agents/crewai_coding_crew/app/crew/config/agents.yaml +0 -39
  141. agents/crewai_coding_crew/app/crew/config/tasks.yaml +0 -37
  142. agents/crewai_coding_crew/app/crew/crew.py +0 -71
  143. agents/crewai_coding_crew/tests/integration/test_agent.py +0 -47
  144. agents/langgraph_base_react/README.md +0 -9
  145. agents/langgraph_base_react/app/agent.py +0 -73
  146. agents/live_api/README.md +0 -37
  147. agents/live_api/app/agent.py +0 -78
  148. agents/live_api/app/server.py +0 -196
  149. agents/live_api/app/templates.py +0 -51
  150. agents/live_api/app/vector_store.py +0 -55
  151. agents/live_api/template/.templateconfig.yaml +0 -29
  152. agents/live_api/tests/integration/test_server_e2e.py +0 -254
  153. agents/live_api/tests/load_test/load_test.py +0 -40
  154. agents/live_api/tests/unit/test_server.py +0 -143
  155. src/base_template/Makefile +0 -72
  156. src/base_template/README.md +0 -208
  157. src/base_template/app/__init__.py +0 -3
  158. src/base_template/app/utils/tracing.py +0 -155
  159. src/base_template/deployment/README.md +0 -126
  160. src/base_template/deployment/cd/staging.yaml +0 -216
  161. src/base_template/deployment/terraform/dev/log_sinks.tf +0 -63
  162. src/base_template/deployment/terraform/log_sinks.tf +0 -70
  163. src/base_template/deployment/terraform/providers.tf +0 -37
  164. src/cli/commands/create.py +0 -664
  165. src/cli/commands/setup_cicd.py +0 -829
  166. src/cli/utils/gcp.py +0 -117
  167. src/cli/utils/logging.py +0 -51
  168. src/cli/utils/template.py +0 -737
  169. src/deployment_targets/agent_engine/app/agent_engine_app.py +0 -336
  170. src/deployment_targets/agent_engine/notebooks/intro_agent_engine.ipynb +0 -1025
  171. src/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +0 -183
  172. src/deployment_targets/agent_engine/tests/load_test/README.md +0 -42
  173. src/deployment_targets/agent_engine/tests/load_test/load_test.py +0 -107
  174. src/deployment_targets/cloud_run/app/server.py +0 -154
  175. src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +0 -249
  176. src/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +0 -0
  177. src/deployment_targets/cloud_run/tests/load_test/README.md +0 -83
  178. src/deployment_targets/cloud_run/tests/load_test/load_test.py +0 -118
  179. src/deployment_targets/cloud_run/uv.lock +0 -6952
  180. src/frontends/live_api_react/frontend/src/App.tsx +0 -205
  181. src/frontends/live_api_react/frontend/src/components/control-tray/ControlTray.tsx +0 -217
  182. src/frontends/live_api_react/frontend/src/components/control-tray/control-tray.scss +0 -201
  183. src/frontends/live_api_react/frontend/src/components/side-panel/SidePanel.tsx +0 -161
  184. src/frontends/live_api_react/frontend/src/components/side-panel/side-panel.scss +0 -285
  185. src/frontends/streamlit/frontend/side_bar.py +0 -214
  186. src/frontends/streamlit/frontend/streamlit_app.py +0 -265
  187. src/frontends/streamlit/frontend/style/app_markdown.py +0 -37
  188. src/frontends/streamlit/frontend/utils/chat_utils.py +0 -67
  189. src/frontends/streamlit/frontend/utils/local_chat_history.py +0 -125
  190. src/frontends/streamlit/frontend/utils/message_editing.py +0 -59
  191. src/frontends/streamlit/frontend/utils/multimodal_utils.py +0 -217
  192. src/frontends/streamlit/frontend/utils/stream_handler.py +0 -301
  193. src/frontends/streamlit/frontend/utils/title_summary.py +0 -94
  194. src/frontends/streamlit_adk/frontend/side_bar.py +0 -214
  195. src/frontends/streamlit_adk/frontend/streamlit_app.py +0 -314
  196. src/frontends/streamlit_adk/frontend/style/app_markdown.py +0 -37
  197. src/frontends/streamlit_adk/frontend/utils/chat_utils.py +0 -84
  198. src/frontends/streamlit_adk/frontend/utils/local_chat_history.py +0 -110
  199. src/frontends/streamlit_adk/frontend/utils/message_editing.py +0 -61
  200. src/frontends/streamlit_adk/frontend/utils/multimodal_utils.py +0 -223
  201. src/frontends/streamlit_adk/frontend/utils/stream_handler.py +0 -311
  202. src/frontends/streamlit_adk/frontend/utils/title_summary.py +0 -129
  203. src/resources/containers/data_processing/Dockerfile +0 -27
  204. src/resources/containers/e2e-tests/Dockerfile +0 -19
  205. src/resources/idx/.idx/dev.nix +0 -57
  206. src/resources/idx/idx-template.json +0 -21
  207. src/resources/idx/idx-template.nix +0 -26
  208. src/resources/locks/uv-adk_base-agent_engine.lock +0 -5338
  209. src/resources/locks/uv-adk_base-cloud_run.lock +0 -5930
  210. src/resources/locks/uv-agentic_rag-agent_engine.lock +0 -5528
  211. src/resources/locks/uv-agentic_rag-cloud_run.lock +0 -6120
  212. src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +0 -6231
  213. src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +0 -6839
  214. src/resources/locks/uv-langgraph_base_react-agent_engine.lock +0 -5233
  215. src/resources/locks/uv-langgraph_base_react-cloud_run.lock +0 -5862
  216. src/resources/locks/uv-live_api-cloud_run.lock +0 -5832
  217. src/resources/setup_cicd/cicd_variables.tf +0 -41
  218. src/resources/setup_cicd/github.tf +0 -87
  219. {agents → agent_starter_pack/agents}/agentic_rag/app/retrievers.py +0 -0
  220. {agents → agent_starter_pack/agents}/agentic_rag/app/templates.py +0 -0
  221. {src → agent_starter_pack}/base_template/deployment/terraform/dev/vars/env.tfvars +0 -0
  222. {src → agent_starter_pack}/base_template/tests/unit/test_dummy.py +0 -0
  223. {src/deployment_targets/agent_engine/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/gcs.py +0 -0
  224. {src → agent_starter_pack}/cli/utils/__init__.py +0 -0
  225. {src → agent_starter_pack}/cli/utils/datastores.py +0 -0
  226. {src → agent_starter_pack}/cli/utils/version.py +0 -0
  227. {src → agent_starter_pack}/data_ingestion/README.md +0 -0
  228. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/ingest_data.py +0 -0
  229. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/pipeline.py +0 -0
  230. {src → agent_starter_pack}/deployment_targets/agent_engine/deployment_metadata.json +0 -0
  231. {src → agent_starter_pack}/deployment_targets/agent_engine/tests/load_test/.results/.placeholder +0 -0
  232. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/favicon.ico +0 -0
  233. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/index.html +0 -0
  234. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/robots.txt +0 -0
  235. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.scss +0 -0
  236. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.test.tsx +0 -0
  237. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/AudioPulse.tsx +0 -0
  238. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/audio-pulse.scss +0 -0
  239. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/mock-logs.ts +0 -0
  240. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/contexts/LiveAPIContext.tsx +0 -0
  241. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-media-stream-mux.ts +0 -0
  242. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-screen-capture.ts +0 -0
  243. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-webcam.ts +0 -0
  244. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.css +0 -0
  245. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.tsx +0 -0
  246. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/react-app-env.d.ts +0 -0
  247. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/reportWebVitals.ts +0 -0
  248. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/setupTests.ts +0 -0
  249. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audioworklet-registry.ts +0 -0
  250. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/store-logger.ts +0 -0
  251. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/audio-processing.ts +0 -0
  252. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/vol-meter.ts +0 -0
  253. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/tsconfig.json +0 -0
  254. {agent_starter_pack-0.3.3.dist-info → agent_starter_pack-0.21.0.dist-info}/WHEEL +0 -0
  255. {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")