recce-nightly 1.15.0.20250806__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 (167) hide show
  1. recce/VERSION +1 -1
  2. recce/__init__.py +5 -0
  3. recce/adapter/dbt_adapter/__init__.py +12 -3
  4. recce/artifact.py +74 -1
  5. recce/cli.py +642 -101
  6. recce/config.py +2 -2
  7. recce/connect_to_cloud.py +1 -1
  8. recce/core.py +2 -2
  9. recce/data/404.html +1 -1
  10. recce/data/__next.__PAGE__.txt +10 -0
  11. recce/data/__next._full.txt +23 -0
  12. recce/data/__next._head.txt +8 -0
  13. recce/data/__next._index.txt +8 -0
  14. recce/data/__next._tree.txt +5 -0
  15. recce/data/_next/static/52aV_JrNUZU6dMFgvTQEO/_buildManifest.js +11 -0
  16. recce/data/_next/static/52aV_JrNUZU6dMFgvTQEO/_clientMiddlewareManifest.json +1 -0
  17. recce/data/_next/static/chunks/02b996c7f6a29a06.js +4 -0
  18. recce/data/_next/static/chunks/19c10d219a6a21ff.js +1 -0
  19. recce/data/_next/static/chunks/2df9ec28a061971d.js +11 -0
  20. recce/data/_next/static/chunks/3098c987393bda15.js +1 -0
  21. recce/data/_next/static/chunks/393dc43e483f717a.css +2 -0
  22. recce/data/_next/static/chunks/399e8d91a7e45073.js +2 -0
  23. recce/data/_next/static/chunks/4d0186f631230245.js +1 -0
  24. recce/data/_next/static/chunks/5794ba9e10a9c060.js +11 -0
  25. recce/data/_next/static/chunks/715761c929a3f28b.js +110 -0
  26. recce/data/_next/static/chunks/71f88fcc615bf282.js +1 -0
  27. recce/data/_next/static/chunks/80d2a95eaf1201ea.js +1 -0
  28. recce/data/_next/static/chunks/9979c6109bbbee35.js +1 -0
  29. recce/data/_next/static/chunks/99d638224186c118.js +1 -0
  30. recce/data/_next/static/chunks/d003eb36240e92f3.js +1 -0
  31. recce/data/_next/static/chunks/d3167cdfec4fc351.js +1 -0
  32. recce/data/_next/static/chunks/e124bccf574a3361.css +1 -0
  33. recce/data/_next/static/chunks/f40141db1bdb46f0.css +6 -0
  34. recce/data/_next/static/chunks/fcc53a88741a52f9.js +1 -0
  35. recce/data/_next/static/chunks/turbopack-b1920d28cfb1f28d.js +3 -0
  36. recce/data/_next/static/media/favicon.a8d38d84.ico +0 -0
  37. recce/data/_next/static/media/montserrat-cyrillic-800-normal.d80d830d.woff2 +0 -0
  38. recce/data/_next/static/media/{montserrat-cyrillic-800-normal.bd5c9f50.woff → montserrat-cyrillic-800-normal.f9d58125.woff} +0 -0
  39. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.076c2a93.woff2 +0 -0
  40. recce/data/_next/static/media/montserrat-latin-800-normal.cde454cc.woff2 +0 -0
  41. recce/data/_next/static/media/{montserrat-latin-800-normal.fc315020.woff → montserrat-latin-800-normal.d5761935.woff} +0 -0
  42. recce/data/_next/static/media/montserrat-latin-ext-800-normal.40ec0659.woff2 +0 -0
  43. recce/data/_next/static/media/{montserrat-latin-ext-800-normal.2e5381b2.woff → montserrat-latin-ext-800-normal.b671449b.woff} +0 -0
  44. recce/data/_next/static/media/{montserrat-vietnamese-800-normal.20c545e6.woff → montserrat-vietnamese-800-normal.9f7b8541.woff} +0 -0
  45. recce/data/_next/static/media/montserrat-vietnamese-800-normal.f9eb854e.woff2 +0 -0
  46. recce/data/_not-found/__next._full.txt +17 -0
  47. recce/data/_not-found/__next._head.txt +8 -0
  48. recce/data/_not-found/__next._index.txt +8 -0
  49. recce/data/_not-found/__next._not-found.__PAGE__.txt +5 -0
  50. recce/data/_not-found/__next._not-found.txt +4 -0
  51. recce/data/_not-found/__next._tree.txt +3 -0
  52. recce/data/_not-found.html +1 -0
  53. recce/data/_not-found.txt +17 -0
  54. recce/data/index.html +1 -1
  55. recce/data/index.txt +21 -23
  56. recce/event/__init__.py +9 -8
  57. recce/event/collector.py +3 -1
  58. recce/event/track.py +10 -0
  59. recce/github.py +1 -1
  60. recce/mcp_server.py +716 -0
  61. recce/models/types.py +35 -2
  62. recce/pull_request.py +1 -1
  63. recce/run.py +2 -2
  64. recce/server.py +105 -3
  65. recce/state/__init__.py +31 -0
  66. recce/state/cloud.py +632 -0
  67. recce/state/const.py +26 -0
  68. recce/state/local.py +56 -0
  69. recce/state/state.py +119 -0
  70. recce/state/state_loader.py +174 -0
  71. recce/summary.py +21 -1
  72. recce/tasks/dataframe.py +63 -1
  73. recce/tasks/rowcount.py +4 -1
  74. recce/tasks/schema.py +4 -1
  75. recce/util/api_token.py +9 -2
  76. recce/util/breaking.py +1 -1
  77. recce/util/io.py +2 -2
  78. recce/util/lineage.py +14 -18
  79. recce/util/recce_cloud.py +187 -7
  80. recce/yaml/__init__.py +2 -2
  81. recce_cloud/__init__.py +24 -0
  82. recce_cloud/api/__init__.py +17 -0
  83. recce_cloud/api/base.py +111 -0
  84. recce_cloud/api/client.py +150 -0
  85. recce_cloud/api/exceptions.py +26 -0
  86. recce_cloud/api/factory.py +63 -0
  87. recce_cloud/api/github.py +76 -0
  88. recce_cloud/api/gitlab.py +82 -0
  89. recce_cloud/artifact.py +57 -0
  90. recce_cloud/ci_providers/__init__.py +9 -0
  91. recce_cloud/ci_providers/base.py +82 -0
  92. recce_cloud/ci_providers/detector.py +147 -0
  93. recce_cloud/ci_providers/github_actions.py +136 -0
  94. recce_cloud/ci_providers/gitlab_ci.py +130 -0
  95. recce_cloud/cli.py +245 -0
  96. recce_cloud/upload.py +214 -0
  97. {recce_nightly-1.15.0.20250806.dist-info → recce_nightly-1.26.0.20251124.dist-info}/METADATA +54 -28
  98. recce_nightly-1.26.0.20251124.dist-info/RECORD +180 -0
  99. {recce_nightly-1.15.0.20250806.dist-info → recce_nightly-1.26.0.20251124.dist-info}/top_level.txt +1 -0
  100. tests/adapter/dbt_adapter/test_dbt_cll.py +4 -2
  101. tests/recce_cloud/__init__.py +0 -0
  102. tests/recce_cloud/test_ci_providers.py +351 -0
  103. tests/recce_cloud/test_cli.py +372 -0
  104. tests/recce_cloud/test_client.py +273 -0
  105. tests/recce_cloud/test_platform_clients.py +333 -0
  106. tests/test_cli.py +106 -3
  107. tests/test_cli_mcp_optional.py +45 -0
  108. tests/test_cloud_listing_cli.py +324 -0
  109. tests/test_core.py +147 -0
  110. tests/test_mcp_server.py +332 -0
  111. tests/test_server.py +6 -6
  112. tests/test_summary.py +14 -6
  113. recce/data/_next/static/Q_5ThPsmamd4VAGXuqwgi/_buildManifest.js +0 -1
  114. recce/data/_next/static/chunks/0376eeba-3db2196398d62270.js +0 -1
  115. recce/data/_next/static/chunks/068b80ea-833a129468ee1622.js +0 -1
  116. recce/data/_next/static/chunks/0ddaf06c-c7961285f66460f6.js +0 -1
  117. recce/data/_next/static/chunks/1268aea1-6dc1251c01bd724b.js +0 -54
  118. recce/data/_next/static/chunks/12f8fac4-16838e42d28d45c3.js +0 -1
  119. recce/data/_next/static/chunks/235b8375-8c84c51d7bd4f6aa.js +0 -1
  120. recce/data/_next/static/chunks/2541941f-2cd3a7c2d629bd33.js +0 -1
  121. recce/data/_next/static/chunks/273-f3fa401bd2b6fc91.js +0 -10
  122. recce/data/_next/static/chunks/2fc37c1e-910deebeb3d77c90.js +0 -1
  123. recce/data/_next/static/chunks/338-2e7eed5135c64550.js +0 -30
  124. recce/data/_next/static/chunks/367-ab8b16dd5f8586ca.js +0 -1
  125. recce/data/_next/static/chunks/3a92ee20-0400ffe460c7c803.js +0 -1
  126. recce/data/_next/static/chunks/62446465-423c03bb8c1f59b6.js +0 -1
  127. recce/data/_next/static/chunks/6af7f9e9-60aa8706f49dae45.js +0 -1
  128. recce/data/_next/static/chunks/6cf54382-49d52ae6e564e2ac.js +0 -1
  129. recce/data/_next/static/chunks/6dc81886-78e2efe4538794ae.js +0 -1
  130. recce/data/_next/static/chunks/715e4acc-9e2e6df4eb3809d1.js +0 -1
  131. recce/data/_next/static/chunks/72-181b430654230f0e.js +0 -1
  132. recce/data/_next/static/chunks/786-774e3e3ed70a41b3.js +0 -1
  133. recce/data/_next/static/chunks/8d700b6a.7fe2c8c3f4e333a6.js +0 -1
  134. recce/data/_next/static/chunks/a69d64b4-d6890125a87b0aba.js +0 -1
  135. recce/data/_next/static/chunks/ae307f12-01100009689ace61.js +0 -1
  136. recce/data/_next/static/chunks/app/_not-found/page-c7ef8ed6dc07aaeb.js +0 -1
  137. recce/data/_next/static/chunks/app/layout-744f0a78e9e50e60.js +0 -1
  138. recce/data/_next/static/chunks/app/page-e8f798c2ae3f59c2.js +0 -1
  139. recce/data/_next/static/chunks/c0015c5c-82c219792582c104.js +0 -1
  140. recce/data/_next/static/chunks/d90cfbaa-e7d779b3912afeec.js +0 -1
  141. recce/data/_next/static/chunks/e07c302e-cd170429646873e1.js +0 -1
  142. recce/data/_next/static/chunks/fa5fb511-15fb438349ad5b97.js +0 -1
  143. recce/data/_next/static/chunks/framework-7950757d31580329.js +0 -1
  144. recce/data/_next/static/chunks/main-app-4df79eb11c34d43c.js +0 -1
  145. recce/data/_next/static/chunks/main-cd6c104af638214a.js +0 -1
  146. recce/data/_next/static/chunks/pages/_app-73008661edbd5e05.js +0 -1
  147. recce/data/_next/static/chunks/pages/_error-cf8bbdc3cf76c83f.js +0 -1
  148. recce/data/_next/static/chunks/webpack-84df6dd5ae3cf908.js +0 -1
  149. recce/data/_next/static/css/188a3a1687e2a064.css +0 -1
  150. recce/data/_next/static/css/8edca58d4abcf908.css +0 -14
  151. recce/data/_next/static/css/abdb9814a3dd18bb.css +0 -1
  152. recce/data/_next/static/css/c21263c1520b615b.css +0 -1
  153. recce/data/_next/static/media/montserrat-cyrillic-800-normal.22628180.woff2 +0 -0
  154. recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.94a63aea.woff2 +0 -0
  155. recce/data/_next/static/media/montserrat-latin-800-normal.6f8fa298.woff2 +0 -0
  156. recce/data/_next/static/media/montserrat-latin-ext-800-normal.013b84f9.woff2 +0 -0
  157. recce/data/_next/static/media/montserrat-vietnamese-800-normal.c0035377.woff2 +0 -0
  158. recce/state.py +0 -865
  159. recce_nightly-1.15.0.20250806.dist-info/RECORD +0 -156
  160. tests/test_state.py +0 -134
  161. /recce/data/_next/static/{Q_5ThPsmamd4VAGXuqwgi → 52aV_JrNUZU6dMFgvTQEO}/_ssgManifest.js +0 -0
  162. /recce/data/_next/static/chunks/{polyfills-42372ed130431b0a.js → a6dad97d9634a72d.js} +0 -0
  163. /recce/data/_next/static/media/{montserrat-cyrillic-ext-800-normal.e6e0d8d0.woff → montserrat-cyrillic-ext-800-normal.a4fa76b5.woff} +0 -0
  164. /recce/data/_next/static/media/{reload-image.79aabb7d.svg → reload-image.7aa931c7.svg} +0 -0
  165. {recce_nightly-1.15.0.20250806.dist-info → recce_nightly-1.26.0.20251124.dist-info}/WHEEL +0 -0
  166. {recce_nightly-1.15.0.20250806.dist-info → recce_nightly-1.26.0.20251124.dist-info}/entry_points.txt +0 -0
  167. {recce_nightly-1.15.0.20250806.dist-info → recce_nightly-1.26.0.20251124.dist-info}/licenses/LICENSE +0 -0
