recce-cloud 1.33.1__py3-none-any.whl → 1.34.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- recce_cloud/VERSION +1 -1
- recce_cloud/api/base.py +9 -9
- recce_cloud/api/client.py +257 -5
- recce_cloud/api/github.py +19 -19
- recce_cloud/api/gitlab.py +19 -19
- recce_cloud/ci_providers/base.py +8 -8
- recce_cloud/ci_providers/detector.py +17 -17
- recce_cloud/ci_providers/github_actions.py +8 -8
- recce_cloud/ci_providers/gitlab_ci.py +8 -8
- recce_cloud/cli.py +244 -86
- recce_cloud/commands/diagnostics.py +3 -3
- recce_cloud/config/project_config.py +10 -10
- recce_cloud/config/resolver.py +47 -19
- recce_cloud/delete.py +6 -6
- recce_cloud/download.py +5 -5
- recce_cloud/review.py +541 -0
- recce_cloud/services/diagnostic_service.py +7 -7
- recce_cloud/upload.py +5 -5
- {recce_cloud-1.33.1.dist-info → recce_cloud-1.34.0.dist-info}/METADATA +6 -6
- recce_cloud-1.34.0.dist-info/RECORD +38 -0
- recce_cloud-1.33.1.dist-info/RECORD +0 -37
- {recce_cloud-1.33.1.dist-info → recce_cloud-1.34.0.dist-info}/WHEEL +0 -0
- {recce_cloud-1.33.1.dist-info → recce_cloud-1.34.0.dist-info}/entry_points.txt +0 -0
recce_cloud/config/resolver.py
CHANGED
|
@@ -19,8 +19,8 @@ from recce_cloud.config.project_config import get_project_binding
|
|
|
19
19
|
class ResolvedConfig:
|
|
20
20
|
"""Resolved configuration with source information."""
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
org_id: str
|
|
23
|
+
project_id: str
|
|
24
24
|
source: str # "cli", "env", "config"
|
|
25
25
|
|
|
26
26
|
|
|
@@ -30,6 +30,26 @@ class ConfigurationError(Exception):
|
|
|
30
30
|
pass
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
def _validate_numeric_id(value: str, field_name: str, source: str) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Validate that a value is a numeric ID.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
value: The value to validate.
|
|
39
|
+
field_name: Name of the field (for error messages).
|
|
40
|
+
source: Source of the value (for error messages).
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
ConfigurationError: If the value is not a numeric ID.
|
|
44
|
+
"""
|
|
45
|
+
if not value.isdigit():
|
|
46
|
+
raise ConfigurationError(
|
|
47
|
+
f"Invalid {field_name}: '{value}' (from {source}). "
|
|
48
|
+
f"The API requires numeric IDs, not slugs. "
|
|
49
|
+
f"Run 'recce-cloud init' to bind this directory to a project with proper IDs."
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
33
53
|
def resolve_config(
|
|
34
54
|
cli_org: Optional[str] = None,
|
|
35
55
|
cli_project: Optional[str] = None,
|
|
@@ -45,32 +65,40 @@ def resolve_config(
|
|
|
45
65
|
4. Error if nothing found
|
|
46
66
|
|
|
47
67
|
Args:
|
|
48
|
-
cli_org: Organization from CLI flag.
|
|
49
|
-
cli_project: Project from CLI flag.
|
|
68
|
+
cli_org: Organization ID from CLI flag.
|
|
69
|
+
cli_project: Project ID from CLI flag.
|
|
50
70
|
project_dir: Project directory for local config lookup.
|
|
51
71
|
|
|
52
72
|
Returns:
|
|
53
|
-
ResolvedConfig with
|
|
73
|
+
ResolvedConfig with org_id, project_id, and source.
|
|
54
74
|
|
|
55
75
|
Raises:
|
|
56
76
|
ConfigurationError: If org/project cannot be resolved.
|
|
57
77
|
"""
|
|
58
78
|
# Priority 1: CLI flags
|
|
59
79
|
if cli_org and cli_project:
|
|
60
|
-
|
|
80
|
+
_validate_numeric_id(cli_org, "org", "CLI flag --org")
|
|
81
|
+
_validate_numeric_id(cli_project, "project", "CLI flag --project")
|
|
82
|
+
return ResolvedConfig(org_id=cli_org, project_id=cli_project, source="cli")
|
|
61
83
|
|
|
62
84
|
# Priority 2: Environment variables
|
|
63
85
|
env_org = os.environ.get("RECCE_ORG")
|
|
64
86
|
env_project = os.environ.get("RECCE_PROJECT")
|
|
65
87
|
if env_org and env_project:
|
|
66
|
-
|
|
88
|
+
_validate_numeric_id(env_org, "org", "environment variable RECCE_ORG")
|
|
89
|
+
_validate_numeric_id(env_project, "project", "environment variable RECCE_PROJECT")
|
|
90
|
+
return ResolvedConfig(org_id=env_org, project_id=env_project, source="env")
|
|
67
91
|
|
|
68
92
|
# Priority 3: Local config file
|
|
69
93
|
binding = get_project_binding(project_dir)
|
|
70
94
|
if binding:
|
|
95
|
+
org_id = binding["org_id"]
|
|
96
|
+
project_id = binding["project_id"]
|
|
97
|
+
_validate_numeric_id(org_id, "org_id", "config file")
|
|
98
|
+
_validate_numeric_id(project_id, "project_id", "config file")
|
|
71
99
|
return ResolvedConfig(
|
|
72
|
-
|
|
73
|
-
|
|
100
|
+
org_id=org_id,
|
|
101
|
+
project_id=project_id,
|
|
74
102
|
source="config",
|
|
75
103
|
)
|
|
76
104
|
|
|
@@ -81,19 +109,19 @@ def resolve_config(
|
|
|
81
109
|
)
|
|
82
110
|
|
|
83
111
|
|
|
84
|
-
def
|
|
112
|
+
def resolve_org_id(
|
|
85
113
|
cli_org: Optional[str] = None,
|
|
86
114
|
project_dir: Optional[str] = None,
|
|
87
115
|
) -> Optional[str]:
|
|
88
116
|
"""
|
|
89
|
-
Resolve organization from multiple sources.
|
|
117
|
+
Resolve organization ID from multiple sources.
|
|
90
118
|
|
|
91
119
|
Args:
|
|
92
|
-
cli_org: Organization from CLI flag.
|
|
120
|
+
cli_org: Organization ID from CLI flag.
|
|
93
121
|
project_dir: Project directory for local config lookup.
|
|
94
122
|
|
|
95
123
|
Returns:
|
|
96
|
-
Organization
|
|
124
|
+
Organization ID, or None if not found.
|
|
97
125
|
"""
|
|
98
126
|
if cli_org:
|
|
99
127
|
return cli_org
|
|
@@ -104,24 +132,24 @@ def resolve_org(
|
|
|
104
132
|
|
|
105
133
|
binding = get_project_binding(project_dir)
|
|
106
134
|
if binding:
|
|
107
|
-
return binding["
|
|
135
|
+
return binding["org_id"]
|
|
108
136
|
|
|
109
137
|
return None
|
|
110
138
|
|
|
111
139
|
|
|
112
|
-
def
|
|
140
|
+
def resolve_project_id(
|
|
113
141
|
cli_project: Optional[str] = None,
|
|
114
142
|
project_dir: Optional[str] = None,
|
|
115
143
|
) -> Optional[str]:
|
|
116
144
|
"""
|
|
117
|
-
Resolve project from multiple sources.
|
|
145
|
+
Resolve project ID or slug from multiple sources.
|
|
118
146
|
|
|
119
147
|
Args:
|
|
120
|
-
cli_project: Project from CLI flag.
|
|
148
|
+
cli_project: Project ID or slug from CLI flag.
|
|
121
149
|
project_dir: Project directory for local config lookup.
|
|
122
150
|
|
|
123
151
|
Returns:
|
|
124
|
-
Project
|
|
152
|
+
Project ID or slug, or None if not found.
|
|
125
153
|
"""
|
|
126
154
|
if cli_project:
|
|
127
155
|
return cli_project
|
|
@@ -132,6 +160,6 @@ def resolve_project(
|
|
|
132
160
|
|
|
133
161
|
binding = get_project_binding(project_dir)
|
|
134
162
|
if binding:
|
|
135
|
-
return binding["
|
|
163
|
+
return binding["project_id"]
|
|
136
164
|
|
|
137
165
|
return None
|
recce_cloud/delete.py
CHANGED
|
@@ -65,7 +65,7 @@ def delete_with_platform_apis(console, token: str, ci_info, prod: bool):
|
|
|
65
65
|
sys.exit(2)
|
|
66
66
|
|
|
67
67
|
# Determine session type
|
|
68
|
-
session_type = "prod" if prod else "
|
|
68
|
+
session_type = "prod" if prod else "pr"
|
|
69
69
|
|
|
70
70
|
# Delete session
|
|
71
71
|
console.rule("Deleting session", style="blue")
|
|
@@ -73,14 +73,14 @@ def delete_with_platform_apis(console, token: str, ci_info, prod: bool):
|
|
|
73
73
|
# Determine what to display based on session type
|
|
74
74
|
if session_type == "prod":
|
|
75
75
|
console.print("Deleting production/base session...")
|
|
76
|
-
elif session_type == "
|
|
77
|
-
console.print(f"Deleting PR/MR session (
|
|
76
|
+
elif session_type == "pr":
|
|
77
|
+
console.print(f"Deleting PR/MR session (PR #{ci_info.pr_number})...")
|
|
78
78
|
else:
|
|
79
79
|
console.print("Deleting session...")
|
|
80
80
|
|
|
81
81
|
try:
|
|
82
82
|
delete_response = client.delete_session(
|
|
83
|
-
|
|
83
|
+
pr_number=ci_info.pr_number,
|
|
84
84
|
session_type=session_type,
|
|
85
85
|
)
|
|
86
86
|
|
|
@@ -105,7 +105,7 @@ def delete_with_platform_apis(console, token: str, ci_info, prod: bool):
|
|
|
105
105
|
console.rule("Deleted Successfully", style="green")
|
|
106
106
|
console.print(f'Deleted session ID "{session_id}" from Recce Cloud')
|
|
107
107
|
|
|
108
|
-
if ci_info.
|
|
109
|
-
console.print(f"
|
|
108
|
+
if ci_info.pr_url:
|
|
109
|
+
console.print(f"Pull request: {ci_info.pr_url}")
|
|
110
110
|
|
|
111
111
|
sys.exit(0)
|
recce_cloud/download.py
CHANGED
|
@@ -181,14 +181,14 @@ def download_with_platform_apis(console, token: str, ci_info, target_path: str,
|
|
|
181
181
|
# Determine what to display based on session type
|
|
182
182
|
if ci_info.session_type == "prod":
|
|
183
183
|
console.print("Looking for production/base session...")
|
|
184
|
-
elif ci_info.session_type == "
|
|
185
|
-
console.print(f"Looking for PR/MR session (
|
|
184
|
+
elif ci_info.session_type == "pr":
|
|
185
|
+
console.print(f"Looking for PR/MR session (PR #{ci_info.pr_number})...")
|
|
186
186
|
else:
|
|
187
187
|
console.print("Looking for session...")
|
|
188
188
|
|
|
189
189
|
try:
|
|
190
190
|
download_response = client.get_session_download_urls(
|
|
191
|
-
|
|
191
|
+
pr_number=ci_info.pr_number,
|
|
192
192
|
session_type=ci_info.session_type,
|
|
193
193
|
)
|
|
194
194
|
|
|
@@ -224,7 +224,7 @@ def download_with_platform_apis(console, token: str, ci_info, target_path: str,
|
|
|
224
224
|
console.print(f'Downloaded dbt artifacts from Recce Cloud for session ID "{session_id}"')
|
|
225
225
|
console.print(f'Artifacts saved to: "{os.path.abspath(target_path)}"')
|
|
226
226
|
|
|
227
|
-
if ci_info.
|
|
228
|
-
console.print(f"
|
|
227
|
+
if ci_info.pr_url:
|
|
228
|
+
console.print(f"Pull request: {ci_info.pr_url}")
|
|
229
229
|
|
|
230
230
|
sys.exit(0)
|