recce-nightly 1.2.0.20250506__py3-none-any.whl → 1.26.0.20251124__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.

Potentially problematic release.


This version of recce-nightly might be problematic. Click here for more details.

Files changed (213) hide show
  1. recce/VERSION +1 -1
  2. recce/__init__.py +27 -22
  3. recce/adapter/base.py +11 -14
  4. recce/adapter/dbt_adapter/__init__.py +810 -480
  5. recce/adapter/dbt_adapter/dbt_version.py +3 -0
  6. recce/adapter/sqlmesh_adapter.py +24 -35
  7. recce/apis/check_api.py +39 -28
  8. recce/apis/check_func.py +33 -27
  9. recce/apis/run_api.py +25 -19
  10. recce/apis/run_func.py +29 -23
  11. recce/artifact.py +119 -51
  12. recce/cli.py +1299 -323
  13. recce/config.py +42 -33
  14. recce/connect_to_cloud.py +138 -0
  15. recce/core.py +55 -47
  16. recce/data/404.html +1 -1
  17. recce/data/__next.__PAGE__.txt +10 -0
  18. recce/data/__next._full.txt +23 -0
  19. recce/data/__next._head.txt +8 -0
  20. recce/data/__next._index.txt +8 -0
  21. recce/data/__next._tree.txt +5 -0
  22. recce/data/_next/static/52aV_JrNUZU6dMFgvTQEO/_buildManifest.js +11 -0
  23. recce/data/_next/static/52aV_JrNUZU6dMFgvTQEO/_clientMiddlewareManifest.json +1 -0
  24. recce/data/_next/static/chunks/02b996c7f6a29a06.js +4 -0
  25. recce/data/_next/static/chunks/19c10d219a6a21ff.js +1 -0
  26. recce/data/_next/static/chunks/2df9ec28a061971d.js +11 -0
  27. recce/data/_next/static/chunks/3098c987393bda15.js +1 -0
  28. recce/data/_next/static/chunks/393dc43e483f717a.css +2 -0
  29. recce/data/_next/static/chunks/399e8d91a7e45073.js +2 -0
  30. recce/data/_next/static/chunks/4d0186f631230245.js +1 -0
  31. recce/data/_next/static/chunks/5794ba9e10a9c060.js +11 -0
  32. recce/data/_next/static/chunks/715761c929a3f28b.js +110 -0
  33. recce/data/_next/static/chunks/71f88fcc615bf282.js +1 -0
  34. recce/data/_next/static/chunks/80d2a95eaf1201ea.js +1 -0
  35. recce/data/_next/static/chunks/9979c6109bbbee35.js +1 -0
  36. recce/data/_next/static/chunks/99d638224186c118.js +1 -0
  37. recce/data/_next/static/chunks/d003eb36240e92f3.js +1 -0
  38. recce/data/_next/static/chunks/d3167cdfec4fc351.js +1 -0
  39. recce/data/_next/static/chunks/e124bccf574a3361.css +1 -0
  40. recce/data/_next/static/chunks/f40141db1bdb46f0.css +6 -0
  41. recce/data/_next/static/chunks/fcc53a88741a52f9.js +1 -0
  42. recce/data/_next/static/chunks/turbopack-b1920d28cfb1f28d.js +3 -0
  43. recce/data/_next/static/media/favicon.a8d38d84.ico +0 -0
  44. recce/data/_next/static/media/montserrat-cyrillic-800-normal.d80d830d.woff2 +0 -0
  45. recce/data/_next/static/media/montserrat-cyrillic-800-normal.f9d58125.woff +0 -0
  46. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.076c2a93.woff2 +0 -0
  47. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.a4fa76b5.woff +0 -0
  48. recce/data/_next/static/media/montserrat-latin-800-normal.cde454cc.woff2 +0 -0
  49. recce/data/_next/static/media/montserrat-latin-800-normal.d5761935.woff +0 -0
  50. recce/data/_next/static/media/montserrat-latin-ext-800-normal.40ec0659.woff2 +0 -0
  51. recce/data/_next/static/media/montserrat-latin-ext-800-normal.b671449b.woff +0 -0
  52. recce/data/_next/static/media/montserrat-vietnamese-800-normal.9f7b8541.woff +0 -0
  53. recce/data/_next/static/media/montserrat-vietnamese-800-normal.f9eb854e.woff2 +0 -0
  54. recce/data/_next/static/media/reload-image.7aa931c7.svg +4 -0
  55. recce/data/_not-found/__next._full.txt +17 -0
  56. recce/data/_not-found/__next._head.txt +8 -0
  57. recce/data/_not-found/__next._index.txt +8 -0
  58. recce/data/_not-found/__next._not-found.__PAGE__.txt +5 -0
  59. recce/data/_not-found/__next._not-found.txt +4 -0
  60. recce/data/_not-found/__next._tree.txt +3 -0
  61. recce/data/_not-found.html +1 -0
  62. recce/data/_not-found.txt +17 -0
  63. recce/data/auth_callback.html +68 -0
  64. recce/data/imgs/reload-image.svg +4 -0
  65. recce/data/index.html +1 -27
  66. recce/data/index.txt +23 -7
  67. recce/diff.py +6 -12
  68. recce/event/__init__.py +86 -74
  69. recce/event/collector.py +33 -22
  70. recce/event/track.py +49 -27
  71. recce/exceptions.py +1 -1
  72. recce/git.py +7 -7
  73. recce/github.py +57 -53
  74. recce/mcp_server.py +716 -0
  75. recce/models/__init__.py +4 -1
  76. recce/models/check.py +6 -7
  77. recce/models/run.py +1 -0
  78. recce/models/types.py +131 -28
  79. recce/pull_request.py +27 -25
  80. recce/run.py +165 -121
  81. recce/server.py +303 -111
  82. recce/state/__init__.py +31 -0
  83. recce/state/cloud.py +632 -0
  84. recce/state/const.py +26 -0
  85. recce/state/local.py +56 -0
  86. recce/state/state.py +119 -0
  87. recce/state/state_loader.py +174 -0
  88. recce/summary.py +188 -143
  89. recce/tasks/__init__.py +19 -3
  90. recce/tasks/core.py +11 -13
  91. recce/tasks/dataframe.py +82 -18
  92. recce/tasks/histogram.py +69 -34
  93. recce/tasks/lineage.py +2 -2
  94. recce/tasks/profile.py +152 -86
  95. recce/tasks/query.py +139 -87
  96. recce/tasks/rowcount.py +37 -31
  97. recce/tasks/schema.py +18 -15
  98. recce/tasks/top_k.py +35 -35
  99. recce/tasks/valuediff.py +216 -152
  100. recce/util/__init__.py +3 -0
  101. recce/util/api_token.py +80 -0
  102. recce/util/breaking.py +87 -85
  103. recce/util/cll.py +274 -219
  104. recce/util/io.py +22 -17
  105. recce/util/lineage.py +65 -16
  106. recce/util/logger.py +1 -1
  107. recce/util/onboarding_state.py +45 -0
  108. recce/util/perf_tracking.py +85 -0
  109. recce/util/recce_cloud.py +322 -72
  110. recce/util/singleton.py +4 -4
  111. recce/yaml/__init__.py +7 -10
  112. recce_cloud/__init__.py +24 -0
  113. recce_cloud/api/__init__.py +17 -0
  114. recce_cloud/api/base.py +111 -0
  115. recce_cloud/api/client.py +150 -0
  116. recce_cloud/api/exceptions.py +26 -0
  117. recce_cloud/api/factory.py +63 -0
  118. recce_cloud/api/github.py +76 -0
  119. recce_cloud/api/gitlab.py +82 -0
  120. recce_cloud/artifact.py +57 -0
  121. recce_cloud/ci_providers/__init__.py +9 -0
  122. recce_cloud/ci_providers/base.py +82 -0
  123. recce_cloud/ci_providers/detector.py +147 -0
  124. recce_cloud/ci_providers/github_actions.py +136 -0
  125. recce_cloud/ci_providers/gitlab_ci.py +130 -0
  126. recce_cloud/cli.py +245 -0
  127. recce_cloud/upload.py +214 -0
  128. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/METADATA +68 -37
  129. recce_nightly-1.26.0.20251124.dist-info/RECORD +180 -0
  130. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/WHEEL +1 -1
  131. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/top_level.txt +1 -0
  132. tests/adapter/dbt_adapter/conftest.py +9 -5
  133. tests/adapter/dbt_adapter/dbt_test_helper.py +37 -22
  134. tests/adapter/dbt_adapter/test_dbt_adapter.py +0 -15
  135. tests/adapter/dbt_adapter/test_dbt_cll.py +656 -41
  136. tests/adapter/dbt_adapter/test_selector.py +22 -21
  137. tests/recce_cloud/__init__.py +0 -0
  138. tests/recce_cloud/test_ci_providers.py +351 -0
  139. tests/recce_cloud/test_cli.py +372 -0
  140. tests/recce_cloud/test_client.py +273 -0
  141. tests/recce_cloud/test_platform_clients.py +333 -0
  142. tests/tasks/conftest.py +1 -1
  143. tests/tasks/test_histogram.py +58 -66
  144. tests/tasks/test_lineage.py +36 -23
  145. tests/tasks/test_preset_checks.py +45 -31
  146. tests/tasks/test_profile.py +339 -15
  147. tests/tasks/test_query.py +46 -46
  148. tests/tasks/test_row_count.py +65 -46
  149. tests/tasks/test_schema.py +65 -42
  150. tests/tasks/test_top_k.py +22 -18
  151. tests/tasks/test_valuediff.py +43 -32
  152. tests/test_cli.py +174 -60
  153. tests/test_cli_mcp_optional.py +45 -0
  154. tests/test_cloud_listing_cli.py +324 -0
  155. tests/test_config.py +7 -9
  156. tests/test_connect_to_cloud.py +82 -0
  157. tests/test_core.py +151 -4
  158. tests/test_dbt.py +7 -7
  159. tests/test_mcp_server.py +332 -0
  160. tests/test_pull_request.py +1 -1
  161. tests/test_server.py +25 -19
  162. tests/test_summary.py +29 -17
  163. recce/data/_next/static/Kcbs3GEIyH2LxgLYat0es/_buildManifest.js +0 -1
  164. recce/data/_next/static/chunks/1f229bf6-d9fe92e56db8d93b.js +0 -1
  165. recce/data/_next/static/chunks/29e3cc0d-8c150e37dff9631b.js +0 -1
  166. recce/data/_next/static/chunks/368-7587b306577df275.js +0 -65
  167. recce/data/_next/static/chunks/36e1c10d-bb0210cbd6573a8d.js +0 -1
  168. recce/data/_next/static/chunks/3998a672-eaad84bdd88cc73e.js +0 -1
  169. recce/data/_next/static/chunks/3a92ee20-3b5d922d4157af5e.js +0 -1
  170. recce/data/_next/static/chunks/450c323b-1bb5db526e54435a.js +0 -1
  171. recce/data/_next/static/chunks/47d8844f-79a1b53c66a7d7ec.js +0 -1
  172. recce/data/_next/static/chunks/6dc81886-c94b9b91bc2c3caf.js +0 -1
  173. recce/data/_next/static/chunks/6ef81909-694dc38134099299.js +0 -1
  174. recce/data/_next/static/chunks/700-3b65fc3666820d00.js +0 -2
  175. recce/data/_next/static/chunks/7a8a3e83-d7fa409d97b38b2b.js +0 -1
  176. recce/data/_next/static/chunks/7f27ae6c-413f6b869a04183a.js +0 -1
  177. recce/data/_next/static/chunks/8d700b6a-f0b1f6b9e0d97ce2.js +0 -1
  178. recce/data/_next/static/chunks/9746af58-d74bef4d03eea6ab.js +0 -1
  179. recce/data/_next/static/chunks/a30376cd-7d806e1602f2dc3a.js +0 -1
  180. recce/data/_next/static/chunks/app/_not-found/page-8a886fa0855c3105.js +0 -1
  181. recce/data/_next/static/chunks/app/layout-9102e22cb73f74d6.js +0 -1
  182. recce/data/_next/static/chunks/app/page-cee661090afbd6aa.js +0 -1
  183. recce/data/_next/static/chunks/b63b1b3f-7395c74e11a14e95.js +0 -1
  184. recce/data/_next/static/chunks/c132bf7d-8102037f9ccf372a.js +0 -1
  185. recce/data/_next/static/chunks/c1ceaa8b-a1e442154d23515e.js +0 -1
  186. recce/data/_next/static/chunks/cd9f8d63-cf0d5a7b0f7a92e8.js +0 -54
  187. recce/data/_next/static/chunks/ce84277d-f42c2c58049cea2d.js +0 -1
  188. recce/data/_next/static/chunks/e24bf851-0f8cbc99656833e7.js +0 -1
  189. recce/data/_next/static/chunks/fee69bc6-f17d36c080742e74.js +0 -1
  190. recce/data/_next/static/chunks/framework-ded83d71b51ce901.js +0 -1
  191. recce/data/_next/static/chunks/main-a0859f1f36d0aa6c.js +0 -1
  192. recce/data/_next/static/chunks/main-app-0225a2255968e566.js +0 -1
  193. recce/data/_next/static/chunks/pages/_app-d5672bf3d8b6371b.js +0 -1
  194. recce/data/_next/static/chunks/pages/_error-ed75be3f25588548.js +0 -1
  195. recce/data/_next/static/chunks/webpack-567d72f0bc0820d5.js +0 -1
  196. recce/data/_next/static/css/c9ecb46a4b21c126.css +0 -14
  197. recce/data/_next/static/media/montserrat-cyrillic-800-normal.22628180.woff2 +0 -0
  198. recce/data/_next/static/media/montserrat-cyrillic-800-normal.31d693bb.woff +0 -0
  199. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.7e2c1e62.woff +0 -0
  200. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.94a63aea.woff2 +0 -0
  201. recce/data/_next/static/media/montserrat-latin-800-normal.6f8fa298.woff2 +0 -0
  202. recce/data/_next/static/media/montserrat-latin-800-normal.97e20d5e.woff +0 -0
  203. recce/data/_next/static/media/montserrat-latin-ext-800-normal.013b84f9.woff2 +0 -0
  204. recce/data/_next/static/media/montserrat-latin-ext-800-normal.aff52ab0.woff +0 -0
  205. recce/data/_next/static/media/montserrat-vietnamese-800-normal.5f21869b.woff +0 -0
  206. recce/data/_next/static/media/montserrat-vietnamese-800-normal.c0035377.woff2 +0 -0
  207. recce/state.py +0 -753
  208. recce_nightly-1.2.0.20250506.dist-info/RECORD +0 -142
  209. tests/test_state.py +0 -123
  210. /recce/data/_next/static/{Kcbs3GEIyH2LxgLYat0es → 52aV_JrNUZU6dMFgvTQEO}/_ssgManifest.js +0 -0
  211. /recce/data/_next/static/chunks/{polyfills-42372ed130431b0a.js → a6dad97d9634a72d.js} +0 -0
  212. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/entry_points.txt +0 -0
  213. {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/licenses/LICENSE +0 -0
recce/artifact.py CHANGED
@@ -9,9 +9,9 @@ from urllib.parse import urlencode
9
9
  import requests
10
10
  from rich.console import Console
11
11
 
12
- from recce.git import hosting_repo, commit_hash_from_branch, current_branch
12
+ from recce.git import commit_hash_from_branch, current_branch, hosting_repo
13
13
  from recce.state import s3_sse_c_headers
14
- from recce.util.recce_cloud import RecceCloud, PresignedUrlMethod
14
+ from recce.util.recce_cloud import PresignedUrlMethod, RecceCloud
15
15
 
16
16
 
17
17
  def verify_artifacts_path(target_path: str) -> bool:
@@ -30,10 +30,7 @@ def verify_artifacts_path(target_path: str) -> bool:
30
30
  if not os.path.isdir(target_path):
31
31
  return False
32
32
 
33
- required_artifacts_files = [
34
- 'manifest.json',
35
- 'catalog.json'
36
- ]
33
+ required_artifacts_files = ["manifest.json", "catalog.json"]
37
34
 
38
35
  if all(f in os.listdir(target_path) for f in required_artifacts_files):
39
36
  # Check if the required files are present in the target path
@@ -43,35 +40,35 @@ def verify_artifacts_path(target_path: str) -> bool:
43
40
 
44
41
 
45
42
  def parse_dbt_version(file_path: str) -> str:
46
- with open(file_path, 'r') as f:
43
+ with open(file_path, "r", encoding="utf-8") as f:
47
44
  data = json.load(f)
48
45
 
49
- dbt_version = data.get('metadata', {}).get('dbt_version', None)
46
+ dbt_version = data.get("metadata", {}).get("dbt_version", None)
50
47
  return dbt_version
51
48
 
52
49
 
53
50
  def archive_artifacts(target_path: str) -> (str, str):
54
51
  if verify_artifacts_path(target_path) is False:
55
- raise Exception(f'Invalid target path: {target_path}')
52
+ raise Exception(f"Invalid target path: {target_path}")
56
53
 
57
- manifest_path = os.path.join(target_path, 'manifest.json')
58
- catalog_path = os.path.join(target_path, 'catalog.json')
54
+ manifest_path = os.path.join(target_path, "manifest.json")
55
+ catalog_path = os.path.join(target_path, "catalog.json")
59
56
 
60
57
  dbt_version = parse_dbt_version(manifest_path)
61
58
  if dbt_version is None:
62
- raise Exception('Failed to parse dbt version from manifest.json')
59
+ raise Exception("Failed to parse dbt version from manifest.json")
63
60
 
64
61
  # prepare the temporary artifacts path
65
62
  tmp_dir = tempfile.mkdtemp()
66
- artifacts_tar_path = os.path.join(tmp_dir, 'dbt_artifacts.tar')
67
- artifacts_tar_gz_path = artifacts_tar_path + '.gz'
63
+ artifacts_tar_path = os.path.join(tmp_dir, "dbt_artifacts.tar")
64
+ artifacts_tar_gz_path = artifacts_tar_path + ".gz"
68
65
 
69
- with tarfile.open(artifacts_tar_path, 'w') as tar:
70
- tar.add(manifest_path, arcname='manifest.json')
71
- tar.add(catalog_path, arcname='catalog.json')
66
+ with tarfile.open(artifacts_tar_path, "w") as tar:
67
+ tar.add(manifest_path, arcname="manifest.json")
68
+ tar.add(catalog_path, arcname="catalog.json")
72
69
 
73
70
  # Compress the tar file
74
- with open(artifacts_tar_path, 'rb') as f_in, gzip.open(artifacts_tar_gz_path, 'wb') as f_out:
71
+ with open(artifacts_tar_path, "rb") as f_in, gzip.open(artifacts_tar_gz_path, "wb") as f_out:
75
72
  f_out.writelines(f_in)
76
73
 
77
74
  # Clean up the temporary directory
@@ -83,6 +80,64 @@ def archive_artifacts(target_path: str) -> (str, str):
83
80
  return artifacts_tar_gz_path, dbt_version
84
81
 
85
82
 
83
+ def upload_artifacts_to_session(target_path: str, session_id: str, token: str, debug: bool = False):
84
+ """Upload dbt artifacts to a specific session ID in Recce Cloud."""
85
+ console = Console()
86
+ if verify_artifacts_path(target_path) is False:
87
+ console.print(f"[[red]Error[/red]] Invalid target path: {target_path}")
88
+ console.print("Please provide a valid target path containing manifest.json and catalog.json.")
89
+ return 1
90
+
91
+ manifest_path = os.path.join(target_path, "manifest.json")
92
+ catalog_path = os.path.join(target_path, "catalog.json")
93
+
94
+ # get the adapter type from the manifest file
95
+ with open(manifest_path, "r", encoding="utf-8") as f:
96
+ manifest_data = json.load(f)
97
+ adapter_type = manifest_data.get("metadata", {}).get("adapter_type")
98
+ if adapter_type is None:
99
+ raise Exception("Failed to parse adapter type from manifest.json")
100
+
101
+ recce_cloud = RecceCloud(token)
102
+
103
+ session = recce_cloud.get_session(session_id)
104
+
105
+ org_id = session.get("org_id")
106
+ if org_id is None:
107
+ raise Exception(f"Session ID {session_id} does not belong to any organization.")
108
+
109
+ project_id = session.get("project_id")
110
+ if project_id is None:
111
+ raise Exception(f"Session ID {session_id} does not belong to any project.")
112
+
113
+ # Get the presigned URL for uploading the artifacts using session ID
114
+ console.print(f'Uploading artifacts for session ID "{session_id}"')
115
+ presigned_urls = recce_cloud.get_upload_urls_by_session_id(org_id, project_id, session_id)
116
+ if debug:
117
+ console.rule("Debug information", style="blue")
118
+ console.print(f"Org ID: {org_id}")
119
+ console.print(f"Project ID: {project_id}")
120
+ console.print(f"Session ID: {session_id}")
121
+ console.print(f"Manifest path: {presigned_urls['manifest_url']}")
122
+ console.print(f"Catalog path: {presigned_urls['catalog_url']}")
123
+ console.print(f"Adapter type: {adapter_type}")
124
+
125
+ # Upload the compressed artifacts (no password needed for session uploads)
126
+ console.print(f'Uploading manifest from path "{manifest_path}"')
127
+ response = requests.put(presigned_urls["manifest_url"], data=open(manifest_path, "rb").read())
128
+ if response.status_code != 200 and response.status_code != 204:
129
+ raise Exception(response.text)
130
+ console.print(f'Uploading catalog from path "{catalog_path}"')
131
+ response = requests.put(presigned_urls["catalog_url"], data=open(catalog_path, "rb").read())
132
+ if response.status_code != 200 and response.status_code != 204:
133
+ raise Exception(response.text)
134
+
135
+ # Update the session metadata
136
+ recce_cloud.update_session(org_id, project_id, session_id, adapter_type)
137
+
138
+ return 0
139
+
140
+
86
141
  def upload_dbt_artifacts(target_path: str, branch: str, token: str, password: str, debug: bool = False):
87
142
  console = Console()
88
143
  if verify_artifacts_path(target_path) is False:
@@ -100,36 +155,33 @@ def upload_dbt_artifacts(target_path: str, branch: str, token: str, password: st
100
155
  compress_file_path, dbt_version = archive_artifacts(target_path)
101
156
  repo = hosting_repo()
102
157
  sha = commit_hash_from_branch(branch)
103
- metadata = {
104
- 'commit': sha,
105
- 'dbt_version': dbt_version
106
- }
158
+ metadata = {"commit": sha, "dbt_version": dbt_version}
107
159
 
108
160
  # Get the presigned URL for uploading the artifacts
109
- presigned_url = RecceCloud(token).get_presigned_url(
161
+ presigned_url = RecceCloud(token).get_presigned_url_by_github_repo(
110
162
  method=PresignedUrlMethod.UPLOAD,
111
163
  repository=repo,
112
- artifact_name='dbt_artifacts.tar.gz',
164
+ artifact_name="dbt_artifacts.tar.gz",
113
165
  branch=branch,
114
- metadata=metadata
166
+ metadata=metadata,
115
167
  )
116
168
 
117
169
  if debug:
118
- console.rule('Debug information', style='blue')
119
- console.print(f'Branch: {branch}')
120
- console.print(f'Commit hash: {sha}')
121
- console.print(f'GitHub repository: {repo}')
122
- console.print(f'Artifact path: {compress_file_path}')
123
- console.print(f'DBT version: {dbt_version}')
124
- console.print(f'Presigned URL: {presigned_url}')
170
+ console.rule("Debug information", style="blue")
171
+ console.print(f"Branch: {branch}")
172
+ console.print(f"Commit hash: {sha}")
173
+ console.print(f"GitHub repository: {repo}")
174
+ console.print(f"Artifact path: {compress_file_path}")
175
+ console.print(f"DBT version: {dbt_version}")
176
+ console.print(f"Presigned URL: {presigned_url}")
125
177
  console.print(f'Uploading the dbt artifacts from path "{target_path}" to branch "{branch}"')
126
178
 
127
179
  # Upload the compressed artifacts
128
180
 
129
181
  headers = s3_sse_c_headers(password)
130
182
  if metadata:
131
- headers['x-amz-tagging'] = urlencode(metadata)
132
- response = requests.put(presigned_url, data=open(compress_file_path, 'rb').read(), headers=headers)
183
+ headers["x-amz-tagging"] = urlencode(metadata)
184
+ response = requests.put(presigned_url, data=open(compress_file_path, "rb").read(), headers=headers)
133
185
  if response.status_code != 200:
134
186
  raise Exception({response.text})
135
187
 
@@ -143,29 +195,29 @@ def upload_dbt_artifacts(target_path: str, branch: str, token: str, password: st
143
195
  pass
144
196
 
145
197
 
146
- def download_dbt_artifacts(target_path: str, branch: str, token: str, password: str,
147
- force: bool = False,
148
- debug: bool = False):
198
+ def download_dbt_artifacts(
199
+ target_path: str, branch: str, token: str, password: str, force: bool = False, debug: bool = False
200
+ ):
149
201
  console = Console()
150
202
  repo = hosting_repo()
151
203
  sha = None
152
204
  dbt_version = None
153
205
 
154
- presigned_url, tags = RecceCloud(token).get_download_presigned_url_with_tags(
206
+ presigned_url, tags = RecceCloud(token).get_download_presigned_url_by_github_repo_with_tags(
155
207
  repository=repo,
156
- artifact_name='dbt_artifacts.tar.gz',
208
+ artifact_name="dbt_artifacts.tar.gz",
157
209
  branch=branch,
158
210
  )
159
211
  if tags:
160
- sha = tags.get('commit')
161
- dbt_version = tags.get('dbt_version')
212
+ sha = tags.get("commit")
213
+ dbt_version = tags.get("dbt_version")
162
214
 
163
215
  if debug:
164
- console.rule('Debug information', style='blue')
165
- console.print(f'Git Branch: {branch}')
166
- console.print(f'Git Commit: {sha}')
167
- console.print(f'GitHub repository: {repo}')
168
- console.print(f'DBT version: {dbt_version}')
216
+ console.rule("Debug information", style="blue")
217
+ console.print(f"Git Branch: {branch}")
218
+ console.print(f"Git Commit: {sha}")
219
+ console.print(f"GitHub repository: {repo}")
220
+ console.print(f"DBT version: {dbt_version}")
169
221
  console.print(f'Downloading from branch: "{branch}" and extracting to "{target_path}"')
170
222
 
171
223
  headers = s3_sse_c_headers(password)
@@ -177,16 +229,17 @@ def download_dbt_artifacts(target_path: str, branch: str, token: str, password:
177
229
  if os.path.exists(target_path):
178
230
  if not force:
179
231
  raise Exception(
180
- f'Path {target_path} already exists. Please provide a new path or use \'--force\' option to overwrite the existing folder.')
181
- console.print(f'[[yellow]Warning[/yellow]] Overwrite existing path: {target_path}')
232
+ f"Path {target_path} already exists. Please provide a new path or use '--force' option to overwrite the existing folder."
233
+ )
234
+ console.print(f"[[yellow]Warning[/yellow]] Overwrite existing path: {target_path}")
182
235
  shutil.rmtree(target_path)
183
236
  os.mkdir(target_path)
184
237
 
185
- tar_gz_file = os.path.join(target_path, 'dbt_artifacts.tar.gz')
186
- with open(tar_gz_file, 'wb') as f:
238
+ tar_gz_file = os.path.join(target_path, "dbt_artifacts.tar.gz")
239
+ with open(tar_gz_file, "wb") as f:
187
240
  f.write(response.content)
188
241
 
189
- with tarfile.open(tar_gz_file, 'r') as tar:
242
+ with tarfile.open(tar_gz_file, "r") as tar:
190
243
  tar.extractall(path=target_path)
191
244
 
192
245
  # Clean up the compressed artifacts
@@ -196,3 +249,18 @@ def download_dbt_artifacts(target_path: str, branch: str, token: str, password:
196
249
  except FileNotFoundError:
197
250
  pass
198
251
  return 0
252
+
253
+
254
+ def delete_dbt_artifacts(branch: str, token: str, debug: bool = False):
255
+ """Delete dbt artifacts from a specific branch in Recce Cloud."""
256
+ console = Console()
257
+ repo = hosting_repo()
258
+
259
+ if debug:
260
+ console.rule("Debug information", style="blue")
261
+ console.print(f"Git Branch: {branch}")
262
+ console.print(f"GitHub repository: {repo}")
263
+
264
+ console.print(f'Deleting dbt artifacts from branch: "{branch}"')
265
+
266
+ RecceCloud(token).purge_artifacts(repo, branch=branch)