recce/VERSION CHANGED
@@ -1 +1 @@
1
- 1.15.0.20250806
1
+ 1.26.0.20251124
recce/__init__.py CHANGED
@@ -35,6 +35,11 @@ def is_ci_env():
35
35
  return False
36
36
 
37
37
 
38
+ def is_recce_cloud_instance():
39
+ """Check if running in Recce Cloud instance."""
40
+ return os.environ.get("RECCE_CLOUD_INSTANCE", "false").lower() == "true"
41
+
42
+
38
43
  def get_runner():
39
44
  # GitHub Action
40
45
  if os.environ.get("GITHUB_ACTIONS", "false") == "true":
@@ -408,7 +408,7 @@ class DbtAdapter(BaseAdapter):
408
408
 
409
409
  if self.adapter.connections.TYPE == "databricks":
410
410
  # reference: get_columns_in_relation (dbt/adapters/databricks/impl.py)
411
- from dbt.adapters.databricks import DatabricksColumn
411
+ from dbt.adapters.databricks.column import DatabricksColumn
412
412
 
413
413
  rows = columns
414
414
  columns = []
@@ -600,7 +600,15 @@ class DbtAdapter(BaseAdapter):
600
600
  return node.compiled_code
601
601
  else:
602
602
  from dbt.clients import jinja
