keboola-cli 0.63.4__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.
- keboola_agent_cli/__init__.py +34 -0
- keboola_agent_cli/__main__.py +5 -0
- keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js +2 -0
- keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/architecture-7EHR7CIX-hNCijx_H.js +1 -0
- keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js +37 -0
- keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js +2 -0
- keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js +133 -0
- keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js +11 -0
- keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js +2 -0
- keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js +63 -0
- keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js +3 -0
- keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js +207 -0
- keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js +232 -0
- keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js +124 -0
- keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js +16 -0
- keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js +160 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js +71 -0
- keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js +2 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js +2 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js +2 -0
- keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js +322 -0
- keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js +5 -0
- keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js +2 -0
- keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js +2 -0
- keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js +44 -0
- keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js +11 -0
- keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js +4 -0
- keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js +25 -0
- keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js +25 -0
- keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js +2 -0
- keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js +86 -0
- keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/eventmodeling-FCH6USID-BrJMIks8.js +1 -0
- keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js +163 -0
- keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js +293 -0
- keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/gitGraph-WXDBUCRP-COacYjo-.js +1 -0
- keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js +107 -0
- keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js +2 -0
- keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/index-CMq50kkV.css +1 -0
- keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js +118 -0
- keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/info-J43DQDTF-DdCTRIzU.js +1 -0
- keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js +3 -0
- keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js +2 -0
- keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js +71 -0
- keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js +140 -0
- keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js +90 -0
- keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js +258 -0
- keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js +2 -0
- keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js +2 -0
- keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js +5 -0
- keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js +97 -0
- keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js +2 -0
- keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/packet-YPE3B663-DLiiw_B2.js +1 -0
- keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js +2 -0
- keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/pie-LRSECV5Y-CRoO8G1g.js +1 -0
- keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js +31 -0
- keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js +8 -0
- keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/radar-GUYGQ44K-DAlLVJHm.js +1 -0
- keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js +85 -0
- keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js +2 -0
- keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js +41 -0
- keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js +163 -0
- keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js +2 -0
- keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js +2 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js +2 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js +121 -0
- keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/treeView-BLDUP644-DbLYl23-.js +1 -0
- keboola_agent_cli/_ui_dist/assets/treemap-LRROVOQU-Bp0eGlOt.js +1 -0
- keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js +35 -0
- keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/wardley-L42UT6IY-D4yH4jqS.js +1 -0
- keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js +79 -0
- keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js +8 -0
- keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js.map +1 -0
- keboola_agent_cli/_ui_dist/index.html +50 -0
- keboola_agent_cli/ai_client.py +83 -0
- keboola_agent_cli/auto_update.py +550 -0
- keboola_agent_cli/changelog.py +1198 -0
- keboola_agent_cli/cli.py +448 -0
- keboola_agent_cli/client.py +3422 -0
- keboola_agent_cli/commands/__init__.py +0 -0
- keboola_agent_cli/commands/_data_app_git.py +343 -0
- keboola_agent_cli/commands/_helpers.py +377 -0
- keboola_agent_cli/commands/_metadata_input.py +49 -0
- keboola_agent_cli/commands/_semantic_layer_crud.py +632 -0
- keboola_agent_cli/commands/_semantic_layer_helpers.py +44 -0
- keboola_agent_cli/commands/_semantic_layer_reference_data.py +247 -0
- keboola_agent_cli/commands/agent.py +968 -0
- keboola_agent_cli/commands/branch.py +423 -0
- keboola_agent_cli/commands/changelog.py +168 -0
- keboola_agent_cli/commands/component.py +216 -0
- keboola_agent_cli/commands/config.py +2442 -0
- keboola_agent_cli/commands/context.py +1481 -0
- keboola_agent_cli/commands/data_app.py +1279 -0
- keboola_agent_cli/commands/dev_portal.py +584 -0
- keboola_agent_cli/commands/doctor.py +37 -0
- keboola_agent_cli/commands/encrypt.py +145 -0
- keboola_agent_cli/commands/feature.py +311 -0
- keboola_agent_cli/commands/flow.py +948 -0
- keboola_agent_cli/commands/http_client.py +157 -0
- keboola_agent_cli/commands/init.py +279 -0
- keboola_agent_cli/commands/job.py +661 -0
- keboola_agent_cli/commands/kai.py +301 -0
- keboola_agent_cli/commands/lineage.py +1464 -0
- keboola_agent_cli/commands/org.py +292 -0
- keboola_agent_cli/commands/permissions.py +360 -0
- keboola_agent_cli/commands/project.py +1192 -0
- keboola_agent_cli/commands/repl.py +243 -0
- keboola_agent_cli/commands/schedule.py +340 -0
- keboola_agent_cli/commands/search.py +178 -0
- keboola_agent_cli/commands/semantic_layer.py +939 -0
- keboola_agent_cli/commands/serve.py +272 -0
- keboola_agent_cli/commands/sharing.py +340 -0
- keboola_agent_cli/commands/storage.py +2630 -0
- keboola_agent_cli/commands/stream.py +266 -0
- keboola_agent_cli/commands/sync.py +1277 -0
- keboola_agent_cli/commands/tool.py +206 -0
- keboola_agent_cli/commands/version.py +186 -0
- keboola_agent_cli/commands/workspace.py +635 -0
- keboola_agent_cli/config_store.py +582 -0
- keboola_agent_cli/constants.py +528 -0
- keboola_agent_cli/data_science_client.py +342 -0
- keboola_agent_cli/dev_portal_client.py +323 -0
- keboola_agent_cli/errors.py +248 -0
- keboola_agent_cli/http_base.py +315 -0
- keboola_agent_cli/json_utils.py +126 -0
- keboola_agent_cli/lib.py +536 -0
- keboola_agent_cli/manage_client.py +324 -0
- keboola_agent_cli/metastore_client.py +214 -0
- keboola_agent_cli/models.py +427 -0
- keboola_agent_cli/output.py +1084 -0
- keboola_agent_cli/permissions.py +469 -0
- keboola_agent_cli/py.typed +3 -0
- keboola_agent_cli/result_models.py +271 -0
- keboola_agent_cli/server/__init__.py +34 -0
- keboola_agent_cli/server/agent_runner.py +1289 -0
- keboola_agent_cli/server/agents_store.py +325 -0
- keboola_agent_cli/server/app.py +764 -0
- keboola_agent_cli/server/auth.py +117 -0
- keboola_agent_cli/server/dependencies.py +149 -0
- keboola_agent_cli/server/pricing.py +303 -0
- keboola_agent_cli/server/routers/__init__.py +1 -0
- keboola_agent_cli/server/routers/agents.py +616 -0
- keboola_agent_cli/server/routers/ai_chat.py +129 -0
- keboola_agent_cli/server/routers/branches.py +133 -0
- keboola_agent_cli/server/routers/components.py +48 -0
- keboola_agent_cli/server/routers/configs.py +507 -0
- keboola_agent_cli/server/routers/data_apps.py +384 -0
- keboola_agent_cli/server/routers/dev_portal.py +67 -0
- keboola_agent_cli/server/routers/encrypt.py +35 -0
- keboola_agent_cli/server/routers/feature.py +179 -0
- keboola_agent_cli/server/routers/flows.py +204 -0
- keboola_agent_cli/server/routers/health.py +53 -0
- keboola_agent_cli/server/routers/jobs.py +175 -0
- keboola_agent_cli/server/routers/kai.py +80 -0
- keboola_agent_cli/server/routers/lineage.py +226 -0
- keboola_agent_cli/server/routers/mcp.py +70 -0
- keboola_agent_cli/server/routers/members.py +170 -0
- keboola_agent_cli/server/routers/org.py +96 -0
- keboola_agent_cli/server/routers/projects.py +106 -0
- keboola_agent_cli/server/routers/schedules.py +54 -0
- keboola_agent_cli/server/routers/search.py +30 -0
- keboola_agent_cli/server/routers/semantic_layer.py +650 -0
- keboola_agent_cli/server/routers/sharing.py +86 -0
- keboola_agent_cli/server/routers/storage.py +574 -0
- keboola_agent_cli/server/routers/stream.py +100 -0
- keboola_agent_cli/server/routers/workspaces.py +302 -0
- keboola_agent_cli/server/run_broadcaster.py +329 -0
- keboola_agent_cli/server/sse.py +25 -0
- keboola_agent_cli/services/__init__.py +0 -0
- keboola_agent_cli/services/_encryption.py +217 -0
- keboola_agent_cli/services/_semantic_layer_cascade.py +147 -0
- keboola_agent_cli/services/_semantic_layer_crud.py +382 -0
- keboola_agent_cli/services/_semantic_layer_internals.py +1078 -0
- keboola_agent_cli/services/_semantic_layer_lookup.py +181 -0
- keboola_agent_cli/services/_semantic_layer_reference_data.py +217 -0
- keboola_agent_cli/services/_sync_bindings.py +456 -0
- keboola_agent_cli/services/_sync_branch.py +191 -0
- keboola_agent_cli/services/_sync_bulk.py +228 -0
- keboola_agent_cli/services/_sync_clone.py +163 -0
- keboola_agent_cli/services/_sync_models.py +97 -0
- keboola_agent_cli/services/_sync_push_ops.py +369 -0
- keboola_agent_cli/services/_sync_storage.py +376 -0
- keboola_agent_cli/services/_sync_writeback.py +167 -0
- keboola_agent_cli/services/agent_service.py +458 -0
- keboola_agent_cli/services/base.py +175 -0
- keboola_agent_cli/services/branch_service.py +588 -0
- keboola_agent_cli/services/component_service.py +694 -0
- keboola_agent_cli/services/config_service.py +2099 -0
- keboola_agent_cli/services/data_app_git_service.py +224 -0
- keboola_agent_cli/services/data_app_service.py +2082 -0
- keboola_agent_cli/services/deep_lineage_service.py +1322 -0
- keboola_agent_cli/services/dev_portal_service.py +345 -0
- keboola_agent_cli/services/doctor_service.py +445 -0
- keboola_agent_cli/services/encrypt_service.py +87 -0
- keboola_agent_cli/services/feature_service.py +268 -0
- keboola_agent_cli/services/flow_service.py +769 -0
- keboola_agent_cli/services/flow_validation.py +188 -0
- keboola_agent_cli/services/http_forwarder_service.py +236 -0
- keboola_agent_cli/services/job_idempotency_store.py +285 -0
- keboola_agent_cli/services/job_service.py +797 -0
- keboola_agent_cli/services/kai_service.py +367 -0
- keboola_agent_cli/services/lineage_service.py +274 -0
- keboola_agent_cli/services/mcp_service.py +1498 -0
- keboola_agent_cli/services/mcp_transport.py +259 -0
- keboola_agent_cli/services/member_service.py +593 -0
- keboola_agent_cli/services/org_service.py +619 -0
- keboola_agent_cli/services/project_service.py +947 -0
- keboola_agent_cli/services/repo_validate_service.py +767 -0
- keboola_agent_cli/services/schedule_service.py +731 -0
- keboola_agent_cli/services/search_service.py +331 -0
- keboola_agent_cli/services/semantic_layer_service.py +1497 -0
- keboola_agent_cli/services/sharing_service.py +307 -0
- keboola_agent_cli/services/storage_service.py +2524 -0
- keboola_agent_cli/services/stream_service.py +395 -0
- keboola_agent_cli/services/sync_service.py +2244 -0
- keboola_agent_cli/services/variables_service.py +447 -0
- keboola_agent_cli/services/version_service.py +1038 -0
- keboola_agent_cli/services/workspace_service.py +1103 -0
- keboola_agent_cli/stream_client.py +217 -0
- keboola_agent_cli/sync/__init__.py +1 -0
- keboola_agent_cli/sync/branch_mapping.py +174 -0
- keboola_agent_cli/sync/clone.py +211 -0
- keboola_agent_cli/sync/code_extraction.py +655 -0
- keboola_agent_cli/sync/config_format.py +290 -0
- keboola_agent_cli/sync/diff_engine.py +566 -0
- keboola_agent_cli/sync/git_utils.py +93 -0
- keboola_agent_cli/sync/manifest.py +162 -0
- keboola_agent_cli/sync/naming.py +90 -0
- keboola_agent_cli/sync/secrets.py +62 -0
- keboola_agent_cli/sync/sql_split.py +134 -0
- keboola_cli-0.63.4.dist-info/METADATA +308 -0
- keboola_cli-0.63.4.dist-info/RECORD +306 -0
- keboola_cli-0.63.4.dist-info/WHEEL +4 -0
- keboola_cli-0.63.4.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
"""Branch service - business logic for branch lifecycle management.
|
|
2
|
+
|
|
3
|
+
Orchestrates multi-project branch retrieval in parallel, annotates with
|
|
4
|
+
project alias, and aggregates results. Provides create, activate, reset,
|
|
5
|
+
delete, and merge URL generation for development branches. Also provides
|
|
6
|
+
branch metadata CRUD and a "project description" convenience wrapper over
|
|
7
|
+
the ``KBC.projectDescription`` metadata key on the default branch.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from ..constants import METADATA_NOT_FOUND
|
|
13
|
+
from ..errors import ConfigError, ErrorCode, KeboolaApiError
|
|
14
|
+
from ..models import ProjectConfig
|
|
15
|
+
from .base import BaseService
|
|
16
|
+
|
|
17
|
+
PROJECT_DESCRIPTION_KEY = "KBC.projectDescription"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BranchService(BaseService):
|
|
21
|
+
"""Business logic for managing Keboola development branches.
|
|
22
|
+
|
|
23
|
+
Supports multi-project aggregation: queries multiple projects in parallel
|
|
24
|
+
using ThreadPoolExecutor, collects results, and reports per-project errors
|
|
25
|
+
without stopping others.
|
|
26
|
+
|
|
27
|
+
Provides branch lifecycle operations: create, activate (use), reset,
|
|
28
|
+
delete, and merge URL generation.
|
|
29
|
+
|
|
30
|
+
Uses dependency injection for config_store and client_factory.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def _fetch_project_branches(
|
|
34
|
+
self,
|
|
35
|
+
alias: str,
|
|
36
|
+
project: ProjectConfig,
|
|
37
|
+
) -> tuple[str, list[dict[str, Any]], bool] | tuple[str, dict[str, str]]:
|
|
38
|
+
"""Fetch development branches for a single project (runs in a worker thread).
|
|
39
|
+
|
|
40
|
+
Returns either (alias, branches_list, True) on success
|
|
41
|
+
or (alias, error_dict) on failure.
|
|
42
|
+
"""
|
|
43
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
44
|
+
try:
|
|
45
|
+
raw_branches = client.list_dev_branches()
|
|
46
|
+
branches: list[dict[str, Any]] = []
|
|
47
|
+
for branch in raw_branches:
|
|
48
|
+
branches.append(
|
|
49
|
+
{
|
|
50
|
+
"project_alias": alias,
|
|
51
|
+
"id": branch.get("id"),
|
|
52
|
+
"name": branch.get("name", ""),
|
|
53
|
+
"isDefault": branch.get("isDefault", False),
|
|
54
|
+
"created": branch.get("created", ""),
|
|
55
|
+
"description": branch.get("description", ""),
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
return (alias, branches, True)
|
|
59
|
+
except KeboolaApiError as exc:
|
|
60
|
+
return (
|
|
61
|
+
alias,
|
|
62
|
+
{
|
|
63
|
+
"project_alias": alias,
|
|
64
|
+
"error_code": exc.error_code,
|
|
65
|
+
"message": exc.message,
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
except Exception as exc:
|
|
69
|
+
return (
|
|
70
|
+
alias,
|
|
71
|
+
{
|
|
72
|
+
"project_alias": alias,
|
|
73
|
+
"error_code": "UNEXPECTED_ERROR",
|
|
74
|
+
"message": str(exc),
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
finally:
|
|
78
|
+
client.close()
|
|
79
|
+
|
|
80
|
+
def list_branches(
|
|
81
|
+
self,
|
|
82
|
+
aliases: list[str] | None = None,
|
|
83
|
+
) -> dict[str, Any]:
|
|
84
|
+
"""List development branches across one or multiple projects.
|
|
85
|
+
|
|
86
|
+
Queries each resolved project for development branches in parallel,
|
|
87
|
+
flattens them into a unified list. Per-project errors are collected
|
|
88
|
+
but do not stop other projects from being queried.
|
|
89
|
+
|
|
90
|
+
Includes active_branches dict mapping alias -> active_branch_id for
|
|
91
|
+
display purposes.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
aliases: Project aliases to query. None means all projects.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Dict with keys:
|
|
98
|
+
- "branches": list of branch dicts with project_alias,
|
|
99
|
+
id, name, isDefault, created, description
|
|
100
|
+
- "errors": list of error dicts with project_alias,
|
|
101
|
+
error_code, message
|
|
102
|
+
- "active_branches": dict mapping alias -> active_branch_id
|
|
103
|
+
|
|
104
|
+
Raises:
|
|
105
|
+
ConfigError: If a specified alias is not found (before querying).
|
|
106
|
+
"""
|
|
107
|
+
projects = self.resolve_projects(aliases)
|
|
108
|
+
|
|
109
|
+
# Collect active branch IDs for display
|
|
110
|
+
active_branches: dict[str, int | None] = {}
|
|
111
|
+
for alias, project in projects.items():
|
|
112
|
+
active_branches[alias] = project.active_branch_id
|
|
113
|
+
|
|
114
|
+
def worker(alias: str, project: ProjectConfig) -> tuple[Any, ...]:
|
|
115
|
+
return self._fetch_project_branches(alias, project)
|
|
116
|
+
|
|
117
|
+
successes, errors = self._run_parallel(projects, worker)
|
|
118
|
+
|
|
119
|
+
# Flatten branches from all successful projects
|
|
120
|
+
all_branches: list[dict[str, Any]] = []
|
|
121
|
+
for _alias, branches, _ok in successes:
|
|
122
|
+
all_branches.extend(branches)
|
|
123
|
+
|
|
124
|
+
# Sort for deterministic output
|
|
125
|
+
all_branches.sort(key=lambda b: (b["project_alias"], b.get("id", 0)))
|
|
126
|
+
errors.sort(key=lambda e: e.get("project_alias", ""))
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
"branches": all_branches,
|
|
130
|
+
"errors": errors,
|
|
131
|
+
"active_branches": active_branches,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
def create_branch(
|
|
135
|
+
self,
|
|
136
|
+
alias: str,
|
|
137
|
+
name: str,
|
|
138
|
+
description: str = "",
|
|
139
|
+
) -> dict[str, Any]:
|
|
140
|
+
"""Create a new development branch and auto-activate it.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
alias: Project alias.
|
|
144
|
+
name: Branch name.
|
|
145
|
+
description: Optional branch description.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Dict with branch details and activation info.
|
|
149
|
+
|
|
150
|
+
Raises:
|
|
151
|
+
ConfigError: If the project alias is not found.
|
|
152
|
+
KeboolaApiError: If the API call fails.
|
|
153
|
+
"""
|
|
154
|
+
projects = self.resolve_projects([alias])
|
|
155
|
+
project = projects[alias]
|
|
156
|
+
|
|
157
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
158
|
+
try:
|
|
159
|
+
# create_dev_branch waits for the async job and returns branch data
|
|
160
|
+
# from job.results (contains the real branch ID)
|
|
161
|
+
branch_data = client.create_dev_branch(name=name, description=description)
|
|
162
|
+
finally:
|
|
163
|
+
client.close()
|
|
164
|
+
|
|
165
|
+
branch_id = int(branch_data["id"])
|
|
166
|
+
|
|
167
|
+
# Auto-activate the created branch
|
|
168
|
+
self._config_store.set_project_branch(alias, branch_id)
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
"project_alias": alias,
|
|
172
|
+
"branch_id": branch_id,
|
|
173
|
+
"branch_name": branch_data.get("name", name),
|
|
174
|
+
"description": branch_data.get("description", description),
|
|
175
|
+
"created": branch_data.get("created", ""),
|
|
176
|
+
"activated": True,
|
|
177
|
+
"message": (
|
|
178
|
+
f"Branch '{name}' (ID: {branch_id}) created and activated for project '{alias}'."
|
|
179
|
+
),
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
def set_active_branch(self, alias: str, branch_id: int) -> dict[str, Any]:
|
|
183
|
+
"""Validate and set an existing branch as active.
|
|
184
|
+
|
|
185
|
+
Calls the API to verify the branch exists before setting it.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
alias: Project alias.
|
|
189
|
+
branch_id: Branch ID to activate.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
Dict with activation details.
|
|
193
|
+
|
|
194
|
+
Raises:
|
|
195
|
+
ConfigError: If the project alias is not found or branch does not exist.
|
|
196
|
+
KeboolaApiError: If the API call fails.
|
|
197
|
+
"""
|
|
198
|
+
projects = self.resolve_projects([alias])
|
|
199
|
+
project = projects[alias]
|
|
200
|
+
|
|
201
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
202
|
+
try:
|
|
203
|
+
raw_branches = client.list_dev_branches()
|
|
204
|
+
finally:
|
|
205
|
+
client.close()
|
|
206
|
+
|
|
207
|
+
# Find the branch by ID
|
|
208
|
+
target_branch = None
|
|
209
|
+
for branch in raw_branches:
|
|
210
|
+
if branch.get("id") == branch_id:
|
|
211
|
+
target_branch = branch
|
|
212
|
+
break
|
|
213
|
+
|
|
214
|
+
if target_branch is None:
|
|
215
|
+
raise ConfigError(
|
|
216
|
+
f"Branch ID {branch_id} not found in project '{alias}'. "
|
|
217
|
+
f"Use 'kbagent branch list --project {alias}' to see available branches."
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
self._config_store.set_project_branch(alias, branch_id)
|
|
221
|
+
|
|
222
|
+
branch_name = target_branch.get("name", "")
|
|
223
|
+
return {
|
|
224
|
+
"project_alias": alias,
|
|
225
|
+
"branch_id": branch_id,
|
|
226
|
+
"branch_name": branch_name,
|
|
227
|
+
"message": (
|
|
228
|
+
f"Active branch set to '{branch_name}' (ID: {branch_id}) for project '{alias}'."
|
|
229
|
+
),
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
def reset_branch(self, alias: str) -> dict[str, Any]:
|
|
233
|
+
"""Clear the active branch, reverting to the main/production branch.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
alias: Project alias.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
Dict confirming the reset.
|
|
240
|
+
|
|
241
|
+
Raises:
|
|
242
|
+
ConfigError: If the project alias is not found.
|
|
243
|
+
"""
|
|
244
|
+
projects = self.resolve_projects([alias])
|
|
245
|
+
previous_branch = projects[alias].active_branch_id
|
|
246
|
+
|
|
247
|
+
self._config_store.set_project_branch(alias, None)
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
"project_alias": alias,
|
|
251
|
+
"previous_branch_id": previous_branch,
|
|
252
|
+
"message": (f"Active branch reset to main for project '{alias}'."),
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
def delete_branch(self, alias: str, branch_id: int) -> dict[str, Any]:
|
|
256
|
+
"""Delete a development branch via API. Auto-resets if it was active.
|
|
257
|
+
|
|
258
|
+
Also cleans up any matching entry in the nearest enclosing sync
|
|
259
|
+
workspace's ``branch-mapping.json`` (issue #267, Bug D), so the
|
|
260
|
+
user is not left with a stale mapping pointing at a deleted
|
|
261
|
+
branch.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
alias: Project alias.
|
|
265
|
+
branch_id: Branch ID to delete.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Dict confirming the deletion.
|
|
269
|
+
|
|
270
|
+
Raises:
|
|
271
|
+
ConfigError: If the project alias is not found.
|
|
272
|
+
KeboolaApiError: If the API call fails.
|
|
273
|
+
"""
|
|
274
|
+
from ..sync.branch_mapping import cleanup_branch_id_from_mapping
|
|
275
|
+
|
|
276
|
+
projects = self.resolve_projects([alias])
|
|
277
|
+
project = projects[alias]
|
|
278
|
+
|
|
279
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
280
|
+
try:
|
|
281
|
+
client.delete_dev_branch(branch_id)
|
|
282
|
+
finally:
|
|
283
|
+
client.close()
|
|
284
|
+
|
|
285
|
+
# Auto-reset if the deleted branch was active
|
|
286
|
+
was_active = project.active_branch_id == branch_id
|
|
287
|
+
if was_active:
|
|
288
|
+
self._config_store.set_project_branch(alias, None)
|
|
289
|
+
|
|
290
|
+
cleanup = cleanup_branch_id_from_mapping(branch_id)
|
|
291
|
+
|
|
292
|
+
message_parts = [f"Branch ID {branch_id} deleted from project '{alias}'."]
|
|
293
|
+
if was_active:
|
|
294
|
+
message_parts.append("Active branch reset to main.")
|
|
295
|
+
if cleanup:
|
|
296
|
+
unlinked = ", ".join(cleanup["git_branches_unlinked"])
|
|
297
|
+
message_parts.append(f"Unlinked git branch(es): {unlinked}.")
|
|
298
|
+
|
|
299
|
+
result: dict[str, Any] = {
|
|
300
|
+
"project_alias": alias,
|
|
301
|
+
"branch_id": branch_id,
|
|
302
|
+
"was_active": was_active,
|
|
303
|
+
"message": " ".join(message_parts),
|
|
304
|
+
}
|
|
305
|
+
if cleanup:
|
|
306
|
+
result["mapping_cleanup"] = cleanup
|
|
307
|
+
return result
|
|
308
|
+
|
|
309
|
+
def get_merge_url(self, alias: str, branch_id: int | None = None) -> dict[str, Any]:
|
|
310
|
+
"""Generate KBC UI merge URL for a development branch.
|
|
311
|
+
|
|
312
|
+
Does not call any API. Constructs the URL from stored project config.
|
|
313
|
+
If no branch_id is provided, uses the active branch from config.
|
|
314
|
+
After generating the URL, resets the active branch to main.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
alias: Project alias.
|
|
318
|
+
branch_id: Branch ID. If None, uses active_branch_id from config.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Dict with merge URL and instructions.
|
|
322
|
+
|
|
323
|
+
Raises:
|
|
324
|
+
ConfigError: If project not found or no branch ID available.
|
|
325
|
+
"""
|
|
326
|
+
projects = self.resolve_projects([alias])
|
|
327
|
+
project = projects[alias]
|
|
328
|
+
|
|
329
|
+
effective_branch_id = branch_id if branch_id is not None else project.active_branch_id
|
|
330
|
+
if effective_branch_id is None:
|
|
331
|
+
raise ConfigError(
|
|
332
|
+
f"No branch specified and no active branch set for project '{alias}'. "
|
|
333
|
+
f"Use --branch ID or set an active branch with 'kbagent branch use'."
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
if project.project_id is None:
|
|
337
|
+
raise ConfigError(
|
|
338
|
+
f"Project '{alias}' has no project_id stored. "
|
|
339
|
+
"Re-add the project with 'kbagent project edit' to populate it."
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
stack_url = project.stack_url.rstrip("/")
|
|
343
|
+
merge_url = (
|
|
344
|
+
f"{stack_url}/admin/projects/{project.project_id}"
|
|
345
|
+
f"/branch/{effective_branch_id}/development-overview"
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
# Reset active branch to main after generating merge URL
|
|
349
|
+
self._config_store.set_project_branch(alias, None)
|
|
350
|
+
|
|
351
|
+
# Best-effort cleanup of any matching sync-workspace mapping so the
|
|
352
|
+
# user is not left referencing a soon-to-be-merged branch (Bug D).
|
|
353
|
+
from ..sync.branch_mapping import cleanup_branch_id_from_mapping
|
|
354
|
+
|
|
355
|
+
cleanup = cleanup_branch_id_from_mapping(effective_branch_id)
|
|
356
|
+
|
|
357
|
+
result: dict[str, Any] = {
|
|
358
|
+
"project_alias": alias,
|
|
359
|
+
"branch_id": effective_branch_id,
|
|
360
|
+
"url": merge_url,
|
|
361
|
+
"message": (
|
|
362
|
+
f"Open this URL to review and merge branch {effective_branch_id} "
|
|
363
|
+
f"in project '{alias}'. Active branch has been reset to main."
|
|
364
|
+
),
|
|
365
|
+
}
|
|
366
|
+
if cleanup:
|
|
367
|
+
unlinked = ", ".join(cleanup["git_branches_unlinked"])
|
|
368
|
+
result["message"] += f" Unlinked git branch(es): {unlinked}."
|
|
369
|
+
result["mapping_cleanup"] = cleanup
|
|
370
|
+
return result
|
|
371
|
+
|
|
372
|
+
# ── Branch metadata ────────────────────────────────────────────────
|
|
373
|
+
|
|
374
|
+
def list_branch_metadata(
|
|
375
|
+
self,
|
|
376
|
+
alias: str,
|
|
377
|
+
branch_id: int | str = "default",
|
|
378
|
+
) -> dict[str, Any]:
|
|
379
|
+
"""List all metadata entries on a branch for a single project.
|
|
380
|
+
|
|
381
|
+
Args:
|
|
382
|
+
alias: Project alias.
|
|
383
|
+
branch_id: Branch ID or "default" for the main branch.
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
Dict with project_alias, branch_id, and a key-sorted metadata list.
|
|
387
|
+
|
|
388
|
+
Raises:
|
|
389
|
+
ConfigError: If the project alias is not found.
|
|
390
|
+
KeboolaApiError: If the API call fails.
|
|
391
|
+
"""
|
|
392
|
+
projects = self.resolve_projects([alias])
|
|
393
|
+
project = projects[alias]
|
|
394
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
395
|
+
try:
|
|
396
|
+
entries = client.list_branch_metadata(branch_id=branch_id)
|
|
397
|
+
finally:
|
|
398
|
+
client.close()
|
|
399
|
+
return {
|
|
400
|
+
"project_alias": alias,
|
|
401
|
+
"branch_id": branch_id,
|
|
402
|
+
"metadata": sorted(entries, key=lambda e: e.get("key", "")),
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
def get_branch_metadata(
|
|
406
|
+
self,
|
|
407
|
+
alias: str,
|
|
408
|
+
key: str,
|
|
409
|
+
branch_id: int | str = "default",
|
|
410
|
+
) -> dict[str, Any]:
|
|
411
|
+
"""Get a single metadata value by key.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
alias: Project alias.
|
|
415
|
+
key: Metadata key (e.g. "KBC.projectDescription").
|
|
416
|
+
branch_id: Branch ID or "default" for the main branch.
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
Dict with project_alias, branch_id, key, value.
|
|
420
|
+
|
|
421
|
+
Raises:
|
|
422
|
+
ConfigError: If the project alias is not found.
|
|
423
|
+
KeboolaApiError: If the key is not present or the API call fails.
|
|
424
|
+
"""
|
|
425
|
+
projects = self.resolve_projects([alias])
|
|
426
|
+
project = projects[alias]
|
|
427
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
428
|
+
try:
|
|
429
|
+
value = client.get_branch_metadata_value(key=key, branch_id=branch_id)
|
|
430
|
+
finally:
|
|
431
|
+
client.close()
|
|
432
|
+
if value is METADATA_NOT_FOUND:
|
|
433
|
+
raise KeboolaApiError(
|
|
434
|
+
message=(
|
|
435
|
+
f"Metadata key '{key}' not found on branch '{branch_id}' of project '{alias}'."
|
|
436
|
+
),
|
|
437
|
+
status_code=404,
|
|
438
|
+
error_code=ErrorCode.NOT_FOUND,
|
|
439
|
+
retryable=False,
|
|
440
|
+
)
|
|
441
|
+
return {
|
|
442
|
+
"project_alias": alias,
|
|
443
|
+
"branch_id": branch_id,
|
|
444
|
+
"key": key,
|
|
445
|
+
"value": value,
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
def set_branch_metadata(
|
|
449
|
+
self,
|
|
450
|
+
alias: str,
|
|
451
|
+
key: str,
|
|
452
|
+
value: str,
|
|
453
|
+
branch_id: int | str = "default",
|
|
454
|
+
) -> dict[str, Any]:
|
|
455
|
+
"""Set a single metadata key/value on a branch.
|
|
456
|
+
|
|
457
|
+
Args:
|
|
458
|
+
alias: Project alias.
|
|
459
|
+
key: Metadata key to set.
|
|
460
|
+
value: Metadata value (plain string; e.g. markdown).
|
|
461
|
+
branch_id: Branch ID or "default" for the main branch.
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
Dict with project_alias, branch_id, key, value, result, message.
|
|
465
|
+
|
|
466
|
+
Raises:
|
|
467
|
+
ConfigError: If the project alias is not found.
|
|
468
|
+
KeboolaApiError: If the API call fails.
|
|
469
|
+
"""
|
|
470
|
+
projects = self.resolve_projects([alias])
|
|
471
|
+
project = projects[alias]
|
|
472
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
473
|
+
try:
|
|
474
|
+
result = client.set_branch_metadata(entries=[(key, value)], branch_id=branch_id)
|
|
475
|
+
finally:
|
|
476
|
+
client.close()
|
|
477
|
+
return {
|
|
478
|
+
"project_alias": alias,
|
|
479
|
+
"branch_id": branch_id,
|
|
480
|
+
"key": key,
|
|
481
|
+
"value": value,
|
|
482
|
+
"result": result,
|
|
483
|
+
"message": (f"Metadata '{key}' set on branch '{branch_id}' of project '{alias}'."),
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
def delete_branch_metadata(
|
|
487
|
+
self,
|
|
488
|
+
alias: str,
|
|
489
|
+
metadata_id: int | str,
|
|
490
|
+
branch_id: int | str = "default",
|
|
491
|
+
) -> dict[str, Any]:
|
|
492
|
+
"""Delete a metadata entry by its numeric ID.
|
|
493
|
+
|
|
494
|
+
Args:
|
|
495
|
+
alias: Project alias.
|
|
496
|
+
metadata_id: Metadata entry ID (from ``list_branch_metadata``).
|
|
497
|
+
branch_id: Branch ID or "default" for the main branch.
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
Dict confirming the deletion.
|
|
501
|
+
|
|
502
|
+
Raises:
|
|
503
|
+
ConfigError: If the project alias is not found.
|
|
504
|
+
KeboolaApiError: If the API call fails.
|
|
505
|
+
"""
|
|
506
|
+
projects = self.resolve_projects([alias])
|
|
507
|
+
project = projects[alias]
|
|
508
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
509
|
+
try:
|
|
510
|
+
client.delete_branch_metadata(metadata_id=metadata_id, branch_id=branch_id)
|
|
511
|
+
finally:
|
|
512
|
+
client.close()
|
|
513
|
+
return {
|
|
514
|
+
"project_alias": alias,
|
|
515
|
+
"branch_id": branch_id,
|
|
516
|
+
"metadata_id": metadata_id,
|
|
517
|
+
"message": (
|
|
518
|
+
f"Metadata ID {metadata_id} deleted from branch '{branch_id}' of project '{alias}'."
|
|
519
|
+
),
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
# ── Project description (convenience wrappers) ─────────────────────
|
|
523
|
+
|
|
524
|
+
def get_project_description(self, alias: str) -> dict[str, Any]:
|
|
525
|
+
"""Get the dashboard project description for a project.
|
|
526
|
+
|
|
527
|
+
Reads the ``KBC.projectDescription`` metadata value from the default
|
|
528
|
+
branch -- this is what the Keboola UI displays on the project
|
|
529
|
+
dashboard.
|
|
530
|
+
|
|
531
|
+
Returns an empty description (not an error) if the key is unset, so
|
|
532
|
+
callers don't need to special-case freshly-provisioned projects.
|
|
533
|
+
|
|
534
|
+
Args:
|
|
535
|
+
alias: Project alias.
|
|
536
|
+
|
|
537
|
+
Returns:
|
|
538
|
+
Dict with project_alias, key, description (str, possibly empty).
|
|
539
|
+
|
|
540
|
+
Raises:
|
|
541
|
+
ConfigError: If the project alias is not found.
|
|
542
|
+
KeboolaApiError: If the API call fails.
|
|
543
|
+
"""
|
|
544
|
+
projects = self.resolve_projects([alias])
|
|
545
|
+
project = projects[alias]
|
|
546
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
547
|
+
try:
|
|
548
|
+
value = client.get_branch_metadata_value(
|
|
549
|
+
key=PROJECT_DESCRIPTION_KEY, branch_id="default"
|
|
550
|
+
)
|
|
551
|
+
finally:
|
|
552
|
+
client.close()
|
|
553
|
+
return {
|
|
554
|
+
"project_alias": alias,
|
|
555
|
+
"key": PROJECT_DESCRIPTION_KEY,
|
|
556
|
+
"description": "" if value is METADATA_NOT_FOUND else (value or ""),
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
def set_project_description(self, alias: str, description: str) -> dict[str, Any]:
|
|
560
|
+
"""Set the dashboard project description for a project.
|
|
561
|
+
|
|
562
|
+
Writes to ``KBC.projectDescription`` on the default branch, which is
|
|
563
|
+
what the Keboola UI reads for the project dashboard description.
|
|
564
|
+
|
|
565
|
+
Args:
|
|
566
|
+
alias: Project alias.
|
|
567
|
+
description: Markdown content for the description.
|
|
568
|
+
|
|
569
|
+
Returns:
|
|
570
|
+
Dict with project_alias, key, description, result, message.
|
|
571
|
+
|
|
572
|
+
Raises:
|
|
573
|
+
ConfigError: If the project alias is not found.
|
|
574
|
+
KeboolaApiError: If the API call fails.
|
|
575
|
+
"""
|
|
576
|
+
raw = self.set_branch_metadata(
|
|
577
|
+
alias=alias,
|
|
578
|
+
key=PROJECT_DESCRIPTION_KEY,
|
|
579
|
+
value=description,
|
|
580
|
+
branch_id="default",
|
|
581
|
+
)
|
|
582
|
+
return {
|
|
583
|
+
"project_alias": alias,
|
|
584
|
+
"key": PROJECT_DESCRIPTION_KEY,
|
|
585
|
+
"description": description,
|
|
586
|
+
"result": raw["result"],
|
|
587
|
+
"message": f"Project description updated for '{alias}' ({len(description)} chars).",
|
|
588
|
+
}
|