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.
- recce/VERSION +1 -1
- recce/__init__.py +27 -22
- recce/adapter/base.py +11 -14
- recce/adapter/dbt_adapter/__init__.py +810 -480
- recce/adapter/dbt_adapter/dbt_version.py +3 -0
- recce/adapter/sqlmesh_adapter.py +24 -35
- recce/apis/check_api.py +39 -28
- recce/apis/check_func.py +33 -27
- recce/apis/run_api.py +25 -19
- recce/apis/run_func.py +29 -23
- recce/artifact.py +119 -51
- recce/cli.py +1299 -323
- recce/config.py +42 -33
- recce/connect_to_cloud.py +138 -0
- recce/core.py +55 -47
- recce/data/404.html +1 -1
- recce/data/__next.__PAGE__.txt +10 -0
- recce/data/__next._full.txt +23 -0
- recce/data/__next._head.txt +8 -0
- recce/data/__next._index.txt +8 -0
- recce/data/__next._tree.txt +5 -0
- recce/data/_next/static/52aV_JrNUZU6dMFgvTQEO/_buildManifest.js +11 -0
- recce/data/_next/static/52aV_JrNUZU6dMFgvTQEO/_clientMiddlewareManifest.json +1 -0
- recce/data/_next/static/chunks/02b996c7f6a29a06.js +4 -0
- recce/data/_next/static/chunks/19c10d219a6a21ff.js +1 -0
- recce/data/_next/static/chunks/2df9ec28a061971d.js +11 -0
- recce/data/_next/static/chunks/3098c987393bda15.js +1 -0
- recce/data/_next/static/chunks/393dc43e483f717a.css +2 -0
- recce/data/_next/static/chunks/399e8d91a7e45073.js +2 -0
- recce/data/_next/static/chunks/4d0186f631230245.js +1 -0
- recce/data/_next/static/chunks/5794ba9e10a9c060.js +11 -0
- recce/data/_next/static/chunks/715761c929a3f28b.js +110 -0
- recce/data/_next/static/chunks/71f88fcc615bf282.js +1 -0
- recce/data/_next/static/chunks/80d2a95eaf1201ea.js +1 -0
- recce/data/_next/static/chunks/9979c6109bbbee35.js +1 -0
- recce/data/_next/static/chunks/99d638224186c118.js +1 -0
- recce/data/_next/static/chunks/d003eb36240e92f3.js +1 -0
- recce/data/_next/static/chunks/d3167cdfec4fc351.js +1 -0
- recce/data/_next/static/chunks/e124bccf574a3361.css +1 -0
- recce/data/_next/static/chunks/f40141db1bdb46f0.css +6 -0
- recce/data/_next/static/chunks/fcc53a88741a52f9.js +1 -0
- recce/data/_next/static/chunks/turbopack-b1920d28cfb1f28d.js +3 -0
- recce/data/_next/static/media/favicon.a8d38d84.ico +0 -0
- recce/data/_next/static/media/montserrat-cyrillic-800-normal.d80d830d.woff2 +0 -0
- recce/data/_next/static/media/montserrat-cyrillic-800-normal.f9d58125.woff +0 -0
- recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.076c2a93.woff2 +0 -0
- recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.a4fa76b5.woff +0 -0
- recce/data/_next/static/media/montserrat-latin-800-normal.cde454cc.woff2 +0 -0
- recce/data/_next/static/media/montserrat-latin-800-normal.d5761935.woff +0 -0
- recce/data/_next/static/media/montserrat-latin-ext-800-normal.40ec0659.woff2 +0 -0
- recce/data/_next/static/media/montserrat-latin-ext-800-normal.b671449b.woff +0 -0
- recce/data/_next/static/media/montserrat-vietnamese-800-normal.9f7b8541.woff +0 -0
- recce/data/_next/static/media/montserrat-vietnamese-800-normal.f9eb854e.woff2 +0 -0
- recce/data/_next/static/media/reload-image.7aa931c7.svg +4 -0
- recce/data/_not-found/__next._full.txt +17 -0
- recce/data/_not-found/__next._head.txt +8 -0
- recce/data/_not-found/__next._index.txt +8 -0
- recce/data/_not-found/__next._not-found.__PAGE__.txt +5 -0
- recce/data/_not-found/__next._not-found.txt +4 -0
- recce/data/_not-found/__next._tree.txt +3 -0
- recce/data/_not-found.html +1 -0
- recce/data/_not-found.txt +17 -0
- recce/data/auth_callback.html +68 -0
- recce/data/imgs/reload-image.svg +4 -0
- recce/data/index.html +1 -27
- recce/data/index.txt +23 -7
- recce/diff.py +6 -12
- recce/event/__init__.py +86 -74
- recce/event/collector.py +33 -22
- recce/event/track.py +49 -27
- recce/exceptions.py +1 -1
- recce/git.py +7 -7
- recce/github.py +57 -53
- recce/mcp_server.py +716 -0
- recce/models/__init__.py +4 -1
- recce/models/check.py +6 -7
- recce/models/run.py +1 -0
- recce/models/types.py +131 -28
- recce/pull_request.py +27 -25
- recce/run.py +165 -121
- recce/server.py +303 -111
- recce/state/__init__.py +31 -0
- recce/state/cloud.py +632 -0
- recce/state/const.py +26 -0
- recce/state/local.py +56 -0
- recce/state/state.py +119 -0
- recce/state/state_loader.py +174 -0
- recce/summary.py +188 -143
- recce/tasks/__init__.py +19 -3
- recce/tasks/core.py +11 -13
- recce/tasks/dataframe.py +82 -18
- recce/tasks/histogram.py +69 -34
- recce/tasks/lineage.py +2 -2
- recce/tasks/profile.py +152 -86
- recce/tasks/query.py +139 -87
- recce/tasks/rowcount.py +37 -31
- recce/tasks/schema.py +18 -15
- recce/tasks/top_k.py +35 -35
- recce/tasks/valuediff.py +216 -152
- recce/util/__init__.py +3 -0
- recce/util/api_token.py +80 -0
- recce/util/breaking.py +87 -85
- recce/util/cll.py +274 -219
- recce/util/io.py +22 -17
- recce/util/lineage.py +65 -16
- recce/util/logger.py +1 -1
- recce/util/onboarding_state.py +45 -0
- recce/util/perf_tracking.py +85 -0
- recce/util/recce_cloud.py +322 -72
- recce/util/singleton.py +4 -4
- recce/yaml/__init__.py +7 -10
- recce_cloud/__init__.py +24 -0
- recce_cloud/api/__init__.py +17 -0
- recce_cloud/api/base.py +111 -0
- recce_cloud/api/client.py +150 -0
- recce_cloud/api/exceptions.py +26 -0
- recce_cloud/api/factory.py +63 -0
- recce_cloud/api/github.py +76 -0
- recce_cloud/api/gitlab.py +82 -0
- recce_cloud/artifact.py +57 -0
- recce_cloud/ci_providers/__init__.py +9 -0
- recce_cloud/ci_providers/base.py +82 -0
- recce_cloud/ci_providers/detector.py +147 -0
- recce_cloud/ci_providers/github_actions.py +136 -0
- recce_cloud/ci_providers/gitlab_ci.py +130 -0
- recce_cloud/cli.py +245 -0
- recce_cloud/upload.py +214 -0
- {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/METADATA +68 -37
- recce_nightly-1.26.0.20251124.dist-info/RECORD +180 -0
- {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/WHEEL +1 -1
- {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/top_level.txt +1 -0
- tests/adapter/dbt_adapter/conftest.py +9 -5
- tests/adapter/dbt_adapter/dbt_test_helper.py +37 -22
- tests/adapter/dbt_adapter/test_dbt_adapter.py +0 -15
- tests/adapter/dbt_adapter/test_dbt_cll.py +656 -41
- tests/adapter/dbt_adapter/test_selector.py +22 -21
- tests/recce_cloud/__init__.py +0 -0
- tests/recce_cloud/test_ci_providers.py +351 -0
- tests/recce_cloud/test_cli.py +372 -0
- tests/recce_cloud/test_client.py +273 -0
- tests/recce_cloud/test_platform_clients.py +333 -0
- tests/tasks/conftest.py +1 -1
- tests/tasks/test_histogram.py +58 -66
- tests/tasks/test_lineage.py +36 -23
- tests/tasks/test_preset_checks.py +45 -31
- tests/tasks/test_profile.py +339 -15
- tests/tasks/test_query.py +46 -46
- tests/tasks/test_row_count.py +65 -46
- tests/tasks/test_schema.py +65 -42
- tests/tasks/test_top_k.py +22 -18
- tests/tasks/test_valuediff.py +43 -32
- tests/test_cli.py +174 -60
- tests/test_cli_mcp_optional.py +45 -0
- tests/test_cloud_listing_cli.py +324 -0
- tests/test_config.py +7 -9
- tests/test_connect_to_cloud.py +82 -0
- tests/test_core.py +151 -4
- tests/test_dbt.py +7 -7
- tests/test_mcp_server.py +332 -0
- tests/test_pull_request.py +1 -1
- tests/test_server.py +25 -19
- tests/test_summary.py +29 -17
- recce/data/_next/static/Kcbs3GEIyH2LxgLYat0es/_buildManifest.js +0 -1
- recce/data/_next/static/chunks/1f229bf6-d9fe92e56db8d93b.js +0 -1
- recce/data/_next/static/chunks/29e3cc0d-8c150e37dff9631b.js +0 -1
- recce/data/_next/static/chunks/368-7587b306577df275.js +0 -65
- recce/data/_next/static/chunks/36e1c10d-bb0210cbd6573a8d.js +0 -1
- recce/data/_next/static/chunks/3998a672-eaad84bdd88cc73e.js +0 -1
- recce/data/_next/static/chunks/3a92ee20-3b5d922d4157af5e.js +0 -1
- recce/data/_next/static/chunks/450c323b-1bb5db526e54435a.js +0 -1
- recce/data/_next/static/chunks/47d8844f-79a1b53c66a7d7ec.js +0 -1
- recce/data/_next/static/chunks/6dc81886-c94b9b91bc2c3caf.js +0 -1
- recce/data/_next/static/chunks/6ef81909-694dc38134099299.js +0 -1
- recce/data/_next/static/chunks/700-3b65fc3666820d00.js +0 -2
- recce/data/_next/static/chunks/7a8a3e83-d7fa409d97b38b2b.js +0 -1
- recce/data/_next/static/chunks/7f27ae6c-413f6b869a04183a.js +0 -1
- recce/data/_next/static/chunks/8d700b6a-f0b1f6b9e0d97ce2.js +0 -1
- recce/data/_next/static/chunks/9746af58-d74bef4d03eea6ab.js +0 -1
- recce/data/_next/static/chunks/a30376cd-7d806e1602f2dc3a.js +0 -1
- recce/data/_next/static/chunks/app/_not-found/page-8a886fa0855c3105.js +0 -1
- recce/data/_next/static/chunks/app/layout-9102e22cb73f74d6.js +0 -1
- recce/data/_next/static/chunks/app/page-cee661090afbd6aa.js +0 -1
- recce/data/_next/static/chunks/b63b1b3f-7395c74e11a14e95.js +0 -1
- recce/data/_next/static/chunks/c132bf7d-8102037f9ccf372a.js +0 -1
- recce/data/_next/static/chunks/c1ceaa8b-a1e442154d23515e.js +0 -1
- recce/data/_next/static/chunks/cd9f8d63-cf0d5a7b0f7a92e8.js +0 -54
- recce/data/_next/static/chunks/ce84277d-f42c2c58049cea2d.js +0 -1
- recce/data/_next/static/chunks/e24bf851-0f8cbc99656833e7.js +0 -1
- recce/data/_next/static/chunks/fee69bc6-f17d36c080742e74.js +0 -1
- recce/data/_next/static/chunks/framework-ded83d71b51ce901.js +0 -1
- recce/data/_next/static/chunks/main-a0859f1f36d0aa6c.js +0 -1
- recce/data/_next/static/chunks/main-app-0225a2255968e566.js +0 -1
- recce/data/_next/static/chunks/pages/_app-d5672bf3d8b6371b.js +0 -1
- recce/data/_next/static/chunks/pages/_error-ed75be3f25588548.js +0 -1
- recce/data/_next/static/chunks/webpack-567d72f0bc0820d5.js +0 -1
- recce/data/_next/static/css/c9ecb46a4b21c126.css +0 -14
- recce/data/_next/static/media/montserrat-cyrillic-800-normal.22628180.woff2 +0 -0
- recce/data/_next/static/media/montserrat-cyrillic-800-normal.31d693bb.woff +0 -0
- recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.7e2c1e62.woff +0 -0
- recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.94a63aea.woff2 +0 -0
- recce/data/_next/static/media/montserrat-latin-800-normal.6f8fa298.woff2 +0 -0
- recce/data/_next/static/media/montserrat-latin-800-normal.97e20d5e.woff +0 -0
- recce/data/_next/static/media/montserrat-latin-ext-800-normal.013b84f9.woff2 +0 -0
- recce/data/_next/static/media/montserrat-latin-ext-800-normal.aff52ab0.woff +0 -0
- recce/data/_next/static/media/montserrat-vietnamese-800-normal.5f21869b.woff +0 -0
- recce/data/_next/static/media/montserrat-vietnamese-800-normal.c0035377.woff2 +0 -0
- recce/state.py +0 -753
- recce_nightly-1.2.0.20250506.dist-info/RECORD +0 -142
- tests/test_state.py +0 -123
- /recce/data/_next/static/{Kcbs3GEIyH2LxgLYat0es → 52aV_JrNUZU6dMFgvTQEO}/_ssgManifest.js +0 -0
- /recce/data/_next/static/chunks/{polyfills-42372ed130431b0a.js → a6dad97d9634a72d.js} +0 -0
- {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/entry_points.txt +0 -0
- {recce_nightly-1.2.0.20250506.dist-info → recce_nightly-1.26.0.20251124.dist-info}/licenses/LICENSE +0 -0
recce/models/__init__.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
from .check import CheckDAO
|
|
2
2
|
from .run import RunDAO
|
|
3
|
-
from .types import Check, Run,
|
|
3
|
+
from .types import Check, Run, RunProgress, RunType
|
|
4
|
+
|
|
5
|
+
# Explicitly declare exports
|
|
6
|
+
__all__ = ["CheckDAO", "RunDAO", "Check", "Run", "RunProgress", "RunType"]
|
recce/models/check.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import List, Optional
|
|
2
2
|
|
|
3
3
|
from recce.exceptions import RecceException
|
|
4
|
+
|
|
4
5
|
from .types import Check
|
|
5
6
|
|
|
6
7
|
|
|
@@ -12,6 +13,7 @@ class CheckDAO:
|
|
|
12
13
|
@property
|
|
13
14
|
def _checks(self):
|
|
14
15
|
from recce.core import default_context
|
|
16
|
+
|
|
15
17
|
return default_context().checks
|
|
16
18
|
|
|
17
19
|
def create(self, check) -> None:
|
|
@@ -38,10 +40,10 @@ class CheckDAO:
|
|
|
38
40
|
def reorder(self, source: int, destination: int):
|
|
39
41
|
|
|
40
42
|
if source < 0 or source >= len(self._checks):
|
|
41
|
-
raise RecceException(
|
|
43
|
+
raise RecceException("Failed to reorder checks. Source index out of range")
|
|
42
44
|
|
|
43
45
|
if destination < 0 or destination >= len(self._checks):
|
|
44
|
-
raise RecceException(
|
|
46
|
+
raise RecceException("Failed to reorder checks. Destination index out of range")
|
|
45
47
|
|
|
46
48
|
check_to_move = self._checks.pop(source)
|
|
47
49
|
self._checks.insert(destination, check_to_move)
|
|
@@ -50,7 +52,4 @@ class CheckDAO:
|
|
|
50
52
|
self._checks.clear()
|
|
51
53
|
|
|
52
54
|
def status(self):
|
|
53
|
-
return {
|
|
54
|
-
'total': len(self._checks),
|
|
55
|
-
'approved': len([c for c in self._checks if c.is_checked])
|
|
56
|
-
}
|
|
55
|
+
return {"total": len(self._checks), "approved": len([c for c in self._checks if c.is_checked])}
|
recce/models/run.py
CHANGED
recce/models/types.py
CHANGED
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
import uuid
|
|
2
2
|
from datetime import datetime, timezone
|
|
3
3
|
from enum import Enum
|
|
4
|
-
from typing import Optional,
|
|
4
|
+
from typing import Dict, List, Literal, Optional, Set
|
|
5
5
|
|
|
6
|
-
from pydantic import
|
|
6
|
+
from pydantic import UUID4, BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from recce.util.pydantic_model import pydantic_model_dump
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
class RunType(Enum):
|
|
10
|
-
SIMPLE =
|
|
12
|
+
SIMPLE = "simple"
|
|
11
13
|
QUERY = "query"
|
|
12
|
-
QUERY_BASE =
|
|
13
|
-
QUERY_DIFF =
|
|
14
|
-
VALUE_DIFF =
|
|
15
|
-
VALUE_DIFF_DETAIL =
|
|
16
|
-
SCHEMA_DIFF =
|
|
17
|
-
PROFILE =
|
|
18
|
-
PROFILE_DIFF =
|
|
19
|
-
ROW_COUNT =
|
|
20
|
-
ROW_COUNT_DIFF =
|
|
21
|
-
LINEAGE_DIFF =
|
|
22
|
-
TOP_K_DIFF =
|
|
23
|
-
HISTOGRAM_DIFF =
|
|
14
|
+
QUERY_BASE = "query_base"
|
|
15
|
+
QUERY_DIFF = "query_diff"
|
|
16
|
+
VALUE_DIFF = "value_diff"
|
|
17
|
+
VALUE_DIFF_DETAIL = "value_diff_detail"
|
|
18
|
+
SCHEMA_DIFF = "schema_diff"
|
|
19
|
+
PROFILE = "profile"
|
|
20
|
+
PROFILE_DIFF = "profile_diff"
|
|
21
|
+
ROW_COUNT = "row_count"
|
|
22
|
+
ROW_COUNT_DIFF = "row_count_diff"
|
|
23
|
+
LINEAGE_DIFF = "lineage_diff"
|
|
24
|
+
TOP_K_DIFF = "top_k_diff"
|
|
25
|
+
HISTOGRAM_DIFF = "histogram_diff"
|
|
24
26
|
|
|
25
27
|
def __str__(self):
|
|
26
28
|
return self.value
|
|
@@ -32,12 +34,10 @@ class RunProgress(BaseModel):
|
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
class RunStatus(Enum):
|
|
35
|
-
FINISHED =
|
|
36
|
-
FAILED =
|
|
37
|
-
CANCELLED =
|
|
38
|
-
RUNNING =
|
|
39
|
-
# This is a special status only in v0.36.0. Replaced by FINISHED. To be removed in the future.
|
|
40
|
-
SUCCESSFUL = 'successful'
|
|
37
|
+
FINISHED = "finished"
|
|
38
|
+
FAILED = "failed"
|
|
39
|
+
CANCELLED = "cancelled"
|
|
40
|
+
RUNNING = "running"
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
class Run(BaseModel):
|
|
@@ -52,6 +52,39 @@ class Run(BaseModel):
|
|
|
52
52
|
run_id: UUID4 = Field(default_factory=uuid.uuid4)
|
|
53
53
|
run_at: str = Field(default_factory=lambda: datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"))
|
|
54
54
|
|
|
55
|
+
def __init__(self, **data):
|
|
56
|
+
type = data.get("type")
|
|
57
|
+
|
|
58
|
+
if "result" in data and data["result"] is not None:
|
|
59
|
+
result = data.get("result")
|
|
60
|
+
|
|
61
|
+
if type in [RunType.QUERY.value, RunType.QUERY_BASE.value]:
|
|
62
|
+
from recce.tasks.query import QueryResult
|
|
63
|
+
|
|
64
|
+
data["result"] = pydantic_model_dump(QueryResult(**result))
|
|
65
|
+
elif type == RunType.QUERY_DIFF.value:
|
|
66
|
+
from recce.tasks.query import QueryDiffResult
|
|
67
|
+
|
|
68
|
+
data["result"] = pydantic_model_dump(QueryDiffResult(**result))
|
|
69
|
+
elif type == RunType.PROFILE.value:
|
|
70
|
+
from recce.tasks.profile import ProfileResult
|
|
71
|
+
|
|
72
|
+
data["result"] = pydantic_model_dump(ProfileResult(**result))
|
|
73
|
+
elif type == RunType.PROFILE_DIFF.value:
|
|
74
|
+
from recce.tasks.profile import ProfileDiffResult
|
|
75
|
+
|
|
76
|
+
data["result"] = pydantic_model_dump(ProfileDiffResult(**result))
|
|
77
|
+
elif type == RunType.VALUE_DIFF.value:
|
|
78
|
+
from recce.tasks.valuediff import ValueDiffResult
|
|
79
|
+
|
|
80
|
+
data["result"] = pydantic_model_dump(ValueDiffResult(**result))
|
|
81
|
+
elif type == RunType.VALUE_DIFF_DETAIL.value:
|
|
82
|
+
from recce.tasks.valuediff import ValueDiffDetailResult
|
|
83
|
+
|
|
84
|
+
data["result"] = pydantic_model_dump(ValueDiffDetailResult(**result))
|
|
85
|
+
|
|
86
|
+
super().__init__(**data)
|
|
87
|
+
|
|
55
88
|
|
|
56
89
|
class Check(BaseModel):
|
|
57
90
|
name: str
|
|
@@ -84,15 +117,15 @@ class Check(BaseModel):
|
|
|
84
117
|
|
|
85
118
|
|
|
86
119
|
ChangeStatus = Literal[
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
120
|
+
"added",
|
|
121
|
+
"removed",
|
|
122
|
+
"modified",
|
|
90
123
|
]
|
|
91
124
|
ChangeCategory = Literal[
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
125
|
+
"breaking",
|
|
126
|
+
"non_breaking",
|
|
127
|
+
"partial_breaking",
|
|
128
|
+
"unknown",
|
|
96
129
|
]
|
|
97
130
|
|
|
98
131
|
|
|
@@ -110,3 +143,73 @@ class LineageDiff(BaseModel):
|
|
|
110
143
|
base: dict
|
|
111
144
|
current: dict
|
|
112
145
|
diff: dict[str, NodeDiff]
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# Column Level Linage
|
|
149
|
+
class CllColumnDep(BaseModel):
|
|
150
|
+
node: str
|
|
151
|
+
column: str
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class CllColumn(BaseModel):
|
|
155
|
+
id: Optional[str] = None
|
|
156
|
+
table_id: Optional[str] = None
|
|
157
|
+
name: Optional[str] = None
|
|
158
|
+
|
|
159
|
+
# data type
|
|
160
|
+
type: Optional[str] = None
|
|
161
|
+
|
|
162
|
+
# transformation type
|
|
163
|
+
transformation_type: Literal["source", "passthrough", "renamed", "derived", "unknown"] = "unknown"
|
|
164
|
+
|
|
165
|
+
# change analysis
|
|
166
|
+
change_status: Optional[ChangeStatus] = None
|
|
167
|
+
|
|
168
|
+
# column-to-column dependencies
|
|
169
|
+
depends_on: List[CllColumnDep] = Field(default_factory=list)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class CllNode(BaseModel):
|
|
173
|
+
id: str
|
|
174
|
+
name: str
|
|
175
|
+
package_name: str
|
|
176
|
+
resource_type: str
|
|
177
|
+
raw_code: Optional[str] = None
|
|
178
|
+
source_name: Optional[str] = None
|
|
179
|
+
|
|
180
|
+
# change analysis
|
|
181
|
+
change_status: Optional[ChangeStatus] = None
|
|
182
|
+
change_category: Optional[ChangeCategory] = None
|
|
183
|
+
|
|
184
|
+
# Column to column dependencies
|
|
185
|
+
columns: Dict[str, CllColumn] = Field(default_factory=dict)
|
|
186
|
+
|
|
187
|
+
# If the node is impacted. Only used if option 'change_analysis' is set
|
|
188
|
+
impacted: Optional[bool] = None
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def build_cll_node(cls, manifest, resource_key, node_id) -> Optional["CllNode"]:
|
|
192
|
+
resources = getattr(manifest, resource_key)
|
|
193
|
+
if node_id not in resources:
|
|
194
|
+
return None
|
|
195
|
+
n = resources[node_id]
|
|
196
|
+
if resource_key == "nodes" and n.resource_type not in ["model", "seed", "snapshot"]:
|
|
197
|
+
return None
|
|
198
|
+
cll_node = CllNode(
|
|
199
|
+
id=n.unique_id,
|
|
200
|
+
name=n.name,
|
|
201
|
+
package_name=n.package_name,
|
|
202
|
+
resource_type=n.resource_type,
|
|
203
|
+
)
|
|
204
|
+
if resource_key == "sources":
|
|
205
|
+
cll_node.source_name = n.source_name
|
|
206
|
+
elif resource_key == "nodes":
|
|
207
|
+
cll_node.raw_code = n.raw_code
|
|
208
|
+
return cll_node
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class CllData(BaseModel):
|
|
212
|
+
nodes: Dict[str, CllNode] = Field(default_factory=dict)
|
|
213
|
+
columns: Dict[str, CllColumn] = Field(default_factory=dict)
|
|
214
|
+
parent_map: Dict[str, Set[str]] = Field(default_factory=dict)
|
|
215
|
+
child_map: Dict[str, Set[str]] = Field(default_factory=dict)
|
recce/pull_request.py
CHANGED
|
@@ -28,14 +28,14 @@ def fetch_pr_metadata(**kwargs):
|
|
|
28
28
|
# fetch from github action event path
|
|
29
29
|
metadata = fetch_pr_metadata_from_event_path()
|
|
30
30
|
if metadata is not None:
|
|
31
|
-
pr_info.id = metadata.get(
|
|
32
|
-
pr_info.url = metadata.get(
|
|
33
|
-
pr_info.title = metadata.get(
|
|
34
|
-
pr_info.repository = metadata.get(
|
|
31
|
+
pr_info.id = metadata.get("github_pr_id")
|
|
32
|
+
pr_info.url = metadata.get("github_pr_url")
|
|
33
|
+
pr_info.title = metadata.get("github_pr_title")
|
|
34
|
+
pr_info.repository = metadata.get("github_repository")
|
|
35
35
|
else:
|
|
36
36
|
repo = hosting_repo()
|
|
37
|
-
pr, message = recce_pr_information(github_token=kwargs.get(
|
|
38
|
-
if kwargs.get(
|
|
37
|
+
pr, message = recce_pr_information(github_token=kwargs.get("github_token"))
|
|
38
|
+
if kwargs.get("cloud") and message:
|
|
39
39
|
print(message)
|
|
40
40
|
|
|
41
41
|
if pr:
|
|
@@ -47,14 +47,14 @@ def fetch_pr_metadata(**kwargs):
|
|
|
47
47
|
pr_info.branch = pr.head.ref
|
|
48
48
|
|
|
49
49
|
# fetch from cli arguments
|
|
50
|
-
if pr_info.url is None and
|
|
51
|
-
pr_info.url = kwargs.get(
|
|
50
|
+
if pr_info.url is None and "github_pull_request_url" in kwargs:
|
|
51
|
+
pr_info.url = kwargs.get("github_pull_request_url")
|
|
52
52
|
|
|
53
53
|
if pr_info.branch is None:
|
|
54
|
-
pr_info.branch = kwargs.get(
|
|
54
|
+
pr_info.branch = kwargs.get("git_current_branch")
|
|
55
55
|
|
|
56
56
|
if pr_info.base_branch is None:
|
|
57
|
-
pr_info.base_branch = kwargs.get(
|
|
57
|
+
pr_info.base_branch = kwargs.get("git_base_branch")
|
|
58
58
|
|
|
59
59
|
# fetch from env
|
|
60
60
|
if pr_info.url is None:
|
|
@@ -65,17 +65,17 @@ def fetch_pr_metadata(**kwargs):
|
|
|
65
65
|
|
|
66
66
|
def fetch_pr_metadata_from_event_path() -> Optional[dict]:
|
|
67
67
|
"""
|
|
68
|
-
|
|
68
|
+
If recce run is running in a GitHub Action, this function will return the pull request metadata.
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
Example:
|
|
71
|
+
{
|
|
72
|
+
"github_pr_id": 1,
|
|
73
|
+
"github_pr_url": "https://github.com/xyz/abc/pull/1,
|
|
74
|
+
"github_pr_title": "Update README.md",
|
|
75
|
+
"github_repository": "xyz/abc"
|
|
76
|
+
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
:return: dict
|
|
79
79
|
"""
|
|
80
80
|
|
|
81
81
|
# get the event json from the path in GITHUB_EVENT_PATH
|
|
@@ -83,7 +83,7 @@ def fetch_pr_metadata_from_event_path() -> Optional[dict]:
|
|
|
83
83
|
github_repository = os.getenv("GITHUB_REPOSITORY")
|
|
84
84
|
if event_path:
|
|
85
85
|
try:
|
|
86
|
-
with open(event_path, "r") as event_file:
|
|
86
|
+
with open(event_path, "r", encoding="utf-8") as event_file:
|
|
87
87
|
event_data = json.load(event_file)
|
|
88
88
|
|
|
89
89
|
pr_id = event_data["number"]
|
|
@@ -92,10 +92,12 @@ def fetch_pr_metadata_from_event_path() -> Optional[dict]:
|
|
|
92
92
|
pr_url = pull_request_data["_links"]["html"]["href"]
|
|
93
93
|
pr_api = pull_request_data["_links"]["self"]["href"]
|
|
94
94
|
pr_title = _fetch_pr_title(pr_api)
|
|
95
|
-
return dict(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
return dict(
|
|
96
|
+
github_pr_id=pr_id,
|
|
97
|
+
github_pr_url=pr_url,
|
|
98
|
+
github_pr_title=pr_title,
|
|
99
|
+
github_repository=github_repository,
|
|
100
|
+
)
|
|
99
101
|
else:
|
|
100
102
|
print("Not a pull request event, skip.")
|
|
101
103
|
except Exception as e:
|
|
@@ -115,7 +117,7 @@ def _fetch_pr_title(endpoint) -> Optional[str]:
|
|
|
115
117
|
|
|
116
118
|
if response.status_code == 200:
|
|
117
119
|
pull_request_data = response.json()
|
|
118
|
-
return pull_request_data.get(
|
|
120
|
+
return pull_request_data.get("title")
|
|
119
121
|
except Exception as e:
|
|
120
122
|
print("Cannot fetch PR title: ", e)
|
|
121
123
|
|