603
- from dbt.context.providers import generate_runtime_model_context
603
+ from dbt.context.providers import (
604
+ generate_runtime_macro_context,
605
+ generate_runtime_model_context,
606
+ )
607
+
608
+ # Set up macro resolver for dbt >= 1.8
609
+ macro_manifest = MacroManifest(manifest.macros)
610
+ self.adapter.set_macro_resolver(macro_manifest)
611
+ self.adapter.set_macro_context_generator(generate_runtime_macro_context)
604
612
 
605
613
  jinja_ctx = generate_runtime_model_context(node, self.runtime_config, manifest)
606
614
  jinja_ctx.update(context)
@@ -737,6 +745,7 @@ class DbtAdapter(BaseAdapter):
737
745
  nodes[unique_id] = {
738
746
  "id": source["unique_id"],
739
747
  "name": source["name"],
748
+ "source_name": source["source_name"],
740
749
  "resource_type": source["resource_type"],
741
750
  "package_name": source["package_name"],
742
751
  "config": source["config"],
@@ -1591,7 +1600,7 @@ class DbtAdapter(BaseAdapter):
1591
1600
  if not os.path.isfile(path):
1592
1601
  return None
1593
1602
 
1594
- with open(path, "r") as f:
1603
+ with open(path, "r", encoding="utf-8") as f:
1595
1604
  json_content = f.read()
1596
1605
  return json.loads(json_content)
1597
1606
 
recce/artifact.py CHANGED
@@ -40,7 +40,7 @@ def verify_artifacts_path(target_path: str) -> bool:
40
40
 
41
41
 
42
42
  def parse_dbt_version(file_path: str) -> str:
43
- with open(file_path, "r") as f:
43
+ with open(file_path, "r", encoding="utf-8") as f:
44
44
  data = json.load(f)
45
45
 
46
46
  dbt_version = data.get("metadata", {}).get("dbt_version", None)
@@ -80,6 +80,64 @@ def archive_artifacts(target_path: str) -> (str, str):
80
80
  return artifacts_tar_gz_path, dbt_version
81
81
 
82
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
+
83
141
  def upload_dbt_artifacts(target_path: str, branch: str, token: str, password: str, debug: bool = False):
84
142
  console = Console()
85
143
  if verify_artifacts_path(target_path) is False:
@@ -191,3 +249,18 @@ def download_dbt_artifacts(
191
249
  except FileNotFoundError:
192
250
  pass
193
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)