entropy-data 0.3.1__tar.gz → 0.3.2__tar.gz
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.
- {entropy_data-0.3.1 → entropy_data-0.3.2}/CHANGELOG.md +4 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/PKG-INFO +1 -1
- {entropy_data-0.3.1 → entropy_data-0.3.2}/pyproject.toml +1 -1
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/client.py +53 -3
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/datacontracts.py +9 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/dataproducts.py +9 -0
- entropy_data-0.3.2/src/entropy_data/commands/gitconnections.py +183 -0
- entropy_data-0.3.2/tests/commands/test_gitconnections.py +255 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/.editorconfig +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/.github/dependabot.yml +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/.github/pull_request_template.md +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/.github/workflows/ci.yaml +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/.github/workflows/release.yaml +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/.gitignore +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/.pre-commit-config.yaml +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/CLAUDE.md +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/Dockerfile +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/LICENSE +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/README.md +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/release +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/__init__.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/__main__.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/cli.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/__init__.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/access.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/api_keys.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/assets.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/certifications.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/connection.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/costs.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/definitions.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/events.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/example_data.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/import_export.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/lineage.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/search.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/settings.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/sourcesystems.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/tags.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/teams.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/test_results.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/commands/usage.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/config.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/output.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/src/entropy_data/util.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/__init__.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/__init__.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/test_api_keys.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/test_assets.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/test_connection.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/test_costs.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/test_lineage.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/test_settings.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/test_tags.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/test_teams.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/commands/test_usage.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/conftest.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/test_client.py +0 -0
- {entropy_data-0.3.1 → entropy_data-0.3.2}/tests/test_config.py +0 -0
|
@@ -121,12 +121,15 @@ class EntropyDataClient:
|
|
|
121
121
|
_raise_for_status(response)
|
|
122
122
|
return response.headers.get(RESPONSE_HEADER_LOCATION_HTML)
|
|
123
123
|
|
|
124
|
-
def post_action_json(
|
|
125
|
-
|
|
124
|
+
def post_action_json(
|
|
125
|
+
self, path: str, resource_id: str, action: str, params: dict | None = None, timeout: int = REQUEST_TIMEOUT
|
|
126
|
+
) -> dict:
|
|
126
127
|
"""POST /api/{path}/{id}/{action} with query params. Returns response JSON."""
|
|
127
128
|
_validate_resource_id(resource_id)
|
|
128
129
|
response = self.session.post(
|
|
129
|
-
f"{self.base_url}/api/{path}/{resource_id}/{action}",
|
|
130
|
+
f"{self.base_url}/api/{path}/{resource_id}/{action}",
|
|
131
|
+
params=params,
|
|
132
|
+
timeout=timeout,
|
|
130
133
|
)
|
|
131
134
|
_raise_for_status(response)
|
|
132
135
|
return response.json()
|
|
@@ -155,6 +158,53 @@ class EntropyDataClient:
|
|
|
155
158
|
_raise_for_status(response)
|
|
156
159
|
return response.json()
|
|
157
160
|
|
|
161
|
+
def get_gitconnection(self, path: str, resource_id: str) -> dict:
|
|
162
|
+
"""GET /api/{path}/{id}/gitconnection."""
|
|
163
|
+
_validate_resource_id(resource_id)
|
|
164
|
+
response = self.session.get(
|
|
165
|
+
f"{self.base_url}/api/{path}/{resource_id}/gitconnection",
|
|
166
|
+
timeout=REQUEST_TIMEOUT,
|
|
167
|
+
)
|
|
168
|
+
_raise_for_status(response)
|
|
169
|
+
return response.json()
|
|
170
|
+
|
|
171
|
+
def put_gitconnection(self, path: str, resource_id: str, body: dict) -> dict:
|
|
172
|
+
"""PUT /api/{path}/{id}/gitconnection."""
|
|
173
|
+
_validate_resource_id(resource_id)
|
|
174
|
+
response = self.session.put(
|
|
175
|
+
f"{self.base_url}/api/{path}/{resource_id}/gitconnection",
|
|
176
|
+
json=body,
|
|
177
|
+
timeout=REQUEST_TIMEOUT,
|
|
178
|
+
)
|
|
179
|
+
_raise_for_status(response)
|
|
180
|
+
return response.json()
|
|
181
|
+
|
|
182
|
+
def delete_gitconnection(self, path: str, resource_id: str) -> None:
|
|
183
|
+
"""DELETE /api/{path}/{id}/gitconnection."""
|
|
184
|
+
_validate_resource_id(resource_id)
|
|
185
|
+
response = self.session.delete(
|
|
186
|
+
f"{self.base_url}/api/{path}/{resource_id}/gitconnection",
|
|
187
|
+
timeout=REQUEST_TIMEOUT,
|
|
188
|
+
)
|
|
189
|
+
_raise_for_status(response)
|
|
190
|
+
|
|
191
|
+
def gitconnection_action(
|
|
192
|
+
self,
|
|
193
|
+
path: str,
|
|
194
|
+
resource_id: str,
|
|
195
|
+
action: str,
|
|
196
|
+
body: dict | None = None,
|
|
197
|
+
) -> dict:
|
|
198
|
+
"""POST /api/{path}/{id}/gitconnection/{action}. action ∈ {pull, push, push-pr}."""
|
|
199
|
+
_validate_resource_id(resource_id)
|
|
200
|
+
response = self.session.post(
|
|
201
|
+
f"{self.base_url}/api/{path}/{resource_id}/gitconnection/{action}",
|
|
202
|
+
json=body if body is not None else None,
|
|
203
|
+
timeout=REQUEST_TIMEOUT,
|
|
204
|
+
)
|
|
205
|
+
_raise_for_status(response)
|
|
206
|
+
return response.json()
|
|
207
|
+
|
|
158
208
|
def search(self, query: str, **params) -> dict:
|
|
159
209
|
"""GET /api/search."""
|
|
160
210
|
params["query"] = query
|
|
@@ -113,3 +113,12 @@ def delete_datacontract(
|
|
|
113
113
|
print_success(f"Data contract '{id}' deleted.")
|
|
114
114
|
except Exception as e:
|
|
115
115
|
handle_error(e)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
from entropy_data.commands.gitconnections import make_gitconnection_app # noqa: E402
|
|
119
|
+
|
|
120
|
+
datacontracts_app.add_typer(
|
|
121
|
+
make_gitconnection_app(RESOURCE_PATH, "Data contract"),
|
|
122
|
+
name="gitconnection",
|
|
123
|
+
help="Manage the git connection.",
|
|
124
|
+
)
|
|
@@ -91,3 +91,12 @@ def delete_dataproduct(
|
|
|
91
91
|
print_success(f"Data product '{id}' deleted.")
|
|
92
92
|
except Exception as e:
|
|
93
93
|
handle_error(e)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
from entropy_data.commands.gitconnections import make_gitconnection_app # noqa: E402
|
|
97
|
+
|
|
98
|
+
dataproducts_app.add_typer(
|
|
99
|
+
make_gitconnection_app(RESOURCE_PATH, "Data product"),
|
|
100
|
+
name="gitconnection",
|
|
101
|
+
help="Manage the git connection.",
|
|
102
|
+
)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Git connection subcommands. Used as a sub-typer of dataproducts and datacontracts."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Annotated, Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from entropy_data.output import OutputFormat, print_link, print_success
|
|
9
|
+
|
|
10
|
+
GIT_CONNECTION_TYPES = ("github", "gitlab", "bitbucket", "azuredevops")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def make_gitconnection_app(resource_path: str, resource_label: str) -> typer.Typer:
|
|
14
|
+
"""Build a Typer app exposing /api/{resource_path}/{id}/gitconnection operations.
|
|
15
|
+
|
|
16
|
+
`resource_path` is the URL segment ("dataproducts" or "datacontracts").
|
|
17
|
+
`resource_label` is the human-readable name shown in success messages.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
app = typer.Typer(no_args_is_help=True)
|
|
21
|
+
|
|
22
|
+
@app.command("get")
|
|
23
|
+
def get_(
|
|
24
|
+
id: Annotated[str, typer.Argument(help=f"{resource_label} ID.")],
|
|
25
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Get the git connection."""
|
|
28
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
29
|
+
|
|
30
|
+
fmt = output or get_output_format()
|
|
31
|
+
try:
|
|
32
|
+
client = get_client()
|
|
33
|
+
data = client.get_gitconnection(resource_path, id)
|
|
34
|
+
if fmt == OutputFormat.json:
|
|
35
|
+
print(json.dumps(data, indent=2))
|
|
36
|
+
else:
|
|
37
|
+
print(json.dumps(data, indent=2))
|
|
38
|
+
except Exception as e:
|
|
39
|
+
handle_error(e)
|
|
40
|
+
|
|
41
|
+
@app.command("put")
|
|
42
|
+
def put_(
|
|
43
|
+
id: Annotated[str, typer.Argument(help=f"{resource_label} ID.")],
|
|
44
|
+
repository_url: Annotated[str, typer.Option("--repository-url", help="URL of the Git repository.")] = ...,
|
|
45
|
+
repository_path: Annotated[
|
|
46
|
+
str, typer.Option("--repository-path", help="Path to the YAML file in the repository.")
|
|
47
|
+
] = ...,
|
|
48
|
+
repository_branch: Annotated[
|
|
49
|
+
Optional[str],
|
|
50
|
+
typer.Option("--repository-branch", help="Branch to use. Defaults to 'main'."),
|
|
51
|
+
] = None,
|
|
52
|
+
git_connection_type: Annotated[
|
|
53
|
+
Optional[str],
|
|
54
|
+
typer.Option(
|
|
55
|
+
"--git-connection-type",
|
|
56
|
+
help=f"Git provider type. One of: {', '.join(GIT_CONNECTION_TYPES)}.",
|
|
57
|
+
),
|
|
58
|
+
] = None,
|
|
59
|
+
host: Annotated[
|
|
60
|
+
Optional[str],
|
|
61
|
+
typer.Option("--host", help="Host of a self-hosted git provider. Omit for SaaS."),
|
|
62
|
+
] = None,
|
|
63
|
+
git_credential_external_id: Annotated[
|
|
64
|
+
Optional[str],
|
|
65
|
+
typer.Option(
|
|
66
|
+
"--git-credential-external-id",
|
|
67
|
+
help="External ID of a stored git credential to use.",
|
|
68
|
+
),
|
|
69
|
+
] = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
"""Create or update the git connection."""
|
|
72
|
+
from entropy_data.cli import get_client, handle_error
|
|
73
|
+
|
|
74
|
+
if git_connection_type and git_connection_type not in GIT_CONNECTION_TYPES:
|
|
75
|
+
raise typer.BadParameter(
|
|
76
|
+
f"Must be one of: {', '.join(GIT_CONNECTION_TYPES)}",
|
|
77
|
+
param_hint="--git-connection-type",
|
|
78
|
+
)
|
|
79
|
+
if not git_connection_type and not git_credential_external_id:
|
|
80
|
+
raise typer.BadParameter(
|
|
81
|
+
"At least one of --git-connection-type or --git-credential-external-id must be provided.",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
body: dict = {"repositoryUrl": repository_url, "repositoryPath": repository_path}
|
|
85
|
+
if repository_branch:
|
|
86
|
+
body["repositoryBranch"] = repository_branch
|
|
87
|
+
if git_connection_type:
|
|
88
|
+
body["gitConnectionType"] = git_connection_type
|
|
89
|
+
if host:
|
|
90
|
+
body["host"] = host
|
|
91
|
+
if git_credential_external_id:
|
|
92
|
+
body["gitCredentialExternalId"] = git_credential_external_id
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
client = get_client()
|
|
96
|
+
data = client.put_gitconnection(resource_path, id, body)
|
|
97
|
+
print_success(f"Git connection saved for {resource_label.lower()} '{id}'.")
|
|
98
|
+
print_link(data.get("webLink"))
|
|
99
|
+
except Exception as e:
|
|
100
|
+
handle_error(e)
|
|
101
|
+
|
|
102
|
+
@app.command("delete")
|
|
103
|
+
def delete_(
|
|
104
|
+
id: Annotated[str, typer.Argument(help=f"{resource_label} ID.")],
|
|
105
|
+
) -> None:
|
|
106
|
+
"""Delete the git connection."""
|
|
107
|
+
from entropy_data.cli import get_client, handle_error
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
client = get_client()
|
|
111
|
+
client.delete_gitconnection(resource_path, id)
|
|
112
|
+
print_success(f"Git connection deleted for {resource_label.lower()} '{id}'.")
|
|
113
|
+
except Exception as e:
|
|
114
|
+
handle_error(e)
|
|
115
|
+
|
|
116
|
+
@app.command("pull")
|
|
117
|
+
def pull_(
|
|
118
|
+
id: Annotated[str, typer.Argument(help=f"{resource_label} ID.")],
|
|
119
|
+
) -> None:
|
|
120
|
+
"""Pull the file from Git into Entropy Data."""
|
|
121
|
+
from entropy_data.cli import get_client, handle_error
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
client = get_client()
|
|
125
|
+
data = client.gitconnection_action(resource_path, id, "pull")
|
|
126
|
+
print_success(f"{resource_label} '{id}' pulled from Git.")
|
|
127
|
+
print_link(data.get("webLink"))
|
|
128
|
+
except Exception as e:
|
|
129
|
+
handle_error(e)
|
|
130
|
+
|
|
131
|
+
@app.command("push")
|
|
132
|
+
def push_(
|
|
133
|
+
id: Annotated[str, typer.Argument(help=f"{resource_label} ID.")],
|
|
134
|
+
commit_message: Annotated[
|
|
135
|
+
Optional[str], typer.Option("--commit-message", help="Custom commit message.")
|
|
136
|
+
] = None,
|
|
137
|
+
) -> None:
|
|
138
|
+
"""Push the current Entropy Data file to Git."""
|
|
139
|
+
from entropy_data.cli import get_client, handle_error
|
|
140
|
+
|
|
141
|
+
body: dict | None = {"commitMessage": commit_message} if commit_message else None
|
|
142
|
+
try:
|
|
143
|
+
client = get_client()
|
|
144
|
+
data = client.gitconnection_action(resource_path, id, "push", body)
|
|
145
|
+
print_success(f"{resource_label} '{id}' pushed to Git.")
|
|
146
|
+
print_link(data.get("webLink"))
|
|
147
|
+
except Exception as e:
|
|
148
|
+
handle_error(e)
|
|
149
|
+
|
|
150
|
+
@app.command("push-pr")
|
|
151
|
+
def push_pr(
|
|
152
|
+
id: Annotated[str, typer.Argument(help=f"{resource_label} ID.")],
|
|
153
|
+
commit_message: Annotated[
|
|
154
|
+
Optional[str], typer.Option("--commit-message", help="Custom commit message.")
|
|
155
|
+
] = None,
|
|
156
|
+
branch_name: Annotated[Optional[str], typer.Option("--branch-name", help="Name of the new branch.")] = None,
|
|
157
|
+
title: Annotated[Optional[str], typer.Option("--title", help="Pull request title.")] = None,
|
|
158
|
+
comment: Annotated[
|
|
159
|
+
Optional[str],
|
|
160
|
+
typer.Option("--comment", help="Pull request description / comment."),
|
|
161
|
+
] = None,
|
|
162
|
+
) -> None:
|
|
163
|
+
"""Push the current Entropy Data file to Git as a pull/merge request."""
|
|
164
|
+
from entropy_data.cli import get_client, handle_error
|
|
165
|
+
|
|
166
|
+
body: dict = {}
|
|
167
|
+
if commit_message:
|
|
168
|
+
body["commitMessage"] = commit_message
|
|
169
|
+
if branch_name:
|
|
170
|
+
body["branchName"] = branch_name
|
|
171
|
+
if title:
|
|
172
|
+
body["title"] = title
|
|
173
|
+
if comment:
|
|
174
|
+
body["comment"] = comment
|
|
175
|
+
try:
|
|
176
|
+
client = get_client()
|
|
177
|
+
data = client.gitconnection_action(resource_path, id, "push-pr", body or None)
|
|
178
|
+
print_success(f"{resource_label} '{id}' pushed to Git as pull request.")
|
|
179
|
+
print_link(data.get("webLink"))
|
|
180
|
+
except Exception as e:
|
|
181
|
+
handle_error(e)
|
|
182
|
+
|
|
183
|
+
return app
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""Tests for git connection subcommands on dataproducts and datacontracts."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
import responses
|
|
7
|
+
from typer.testing import CliRunner
|
|
8
|
+
|
|
9
|
+
import entropy_data.config as cfg
|
|
10
|
+
from entropy_data.cli import app
|
|
11
|
+
|
|
12
|
+
runner = CliRunner()
|
|
13
|
+
BASE_URL = "https://api.entropy-data.com"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
CONNECTION_RESPONSE = {
|
|
17
|
+
"gitConnectionId": "11111111-1111-1111-1111-111111111111",
|
|
18
|
+
"gitConnectionType": "github",
|
|
19
|
+
"repositoryUrl": "https://github.com/acme/contracts",
|
|
20
|
+
"repositoryBranch": "main",
|
|
21
|
+
"repositoryPath": "contracts/orders.yaml",
|
|
22
|
+
"syncStatus": "UP_TO_DATE",
|
|
23
|
+
"webLink": "https://github.com/acme/contracts/blob/main/contracts/orders.yaml",
|
|
24
|
+
"lastHash": "abc123",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.fixture
|
|
29
|
+
def configured(monkeypatch, tmp_path):
|
|
30
|
+
monkeypatch.setattr(cfg, "CONFIG_FILE", tmp_path / "config.toml")
|
|
31
|
+
monkeypatch.setenv("ENTROPY_DATA_API_KEY", "test-key")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.mark.parametrize("resource", ["dataproducts", "datacontracts"])
|
|
35
|
+
@responses.activate
|
|
36
|
+
def test_gitconnection_get(configured, resource):
|
|
37
|
+
responses.add(
|
|
38
|
+
responses.GET,
|
|
39
|
+
f"{BASE_URL}/api/{resource}/orders/gitconnection",
|
|
40
|
+
json=CONNECTION_RESPONSE,
|
|
41
|
+
status=200,
|
|
42
|
+
)
|
|
43
|
+
result = runner.invoke(app, [resource, "gitconnection", "get", "orders"])
|
|
44
|
+
assert result.exit_code == 0
|
|
45
|
+
assert "github.com/acme/contracts" in result.output
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@pytest.mark.parametrize("resource", ["dataproducts", "datacontracts"])
|
|
49
|
+
@responses.activate
|
|
50
|
+
def test_gitconnection_put(configured, resource):
|
|
51
|
+
responses.add(
|
|
52
|
+
responses.PUT,
|
|
53
|
+
f"{BASE_URL}/api/{resource}/orders/gitconnection",
|
|
54
|
+
json=CONNECTION_RESPONSE,
|
|
55
|
+
status=200,
|
|
56
|
+
)
|
|
57
|
+
result = runner.invoke(
|
|
58
|
+
app,
|
|
59
|
+
[
|
|
60
|
+
resource,
|
|
61
|
+
"gitconnection",
|
|
62
|
+
"put",
|
|
63
|
+
"orders",
|
|
64
|
+
"--repository-url",
|
|
65
|
+
"https://github.com/acme/contracts",
|
|
66
|
+
"--repository-path",
|
|
67
|
+
"contracts/orders.yaml",
|
|
68
|
+
"--git-connection-type",
|
|
69
|
+
"github",
|
|
70
|
+
],
|
|
71
|
+
)
|
|
72
|
+
assert result.exit_code == 0
|
|
73
|
+
assert "saved" in result.output
|
|
74
|
+
sent = json.loads(responses.calls[-1].request.body)
|
|
75
|
+
assert sent["repositoryUrl"] == "https://github.com/acme/contracts"
|
|
76
|
+
assert sent["repositoryPath"] == "contracts/orders.yaml"
|
|
77
|
+
assert sent["gitConnectionType"] == "github"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_gitconnection_put_requires_credential_or_type(configured):
|
|
81
|
+
result = runner.invoke(
|
|
82
|
+
app,
|
|
83
|
+
[
|
|
84
|
+
"dataproducts",
|
|
85
|
+
"gitconnection",
|
|
86
|
+
"put",
|
|
87
|
+
"orders",
|
|
88
|
+
"--repository-url",
|
|
89
|
+
"https://github.com/acme/contracts",
|
|
90
|
+
"--repository-path",
|
|
91
|
+
"contracts/orders.yaml",
|
|
92
|
+
],
|
|
93
|
+
)
|
|
94
|
+
assert result.exit_code != 0
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_gitconnection_put_rejects_invalid_type(configured):
|
|
98
|
+
result = runner.invoke(
|
|
99
|
+
app,
|
|
100
|
+
[
|
|
101
|
+
"dataproducts",
|
|
102
|
+
"gitconnection",
|
|
103
|
+
"put",
|
|
104
|
+
"orders",
|
|
105
|
+
"--repository-url",
|
|
106
|
+
"https://github.com/acme/contracts",
|
|
107
|
+
"--repository-path",
|
|
108
|
+
"contracts/orders.yaml",
|
|
109
|
+
"--git-connection-type",
|
|
110
|
+
"svn",
|
|
111
|
+
],
|
|
112
|
+
)
|
|
113
|
+
assert result.exit_code != 0
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@pytest.mark.parametrize("resource", ["dataproducts", "datacontracts"])
|
|
117
|
+
@responses.activate
|
|
118
|
+
def test_gitconnection_put_with_credential_external_id(configured, resource):
|
|
119
|
+
responses.add(
|
|
120
|
+
responses.PUT,
|
|
121
|
+
f"{BASE_URL}/api/{resource}/orders/gitconnection",
|
|
122
|
+
json=CONNECTION_RESPONSE,
|
|
123
|
+
status=200,
|
|
124
|
+
)
|
|
125
|
+
result = runner.invoke(
|
|
126
|
+
app,
|
|
127
|
+
[
|
|
128
|
+
resource,
|
|
129
|
+
"gitconnection",
|
|
130
|
+
"put",
|
|
131
|
+
"orders",
|
|
132
|
+
"--repository-url",
|
|
133
|
+
"https://github.com/acme/contracts",
|
|
134
|
+
"--repository-path",
|
|
135
|
+
"contracts/orders.yaml",
|
|
136
|
+
"--git-credential-external-id",
|
|
137
|
+
"acme-ci",
|
|
138
|
+
],
|
|
139
|
+
)
|
|
140
|
+
assert result.exit_code == 0
|
|
141
|
+
sent = json.loads(responses.calls[-1].request.body)
|
|
142
|
+
assert sent["gitCredentialExternalId"] == "acme-ci"
|
|
143
|
+
assert "gitConnectionType" not in sent
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@pytest.mark.parametrize("resource", ["dataproducts", "datacontracts"])
|
|
147
|
+
@responses.activate
|
|
148
|
+
def test_gitconnection_delete(configured, resource):
|
|
149
|
+
responses.add(
|
|
150
|
+
responses.DELETE,
|
|
151
|
+
f"{BASE_URL}/api/{resource}/orders/gitconnection",
|
|
152
|
+
status=200,
|
|
153
|
+
)
|
|
154
|
+
result = runner.invoke(app, [resource, "gitconnection", "delete", "orders"])
|
|
155
|
+
assert result.exit_code == 0
|
|
156
|
+
assert "deleted" in result.output
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@pytest.mark.parametrize("resource", ["dataproducts", "datacontracts"])
|
|
160
|
+
@responses.activate
|
|
161
|
+
def test_gitconnection_pull(configured, resource):
|
|
162
|
+
responses.add(
|
|
163
|
+
responses.POST,
|
|
164
|
+
f"{BASE_URL}/api/{resource}/orders/gitconnection/pull",
|
|
165
|
+
json=CONNECTION_RESPONSE,
|
|
166
|
+
status=200,
|
|
167
|
+
)
|
|
168
|
+
result = runner.invoke(app, [resource, "gitconnection", "pull", "orders"])
|
|
169
|
+
assert result.exit_code == 0
|
|
170
|
+
assert "pulled" in result.output
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@pytest.mark.parametrize("resource", ["dataproducts", "datacontracts"])
|
|
174
|
+
@responses.activate
|
|
175
|
+
def test_gitconnection_push(configured, resource):
|
|
176
|
+
responses.add(
|
|
177
|
+
responses.POST,
|
|
178
|
+
f"{BASE_URL}/api/{resource}/orders/gitconnection/push",
|
|
179
|
+
json=CONNECTION_RESPONSE,
|
|
180
|
+
status=200,
|
|
181
|
+
)
|
|
182
|
+
result = runner.invoke(
|
|
183
|
+
app,
|
|
184
|
+
[resource, "gitconnection", "push", "orders", "--commit-message", "update orders"],
|
|
185
|
+
)
|
|
186
|
+
assert result.exit_code == 0
|
|
187
|
+
assert "pushed" in result.output
|
|
188
|
+
sent = json.loads(responses.calls[-1].request.body)
|
|
189
|
+
assert sent["commitMessage"] == "update orders"
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@pytest.mark.parametrize("resource", ["dataproducts", "datacontracts"])
|
|
193
|
+
@responses.activate
|
|
194
|
+
def test_gitconnection_push_no_body(configured, resource):
|
|
195
|
+
responses.add(
|
|
196
|
+
responses.POST,
|
|
197
|
+
f"{BASE_URL}/api/{resource}/orders/gitconnection/push",
|
|
198
|
+
json=CONNECTION_RESPONSE,
|
|
199
|
+
status=200,
|
|
200
|
+
)
|
|
201
|
+
result = runner.invoke(app, [resource, "gitconnection", "push", "orders"])
|
|
202
|
+
assert result.exit_code == 0
|
|
203
|
+
assert responses.calls[-1].request.body in (None, b"null", "null")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@pytest.mark.parametrize("resource", ["dataproducts", "datacontracts"])
|
|
207
|
+
@responses.activate
|
|
208
|
+
def test_gitconnection_push_pr(configured, resource):
|
|
209
|
+
responses.add(
|
|
210
|
+
responses.POST,
|
|
211
|
+
f"{BASE_URL}/api/{resource}/orders/gitconnection/push-pr",
|
|
212
|
+
json=CONNECTION_RESPONSE,
|
|
213
|
+
status=200,
|
|
214
|
+
)
|
|
215
|
+
result = runner.invoke(
|
|
216
|
+
app,
|
|
217
|
+
[
|
|
218
|
+
resource,
|
|
219
|
+
"gitconnection",
|
|
220
|
+
"push-pr",
|
|
221
|
+
"orders",
|
|
222
|
+
"--branch-name",
|
|
223
|
+
"feat/orders",
|
|
224
|
+
"--title",
|
|
225
|
+
"Update orders",
|
|
226
|
+
"--commit-message",
|
|
227
|
+
"update orders",
|
|
228
|
+
"--comment",
|
|
229
|
+
"ci push",
|
|
230
|
+
],
|
|
231
|
+
)
|
|
232
|
+
assert result.exit_code == 0
|
|
233
|
+
sent = json.loads(responses.calls[-1].request.body)
|
|
234
|
+
assert sent["branchName"] == "feat/orders"
|
|
235
|
+
assert sent["title"] == "Update orders"
|
|
236
|
+
assert sent["commitMessage"] == "update orders"
|
|
237
|
+
assert sent["comment"] == "ci push"
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def test_gitconnection_help_under_dataproducts():
|
|
241
|
+
result = runner.invoke(app, ["dataproducts", "gitconnection", "--help"])
|
|
242
|
+
assert result.exit_code == 0
|
|
243
|
+
assert "get" in result.output
|
|
244
|
+
assert "put" in result.output
|
|
245
|
+
assert "delete" in result.output
|
|
246
|
+
assert "pull" in result.output
|
|
247
|
+
assert "push" in result.output
|
|
248
|
+
assert "push-pr" in result.output
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def test_gitconnection_help_under_datacontracts():
|
|
252
|
+
result = runner.invoke(app, ["datacontracts", "gitconnection", "--help"])
|
|
253
|
+
assert result.exit_code == 0
|
|
254
|
+
assert "get" in result.output
|
|
255
|
+
assert "push-pr" in result.output
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|