ecosyste-ms-cli 1.3.2__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.
- ecosyste_ms_cli-1.3.2.dist-info/METADATA +133 -0
- ecosyste_ms_cli-1.3.2.dist-info/RECORD +84 -0
- ecosyste_ms_cli-1.3.2.dist-info/WHEEL +5 -0
- ecosyste_ms_cli-1.3.2.dist-info/entry_points.txt +2 -0
- ecosyste_ms_cli-1.3.2.dist-info/licenses/LICENSE +21 -0
- ecosyste_ms_cli-1.3.2.dist-info/top_level.txt +1 -0
- ecosystems_cli/__init__.py +3 -0
- ecosystems_cli/__main__.py +4 -0
- ecosystems_cli/apis/__init__.py +0 -0
- ecosystems_cli/apis/advisories.openapi.yaml +347 -0
- ecosystems_cli/apis/archives.openapi.yaml +193 -0
- ecosystems_cli/apis/commits.openapi.yaml +391 -0
- ecosystems_cli/apis/dependabot.openapi.yaml +887 -0
- ecosystems_cli/apis/diff.openapi.yaml +90 -0
- ecosystems_cli/apis/docker.openapi.yaml +534 -0
- ecosystems_cli/apis/issues.openapi.yaml +839 -0
- ecosystems_cli/apis/licenses.openapi.yaml +80 -0
- ecosystems_cli/apis/opencollective.openapi.yaml +247 -0
- ecosystems_cli/apis/packages.openapi.yaml +2522 -0
- ecosystems_cli/apis/parser.openapi.yaml +97 -0
- ecosystems_cli/apis/registries.yaml +155 -0
- ecosystems_cli/apis/repos.openapi.yaml +1521 -0
- ecosystems_cli/apis/resolve.openapi.yaml +130 -0
- ecosystems_cli/apis/sbom.openapi.yaml +79 -0
- ecosystems_cli/apis/sponsors.openapi.yaml +283 -0
- ecosystems_cli/apis/summary.openapi.yaml +239 -0
- ecosystems_cli/apis/timeline.openapi.yaml +91 -0
- ecosystems_cli/cli.py +213 -0
- ecosystems_cli/commands/__init__.py +1 -0
- ecosystems_cli/commands/advisories.py +109 -0
- ecosystems_cli/commands/archives.py +5 -0
- ecosystems_cli/commands/commits.py +5 -0
- ecosystems_cli/commands/decorators.py +101 -0
- ecosystems_cli/commands/dependabot.py +5 -0
- ecosystems_cli/commands/diff.py +144 -0
- ecosystems_cli/commands/docker.py +5 -0
- ecosystems_cli/commands/execution.py +99 -0
- ecosystems_cli/commands/generator.py +127 -0
- ecosystems_cli/commands/handlers/__init__.py +45 -0
- ecosystems_cli/commands/handlers/advisories.py +73 -0
- ecosystems_cli/commands/handlers/archives.py +40 -0
- ecosystems_cli/commands/handlers/base.py +38 -0
- ecosystems_cli/commands/handlers/commits.py +76 -0
- ecosystems_cli/commands/handlers/default.py +40 -0
- ecosystems_cli/commands/handlers/dependabot.py +205 -0
- ecosystems_cli/commands/handlers/diff.py +72 -0
- ecosystems_cli/commands/handlers/docker.py +142 -0
- ecosystems_cli/commands/handlers/factory.py +60 -0
- ecosystems_cli/commands/handlers/issues.py +87 -0
- ecosystems_cli/commands/handlers/licenses.py +52 -0
- ecosystems_cli/commands/handlers/opencollective.py +86 -0
- ecosystems_cli/commands/handlers/packages.py +103 -0
- ecosystems_cli/commands/handlers/parser.py +57 -0
- ecosystems_cli/commands/handlers/repos.py +97 -0
- ecosystems_cli/commands/handlers/resolve.py +68 -0
- ecosystems_cli/commands/handlers/sbom.py +52 -0
- ecosystems_cli/commands/handlers/sponsors.py +52 -0
- ecosystems_cli/commands/handlers/summary.py +81 -0
- ecosystems_cli/commands/handlers/timeline.py +45 -0
- ecosystems_cli/commands/issues.py +5 -0
- ecosystems_cli/commands/licenses.py +135 -0
- ecosystems_cli/commands/mcp.py +54 -0
- ecosystems_cli/commands/opencollective.py +5 -0
- ecosystems_cli/commands/packages.py +151 -0
- ecosystems_cli/commands/parser.py +135 -0
- ecosystems_cli/commands/repos.py +5 -0
- ecosystems_cli/commands/resolve.py +160 -0
- ecosystems_cli/commands/sbom.py +135 -0
- ecosystems_cli/commands/sponsors.py +5 -0
- ecosystems_cli/commands/summary.py +5 -0
- ecosystems_cli/commands/timeline.py +5 -0
- ecosystems_cli/constants.py +92 -0
- ecosystems_cli/exceptions.py +149 -0
- ecosystems_cli/helpers/click_params.py +49 -0
- ecosystems_cli/helpers/flatten_dict.py +15 -0
- ecosystems_cli/helpers/format_value.py +30 -0
- ecosystems_cli/helpers/get_domain.py +68 -0
- ecosystems_cli/helpers/load_api_spec.py +31 -0
- ecosystems_cli/helpers/print_error.py +15 -0
- ecosystems_cli/helpers/print_operations.py +73 -0
- ecosystems_cli/helpers/print_output.py +183 -0
- ecosystems_cli/helpers/purl_parser.py +121 -0
- ecosystems_cli/mcp_server.py +267 -0
- ecosystems_cli/openapi_client.py +461 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Handler for commits API operations."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
4
|
+
|
|
5
|
+
from .base import OperationHandler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CommitsOperationHandler(OperationHandler):
|
|
9
|
+
"""Handler for commits API operations."""
|
|
10
|
+
|
|
11
|
+
# Operation parameter configuration
|
|
12
|
+
# Maps operation_id -> list of (api_param_name, lowercase_variants)
|
|
13
|
+
OPERATION_PARAMS = {
|
|
14
|
+
"getHost": [("hostName", ["hostname"])],
|
|
15
|
+
"getHostRepositories": [("hostName", ["hostname"])],
|
|
16
|
+
"getHostRepository": [("hostName", ["hostname"]), ("repoName", ["reponame"])],
|
|
17
|
+
"getRepositoryCommits": [("hostName", ["hostname"]), ("repoName", ["reponame"])],
|
|
18
|
+
"getHostCommitter": [("hostName", ["hostname"]), ("login", ["login"])],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
def _extract_param(self, kwargs: dict, api_name: str, lowercase_variants: List[str]) -> Optional[str]:
|
|
22
|
+
"""Extract parameter from kwargs, trying API name first, then lowercase variants.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
kwargs: Keyword arguments dict
|
|
26
|
+
api_name: The API parameter name (exact case)
|
|
27
|
+
lowercase_variants: List of lowercase parameter name variants to try
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Parameter value if found, None otherwise
|
|
31
|
+
"""
|
|
32
|
+
# Try exact API name first
|
|
33
|
+
if api_name in kwargs:
|
|
34
|
+
return kwargs.pop(api_name)
|
|
35
|
+
|
|
36
|
+
# Try lowercase variants
|
|
37
|
+
for variant in lowercase_variants:
|
|
38
|
+
if variant in kwargs:
|
|
39
|
+
return kwargs.pop(variant)
|
|
40
|
+
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
def build_params(self, operation_id: str, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
44
|
+
"""Build parameters for commits API operations.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
operation_id: The operation identifier
|
|
48
|
+
args: Positional arguments
|
|
49
|
+
kwargs: Keyword arguments
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Tuple of (path_params, query_params)
|
|
53
|
+
"""
|
|
54
|
+
path_params = {}
|
|
55
|
+
query_params = {}
|
|
56
|
+
|
|
57
|
+
# Get parameter configuration for this operation
|
|
58
|
+
param_config = self.OPERATION_PARAMS.get(operation_id, [])
|
|
59
|
+
|
|
60
|
+
# Extract path parameters from args or kwargs
|
|
61
|
+
for i, (api_name, lowercase_variants) in enumerate(param_config):
|
|
62
|
+
if i < len(args):
|
|
63
|
+
# Use positional argument
|
|
64
|
+
path_params[api_name] = args[i]
|
|
65
|
+
else:
|
|
66
|
+
# Try to extract from kwargs
|
|
67
|
+
value = self._extract_param(kwargs, api_name, lowercase_variants)
|
|
68
|
+
if value is not None:
|
|
69
|
+
path_params[api_name] = value
|
|
70
|
+
|
|
71
|
+
# For all operations, remaining kwargs are query parameters
|
|
72
|
+
for key, value in kwargs.items():
|
|
73
|
+
if value is not None:
|
|
74
|
+
query_params[key] = value
|
|
75
|
+
|
|
76
|
+
return path_params, query_params
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Default handler for standard API operations."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Tuple
|
|
4
|
+
|
|
5
|
+
from .base import OperationHandler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DefaultOperationHandler(OperationHandler):
|
|
9
|
+
"""Default handler for standard API operations."""
|
|
10
|
+
|
|
11
|
+
# Configuration mapping: operation_id -> (param_type, param_name, arg_count)
|
|
12
|
+
OPERATION_CONFIG = {
|
|
13
|
+
"getProject": ("path", "id", 1),
|
|
14
|
+
"getList": ("path", "id", 1),
|
|
15
|
+
"getListProjects": ("path", "id", 1),
|
|
16
|
+
"getCollection": ("path", "id", 1),
|
|
17
|
+
"getCollectionProjects": ("path", "id", 1),
|
|
18
|
+
"getTopic": ("path", "slug", 1),
|
|
19
|
+
"getCollective": ("path", "id", 1),
|
|
20
|
+
"getCollectiveProjects": ("path", "slug", 1),
|
|
21
|
+
"lookupProject": ("query", "url", 1),
|
|
22
|
+
"createJob": ("query", "url", 1),
|
|
23
|
+
"getJob": ("path", "jobID", 1),
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
def build_params(self, operation_id: str, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
27
|
+
"""Build parameters for standard API operations."""
|
|
28
|
+
all_args = list(args) + list(kwargs.values())
|
|
29
|
+
|
|
30
|
+
config = self.OPERATION_CONFIG.get(operation_id)
|
|
31
|
+
if config and len(all_args) >= config[2]:
|
|
32
|
+
param_type, param_name, _ = config
|
|
33
|
+
value = all_args[0]
|
|
34
|
+
|
|
35
|
+
if param_type == "path":
|
|
36
|
+
return {param_name: value}, {}
|
|
37
|
+
elif param_type == "query":
|
|
38
|
+
return {}, {param_name: value}
|
|
39
|
+
|
|
40
|
+
return {}, {}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""Handler for dependabot API operations."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Tuple
|
|
4
|
+
|
|
5
|
+
from .base import OperationHandler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DependabotOperationHandler(OperationHandler):
|
|
9
|
+
"""Handler for dependabot API operations.
|
|
10
|
+
|
|
11
|
+
Handles parameter mapping for dependabot API operations including:
|
|
12
|
+
- Package operations: getPackages, getPackage, getEcosystemPackages
|
|
13
|
+
- Repository operations: getHost, getHostRepository, getHostRepositoryIssues
|
|
14
|
+
- Advisory operations: getAdvisories, getAdvisory
|
|
15
|
+
- Lookup operations: repositoriesLookup
|
|
16
|
+
|
|
17
|
+
Supports hierarchical path parameters like /hosts/{hostName}/repositories/{repoName}/issues/{issueNumber}
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def build_params(self, operation_id: str, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
21
|
+
"""Build parameters for dependabot API operations.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
operation_id: The operation identifier
|
|
25
|
+
args: Positional arguments
|
|
26
|
+
kwargs: Keyword arguments
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Tuple of (path_params, query_params)
|
|
30
|
+
"""
|
|
31
|
+
handlers = {
|
|
32
|
+
"getPackages": self._handle_query_params,
|
|
33
|
+
"getPackageEcosystems": self._handle_no_params,
|
|
34
|
+
"getEcosystemPackages": self._handle_ecosystem_packages,
|
|
35
|
+
"getPackage": self._handle_get_package,
|
|
36
|
+
"getIssuePackages": self._handle_issue_packages,
|
|
37
|
+
"repositoriesLookup": self._handle_repositories_lookup,
|
|
38
|
+
"getRegistries": self._handle_query_params,
|
|
39
|
+
"getHost": self._handle_get_host,
|
|
40
|
+
"getHostRepositories": self._handle_host_repositories,
|
|
41
|
+
"getHostRepository": self._handle_host_repository,
|
|
42
|
+
"getHostRepositoryIssues": self._handle_host_repository_issues,
|
|
43
|
+
"getHostRepositoryIssue": self._handle_host_repository_issue,
|
|
44
|
+
"getAdvisories": self._handle_query_params,
|
|
45
|
+
"getAdvisory": self._handle_get_advisory,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
handler = handlers.get(operation_id, self._handle_default)
|
|
49
|
+
return handler(args, kwargs)
|
|
50
|
+
|
|
51
|
+
def _handle_ecosystem_packages(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
52
|
+
"""Handle getEcosystemPackages operation parameters."""
|
|
53
|
+
path_params = {}
|
|
54
|
+
query_params = {}
|
|
55
|
+
|
|
56
|
+
ecosystem = args[0] if args else kwargs.pop("ecosystem", None)
|
|
57
|
+
if ecosystem:
|
|
58
|
+
path_params["ecosystem"] = ecosystem
|
|
59
|
+
|
|
60
|
+
# Add remaining kwargs as query parameters
|
|
61
|
+
query_params.update({k: v for k, v in kwargs.items() if v is not None})
|
|
62
|
+
|
|
63
|
+
return path_params, query_params
|
|
64
|
+
|
|
65
|
+
def _handle_get_package(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
66
|
+
"""Handle getPackage operation parameters."""
|
|
67
|
+
path_params = {}
|
|
68
|
+
|
|
69
|
+
if len(args) >= 2:
|
|
70
|
+
path_params["ecosystem"] = args[0]
|
|
71
|
+
path_params["name"] = args[1]
|
|
72
|
+
else:
|
|
73
|
+
if "ecosystem" in kwargs:
|
|
74
|
+
path_params["ecosystem"] = kwargs["ecosystem"]
|
|
75
|
+
if "name" in kwargs:
|
|
76
|
+
path_params["name"] = kwargs["name"]
|
|
77
|
+
|
|
78
|
+
return path_params, {}
|
|
79
|
+
|
|
80
|
+
def _handle_issue_packages(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
81
|
+
"""Handle getIssuePackages operation parameters."""
|
|
82
|
+
path_params = {}
|
|
83
|
+
|
|
84
|
+
issue_id = args[0] if args else kwargs.get("issueId")
|
|
85
|
+
if issue_id:
|
|
86
|
+
path_params["issueId"] = issue_id
|
|
87
|
+
|
|
88
|
+
return path_params, {}
|
|
89
|
+
|
|
90
|
+
def _handle_repositories_lookup(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
91
|
+
"""Handle repositoriesLookup operation parameters."""
|
|
92
|
+
query_params = {}
|
|
93
|
+
|
|
94
|
+
url = args[0] if args else kwargs.get("url")
|
|
95
|
+
if url:
|
|
96
|
+
query_params["url"] = url
|
|
97
|
+
|
|
98
|
+
return {}, query_params
|
|
99
|
+
|
|
100
|
+
def _handle_get_host(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
101
|
+
"""Handle getHost operation parameters."""
|
|
102
|
+
path_params = {}
|
|
103
|
+
query_params = {}
|
|
104
|
+
|
|
105
|
+
host_name = args[0] if args else kwargs.pop("hostName", None)
|
|
106
|
+
if host_name:
|
|
107
|
+
path_params["hostName"] = host_name
|
|
108
|
+
|
|
109
|
+
# Add remaining kwargs as query parameters
|
|
110
|
+
query_params.update({k: v for k, v in kwargs.items() if v is not None})
|
|
111
|
+
|
|
112
|
+
return path_params, query_params
|
|
113
|
+
|
|
114
|
+
def _handle_host_repositories(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
115
|
+
"""Handle getHostRepositories operation parameters."""
|
|
116
|
+
path_params = {}
|
|
117
|
+
query_params = {}
|
|
118
|
+
|
|
119
|
+
host_name = args[0] if args else kwargs.pop("hostName", None)
|
|
120
|
+
if host_name:
|
|
121
|
+
path_params["hostName"] = host_name
|
|
122
|
+
|
|
123
|
+
# Add remaining kwargs as query parameters
|
|
124
|
+
query_params.update({k: v for k, v in kwargs.items() if v is not None})
|
|
125
|
+
|
|
126
|
+
return path_params, query_params
|
|
127
|
+
|
|
128
|
+
def _handle_host_repository(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
129
|
+
"""Handle getHostRepository operation parameters."""
|
|
130
|
+
path_params = {}
|
|
131
|
+
|
|
132
|
+
if len(args) >= 2:
|
|
133
|
+
path_params["hostName"] = args[0]
|
|
134
|
+
path_params["repoName"] = args[1]
|
|
135
|
+
else:
|
|
136
|
+
if "hostName" in kwargs:
|
|
137
|
+
path_params["hostName"] = kwargs["hostName"]
|
|
138
|
+
if "repoName" in kwargs:
|
|
139
|
+
path_params["repoName"] = kwargs["repoName"]
|
|
140
|
+
|
|
141
|
+
return path_params, {}
|
|
142
|
+
|
|
143
|
+
def _handle_host_repository_issues(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
144
|
+
"""Handle getHostRepositoryIssues operation parameters."""
|
|
145
|
+
path_params = {}
|
|
146
|
+
query_params = {}
|
|
147
|
+
|
|
148
|
+
if len(args) >= 2:
|
|
149
|
+
path_params["hostName"] = args[0]
|
|
150
|
+
path_params["repoName"] = args[1]
|
|
151
|
+
else:
|
|
152
|
+
if "hostName" in kwargs:
|
|
153
|
+
path_params["hostName"] = kwargs.pop("hostName")
|
|
154
|
+
if "repoName" in kwargs:
|
|
155
|
+
path_params["repoName"] = kwargs.pop("repoName")
|
|
156
|
+
|
|
157
|
+
# Add remaining kwargs as query parameters
|
|
158
|
+
query_params.update({k: v for k, v in kwargs.items() if v is not None})
|
|
159
|
+
|
|
160
|
+
return path_params, query_params
|
|
161
|
+
|
|
162
|
+
def _handle_host_repository_issue(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
163
|
+
"""Handle getHostRepositoryIssue operation parameters."""
|
|
164
|
+
path_params = {}
|
|
165
|
+
|
|
166
|
+
if len(args) >= 3:
|
|
167
|
+
path_params["hostName"] = args[0]
|
|
168
|
+
path_params["repoName"] = args[1]
|
|
169
|
+
path_params["issueNumber"] = args[2]
|
|
170
|
+
else:
|
|
171
|
+
if "hostName" in kwargs:
|
|
172
|
+
path_params["hostName"] = kwargs["hostName"]
|
|
173
|
+
if "repoName" in kwargs:
|
|
174
|
+
path_params["repoName"] = kwargs["repoName"]
|
|
175
|
+
if "issueNumber" in kwargs:
|
|
176
|
+
path_params["issueNumber"] = kwargs["issueNumber"]
|
|
177
|
+
|
|
178
|
+
return path_params, {}
|
|
179
|
+
|
|
180
|
+
def _handle_get_advisory(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
181
|
+
"""Handle getAdvisory operation parameters."""
|
|
182
|
+
path_params = {}
|
|
183
|
+
query_params = {}
|
|
184
|
+
|
|
185
|
+
advisory_id = args[0] if args else kwargs.pop("advisoryId", None)
|
|
186
|
+
if advisory_id:
|
|
187
|
+
path_params["advisoryId"] = advisory_id
|
|
188
|
+
|
|
189
|
+
# Add remaining kwargs as query parameters
|
|
190
|
+
query_params.update({k: v for k, v in kwargs.items() if v is not None})
|
|
191
|
+
|
|
192
|
+
return path_params, query_params
|
|
193
|
+
|
|
194
|
+
def _handle_query_params(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
195
|
+
"""Handle operations that only have query parameters."""
|
|
196
|
+
query_params = {k: v for k, v in kwargs.items() if v is not None}
|
|
197
|
+
return {}, query_params
|
|
198
|
+
|
|
199
|
+
def _handle_no_params(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
200
|
+
"""Handle operations with no parameters."""
|
|
201
|
+
return {}, {}
|
|
202
|
+
|
|
203
|
+
def _handle_default(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
204
|
+
"""Default handler for unknown operations."""
|
|
205
|
+
return {}, {}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Handler for diff API operations."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Tuple
|
|
4
|
+
|
|
5
|
+
from .base import OperationHandler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DiffOperationHandler(OperationHandler):
|
|
9
|
+
"""Handler for diff API operations.
|
|
10
|
+
|
|
11
|
+
Handles parameter mapping for diff API operations including:
|
|
12
|
+
- createJob: Submit diff job with two URLs to compare
|
|
13
|
+
- getJob: Get job status and results by job ID
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def build_params(self, operation_id: str, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
17
|
+
"""Build parameters for diff API operations.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
operation_id: The operation identifier
|
|
21
|
+
args: Positional arguments
|
|
22
|
+
kwargs: Keyword arguments
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Tuple of (path_params, query_params)
|
|
26
|
+
"""
|
|
27
|
+
handlers = {
|
|
28
|
+
"createJob": self._handle_create_job,
|
|
29
|
+
"getJob": self._handle_get_job,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
handler = handlers.get(operation_id, self._handle_default)
|
|
33
|
+
return handler(args, kwargs)
|
|
34
|
+
|
|
35
|
+
def _handle_create_job(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
36
|
+
"""Handle createJob operation parameters.
|
|
37
|
+
|
|
38
|
+
Requires two URLs to compare. Can be provided as:
|
|
39
|
+
- Positional arguments: diff create-job url1 url2
|
|
40
|
+
- Named arguments: diff create-job --url-1 url1 --url-2 url2
|
|
41
|
+
"""
|
|
42
|
+
query_params = {}
|
|
43
|
+
|
|
44
|
+
if len(args) >= 2:
|
|
45
|
+
query_params["url_1"] = args[0]
|
|
46
|
+
query_params["url_2"] = args[1]
|
|
47
|
+
else:
|
|
48
|
+
# Try to get from kwargs
|
|
49
|
+
url_1 = kwargs.get("url_1")
|
|
50
|
+
url_2 = kwargs.get("url_2")
|
|
51
|
+
|
|
52
|
+
if url_1:
|
|
53
|
+
query_params["url_1"] = url_1
|
|
54
|
+
if url_2:
|
|
55
|
+
query_params["url_2"] = url_2
|
|
56
|
+
|
|
57
|
+
# Note: API validation will handle missing required parameters
|
|
58
|
+
return {}, query_params
|
|
59
|
+
|
|
60
|
+
def _handle_get_job(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
61
|
+
"""Handle getJob operation parameters."""
|
|
62
|
+
path_params = {}
|
|
63
|
+
|
|
64
|
+
job_id = args[0] if args else kwargs.get("job_id")
|
|
65
|
+
if job_id:
|
|
66
|
+
path_params["jobID"] = job_id
|
|
67
|
+
|
|
68
|
+
return path_params, {}
|
|
69
|
+
|
|
70
|
+
def _handle_default(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
71
|
+
"""Default handler for unknown operations."""
|
|
72
|
+
return {}, {}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Handler for docker API operations."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Tuple
|
|
4
|
+
|
|
5
|
+
from .base import OperationHandler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DockerOperationHandler(OperationHandler):
|
|
9
|
+
"""Handler for docker API operations."""
|
|
10
|
+
|
|
11
|
+
def build_params(self, operation_id: str, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
12
|
+
"""Build parameters for docker API operations.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
operation_id: The operation identifier
|
|
16
|
+
args: Positional arguments
|
|
17
|
+
kwargs: Keyword arguments
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Tuple of (path_params, query_params)
|
|
21
|
+
"""
|
|
22
|
+
handlers = {
|
|
23
|
+
"getPackages": self._handle_query_params,
|
|
24
|
+
"getPackage": self._handle_get_package,
|
|
25
|
+
"getPackageVersions": self._handle_get_package_versions,
|
|
26
|
+
"getPackageVersion": self._handle_get_package_version,
|
|
27
|
+
"usage": self._handle_no_params,
|
|
28
|
+
"usageEcosystem": self._handle_usage_ecosystem,
|
|
29
|
+
"usagePackage": self._handle_usage_package,
|
|
30
|
+
"getDistros": self._handle_query_params,
|
|
31
|
+
"getDistro": self._handle_get_distro,
|
|
32
|
+
"getDistroVersions": self._handle_get_distro_versions,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
handler = handlers.get(operation_id, self._handle_default)
|
|
36
|
+
return handler(args, kwargs)
|
|
37
|
+
|
|
38
|
+
def _handle_get_package(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
39
|
+
"""Handle getPackage operation parameters."""
|
|
40
|
+
path_params = {}
|
|
41
|
+
|
|
42
|
+
# Click normalizes parameter names to lowercase, so check both
|
|
43
|
+
package_name = args[0] if args else (kwargs.get("packageName") or kwargs.get("packagename"))
|
|
44
|
+
if package_name:
|
|
45
|
+
path_params["packageName"] = package_name
|
|
46
|
+
|
|
47
|
+
return path_params, {}
|
|
48
|
+
|
|
49
|
+
def _handle_get_package_versions(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
50
|
+
"""Handle getPackageVersions operation parameters."""
|
|
51
|
+
path_params = {}
|
|
52
|
+
query_params = {}
|
|
53
|
+
|
|
54
|
+
# Click normalizes parameter names to lowercase
|
|
55
|
+
package_name = args[0] if args else (kwargs.pop("packageName", None) or kwargs.pop("packagename", None))
|
|
56
|
+
if package_name:
|
|
57
|
+
path_params["packageName"] = package_name
|
|
58
|
+
|
|
59
|
+
# Add remaining kwargs as query parameters
|
|
60
|
+
query_params.update({k: v for k, v in kwargs.items() if v is not None})
|
|
61
|
+
|
|
62
|
+
return path_params, query_params
|
|
63
|
+
|
|
64
|
+
def _handle_get_package_version(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
65
|
+
"""Handle getPackageVersion operation parameters."""
|
|
66
|
+
path_params = {}
|
|
67
|
+
|
|
68
|
+
if len(args) >= 2:
|
|
69
|
+
path_params["packageName"] = args[0]
|
|
70
|
+
path_params["versionNumber"] = args[1]
|
|
71
|
+
else:
|
|
72
|
+
# Click normalizes parameter names to lowercase
|
|
73
|
+
if "packageName" in kwargs or "packagename" in kwargs:
|
|
74
|
+
path_params["packageName"] = kwargs.get("packageName") or kwargs.get("packagename")
|
|
75
|
+
if "versionNumber" in kwargs or "versionnumber" in kwargs:
|
|
76
|
+
path_params["versionNumber"] = kwargs.get("versionNumber") or kwargs.get("versionnumber")
|
|
77
|
+
|
|
78
|
+
return path_params, {}
|
|
79
|
+
|
|
80
|
+
def _handle_usage_ecosystem(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
81
|
+
"""Handle usageEcosystem operation parameters."""
|
|
82
|
+
path_params = {}
|
|
83
|
+
|
|
84
|
+
ecosystem = args[0] if args else kwargs.get("ecosystem")
|
|
85
|
+
if ecosystem:
|
|
86
|
+
path_params["ecosystem"] = ecosystem
|
|
87
|
+
|
|
88
|
+
return path_params, {}
|
|
89
|
+
|
|
90
|
+
def _handle_usage_package(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
91
|
+
"""Handle usagePackage operation parameters."""
|
|
92
|
+
path_params = {}
|
|
93
|
+
|
|
94
|
+
if len(args) >= 2:
|
|
95
|
+
path_params["ecosystem"] = args[0]
|
|
96
|
+
path_params["package"] = args[1]
|
|
97
|
+
else:
|
|
98
|
+
if "ecosystem" in kwargs:
|
|
99
|
+
path_params["ecosystem"] = kwargs["ecosystem"]
|
|
100
|
+
if "package" in kwargs:
|
|
101
|
+
path_params["package"] = kwargs["package"]
|
|
102
|
+
|
|
103
|
+
return path_params, {}
|
|
104
|
+
|
|
105
|
+
def _handle_get_distro(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
106
|
+
"""Handle getDistro operation parameters."""
|
|
107
|
+
path_params = {}
|
|
108
|
+
|
|
109
|
+
# Click normalizes parameter names to lowercase, so check both
|
|
110
|
+
slug = args[0] if args else (kwargs.get("slug"))
|
|
111
|
+
if slug:
|
|
112
|
+
path_params["slug"] = slug
|
|
113
|
+
|
|
114
|
+
return path_params, {}
|
|
115
|
+
|
|
116
|
+
def _handle_get_distro_versions(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
117
|
+
"""Handle getDistroVersions operation parameters."""
|
|
118
|
+
path_params = {}
|
|
119
|
+
query_params = {}
|
|
120
|
+
|
|
121
|
+
# Click normalizes parameter names to lowercase
|
|
122
|
+
slug = args[0] if args else kwargs.pop("slug", None)
|
|
123
|
+
if slug:
|
|
124
|
+
path_params["slug"] = slug
|
|
125
|
+
|
|
126
|
+
# Add remaining kwargs as query parameters
|
|
127
|
+
query_params.update({k: v for k, v in kwargs.items() if v is not None})
|
|
128
|
+
|
|
129
|
+
return path_params, query_params
|
|
130
|
+
|
|
131
|
+
def _handle_query_params(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
132
|
+
"""Handle operations that only have query parameters."""
|
|
133
|
+
query_params = {k: v for k, v in kwargs.items() if v is not None}
|
|
134
|
+
return {}, query_params
|
|
135
|
+
|
|
136
|
+
def _handle_no_params(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
137
|
+
"""Handle operations with no parameters."""
|
|
138
|
+
return {}, {}
|
|
139
|
+
|
|
140
|
+
def _handle_default(self, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
141
|
+
"""Default handler for unknown operations."""
|
|
142
|
+
return {}, {}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Factory for creating operation handlers."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Type
|
|
4
|
+
|
|
5
|
+
from .advisories import AdvisoriesOperationHandler
|
|
6
|
+
from .archives import ArchivesOperationHandler
|
|
7
|
+
from .base import OperationHandler
|
|
8
|
+
from .commits import CommitsOperationHandler
|
|
9
|
+
from .default import DefaultOperationHandler
|
|
10
|
+
from .dependabot import DependabotOperationHandler
|
|
11
|
+
from .diff import DiffOperationHandler
|
|
12
|
+
from .docker import DockerOperationHandler
|
|
13
|
+
from .issues import IssuesOperationHandler
|
|
14
|
+
from .licenses import LicensesOperationHandler
|
|
15
|
+
from .opencollective import OpenCollectiveOperationHandler
|
|
16
|
+
from .packages import PackagesOperationHandler
|
|
17
|
+
from .parser import ParserOperationHandler
|
|
18
|
+
from .repos import ReposOperationHandler
|
|
19
|
+
from .resolve import ResolveOperationHandler
|
|
20
|
+
from .sbom import SbomOperationHandler
|
|
21
|
+
from .sponsors import SponsorsOperationHandler
|
|
22
|
+
from .summary import SummaryOperationHandler
|
|
23
|
+
from .timeline import TimelineOperationHandler
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class OperationHandlerFactory:
|
|
27
|
+
"""Factory for creating operation handlers."""
|
|
28
|
+
|
|
29
|
+
_handlers: Dict[str, Type[OperationHandler]] = {
|
|
30
|
+
"advisories": AdvisoriesOperationHandler,
|
|
31
|
+
"archives": ArchivesOperationHandler,
|
|
32
|
+
"commits": CommitsOperationHandler,
|
|
33
|
+
"dependabot": DependabotOperationHandler,
|
|
34
|
+
"diff": DiffOperationHandler,
|
|
35
|
+
"docker": DockerOperationHandler,
|
|
36
|
+
"issues": IssuesOperationHandler,
|
|
37
|
+
"licenses": LicensesOperationHandler,
|
|
38
|
+
"opencollective": OpenCollectiveOperationHandler,
|
|
39
|
+
"packages": PackagesOperationHandler,
|
|
40
|
+
"parser": ParserOperationHandler,
|
|
41
|
+
"repos": ReposOperationHandler,
|
|
42
|
+
"resolve": ResolveOperationHandler,
|
|
43
|
+
"sbom": SbomOperationHandler,
|
|
44
|
+
"sponsors": SponsorsOperationHandler,
|
|
45
|
+
"summary": SummaryOperationHandler,
|
|
46
|
+
"timeline": TimelineOperationHandler,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def get_handler(cls, api_name: str) -> OperationHandler:
|
|
51
|
+
"""Get the appropriate handler for an API.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
api_name: Name of the API
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
OperationHandler instance for the API
|
|
58
|
+
"""
|
|
59
|
+
handler_class = cls._handlers.get(api_name, DefaultOperationHandler)
|
|
60
|
+
return handler_class()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Handler for issues API operations."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
4
|
+
|
|
5
|
+
from .base import OperationHandler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class IssuesOperationHandler(OperationHandler):
|
|
9
|
+
"""Handler for issues API operations."""
|
|
10
|
+
|
|
11
|
+
# Operation parameter configuration
|
|
12
|
+
# Maps operation_id -> list of (api_param_name, lowercase_variants)
|
|
13
|
+
OPERATION_PARAMS = {
|
|
14
|
+
"getHost": [("hostName", ["hostname"])],
|
|
15
|
+
"getHostRepositories": [("hostName", ["hostname"])],
|
|
16
|
+
"getHostRepository": [("hostName", ["hostname"]), ("repoName", ["reponame"])],
|
|
17
|
+
"getHostRepositoryIssues": [("hostName", ["hostname"]), ("repoName", ["reponame"])],
|
|
18
|
+
"getHostRepositoryIssue": [
|
|
19
|
+
("hostName", ["hostname"]),
|
|
20
|
+
("repoName", ["reponame"]),
|
|
21
|
+
("issueNumber", ["issuenumber", "issue_number"]),
|
|
22
|
+
],
|
|
23
|
+
"getHostRepositoryLabels": [("hostName", ["hostname"]), ("repoName", ["reponame"])],
|
|
24
|
+
"getHostOwners": [("hostName", ["hostname"])],
|
|
25
|
+
"getHostOwner": [("hostName", ["hostname"]), ("ownerName", ["ownername"])],
|
|
26
|
+
"getHostOwnerMaintainers": [("hostName", ["hostname"]), ("ownerName", ["ownername"])],
|
|
27
|
+
"getHostAuthors": [("hostName", ["hostname"])],
|
|
28
|
+
"getHostAuthor": [("hostName", ["hostname"]), ("authorName", ["authorname"])],
|
|
29
|
+
"getJob": [("jobId", ["jobid"])],
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
def _extract_param(self, kwargs: dict, api_name: str, lowercase_variants: List[str]) -> Optional[str]:
|
|
33
|
+
"""Extract parameter from kwargs, trying API name first, then lowercase variants.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
kwargs: Keyword arguments dict
|
|
37
|
+
api_name: The API parameter name (exact case)
|
|
38
|
+
lowercase_variants: List of lowercase parameter name variants to try
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Parameter value if found, None otherwise
|
|
42
|
+
"""
|
|
43
|
+
# Try exact API name first
|
|
44
|
+
if api_name in kwargs:
|
|
45
|
+
return kwargs.pop(api_name)
|
|
46
|
+
|
|
47
|
+
# Try lowercase variants
|
|
48
|
+
for variant in lowercase_variants:
|
|
49
|
+
if variant in kwargs:
|
|
50
|
+
return kwargs.pop(variant)
|
|
51
|
+
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
def build_params(self, operation_id: str, args: tuple, kwargs: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
55
|
+
"""Build parameters for issues API operations.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
operation_id: The operation identifier
|
|
59
|
+
args: Positional arguments
|
|
60
|
+
kwargs: Keyword arguments
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Tuple of (path_params, query_params)
|
|
64
|
+
"""
|
|
65
|
+
path_params = {}
|
|
66
|
+
query_params = {}
|
|
67
|
+
|
|
68
|
+
# Get parameter configuration for this operation
|
|
69
|
+
param_config = self.OPERATION_PARAMS.get(operation_id, [])
|
|
70
|
+
|
|
71
|
+
# Extract path parameters from args or kwargs
|
|
72
|
+
for i, (api_name, lowercase_variants) in enumerate(param_config):
|
|
73
|
+
if i < len(args):
|
|
74
|
+
# Use positional argument
|
|
75
|
+
path_params[api_name] = args[i]
|
|
76
|
+
else:
|
|
77
|
+
# Try to extract from kwargs
|
|
78
|
+
value = self._extract_param(kwargs, api_name, lowercase_variants)
|
|
79
|
+
if value is not None:
|
|
80
|
+
path_params[api_name] = value
|
|
81
|
+
|
|
82
|
+
# For all operations, remaining kwargs are query parameters
|
|
83
|
+
for key, value in kwargs.items():
|
|
84
|
+
if value is not None:
|
|
85
|
+
query_params[key] = value
|
|
86
|
+
|
|
87
|
+
return path_params, query_params
|