-
Notifications
You must be signed in to change notification settings - Fork 11
Initial version of v2 pull integration + project info v2 #282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
MarcelGeo
wants to merge
8
commits into
v2-pull-integration
Choose a base branch
from
pull-initial
base: v2-pull-integration
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
2220abc
Initial dirty version of v2 pull integration + porject info v2
MarcelGeo 001c83d
Separate diff files from merge files + comments @wonder-sk
MarcelGeo 68b84c1
Introduce:
MarcelGeo ae3e55c
Added return types fo new functions
MarcelGeo 55d9e5a
Fix test test_mergin_project
MarcelGeo db7be6c
add optional download_path for pattern with diff files
MarcelGeo 8e3f2ec
solve base file missing
MarcelGeo 9552372
Handle unfinished pull
MarcelGeo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,3 +13,4 @@ htmlcov | |
| deps | ||
| venv | ||
| .vscode/settings.json | ||
| debug.py | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,15 @@ | |
| import typing | ||
| import warnings | ||
|
|
||
| from mergin.models import ( | ||
| ProjectDelta, | ||
| ProjectDeltaItemDiff, | ||
| ProjectDeltaItem, | ||
| ProjectResponse, | ||
| ProjectFile, | ||
| ProjectWorkspace, | ||
| ) | ||
|
|
||
| from .common import ( | ||
| ClientError, | ||
| LoginError, | ||
|
|
@@ -119,6 +128,7 @@ def __init__( | |
| self._user_info = None | ||
| self._server_type = None | ||
| self._server_version = None | ||
| self._server_features = {} | ||
| self.client_version = "Python-client/" + __version__ | ||
| if plugin_version is not None: # this could be e.g. "Plugin/2020.1 QGIS/3.14" | ||
| self.client_version += " " + plugin_version | ||
|
|
@@ -309,6 +319,13 @@ def delete(self, path, validate_auth=True): | |
| request = urllib.request.Request(url, method="DELETE") | ||
| return self._do_request(request, validate_auth=validate_auth) | ||
|
|
||
| def head(self, path, data=None, headers={}, validate_auth=True): | ||
| url = urllib.parse.urljoin(self.url, urllib.parse.quote(path)) | ||
| if data: | ||
| url += "?" + urllib.parse.urlencode(data) | ||
| request = urllib.request.Request(url, headers=headers, method="HEAD") | ||
| return self._do_request(request, validate_auth=validate_auth) | ||
|
|
||
| def login(self, login, password): | ||
| """ | ||
| Authenticate login credentials and store session token | ||
|
|
@@ -412,6 +429,19 @@ def server_version(self): | |
|
|
||
| return self._server_version | ||
|
|
||
| def server_features(self): | ||
| """ | ||
| Returns feature flags of the server. | ||
| """ | ||
| if self._server_features: | ||
| return self._server_features | ||
| config = self.server_config() | ||
| self._server_features = { | ||
| "v2_push_enabled": config.get("v2_push_enabled", False), | ||
| "v2_pull_enabled": config.get("v2_pull_enabled", False), | ||
| } | ||
| return self._server_features | ||
|
|
||
| def workspaces_list(self): | ||
| """ | ||
| Find all available workspaces | ||
|
|
@@ -699,6 +729,90 @@ def project_info(self, project_path_or_id, since=None, version=None): | |
| resp = self.get("/v1/project/{}".format(project_path_or_id), params) | ||
| return json.load(resp) | ||
|
|
||
| def project_info_v2(self, project_id: str, files_at_version=None) -> ProjectResponse: | ||
| """ | ||
| Fetch info about project. | ||
|
|
||
| :param project_id: Project's id | ||
| :type project_id: String | ||
| :param files_at_version: Version to track files at given version | ||
| :type files_at_version: String | ||
| """ | ||
MarcelGeo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| self.check_v2_project_info_support() | ||
|
|
||
| params = {} | ||
| if files_at_version: | ||
| params = {"files_at_version": files_at_version} | ||
| resp = self.get(f"/v2/projects/{project_id}", params) | ||
| resp_json = json.load(resp) | ||
| project_workspace = resp_json.get("workspace", {}) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can workspace be optional in response? |
||
| return ProjectResponse( | ||
| id=resp_json.get("id"), | ||
| name=resp_json.get("name"), | ||
| created_at=resp_json.get("created_at"), | ||
| updated_at=resp_json.get("updated_at"), | ||
| version=resp_json.get("version"), | ||
| public=resp_json.get("public"), | ||
| role=resp_json.get("role"), | ||
| size=resp_json.get("size"), | ||
| workspace=ProjectWorkspace( | ||
| id=project_workspace.get("id"), | ||
| name=project_workspace.get("name"), | ||
| ), | ||
| files=[ | ||
| ProjectFile( | ||
| checksum=f.get("checksum"), | ||
| mtime=f.get("mtime"), | ||
| path=f.get("path"), | ||
| size=f.get("size"), | ||
| ) | ||
| for f in resp_json.get("files", []) | ||
| ], | ||
| ) | ||
|
|
||
| def get_project_delta(self, project_id: str, since: str, to: typing.Optional[str] = None) -> ProjectDelta: | ||
| """ | ||
| Fetch info about project delta since given version. | ||
|
|
||
| :param project_id: Project's id | ||
| :type project_id: String | ||
| :param since: Version to track history of files from | ||
| :type since: String | ||
| :param to: Optional version to track history of files to, if not given latest version is used | ||
| :type since: String | ||
| :rtype: Dict | ||
| """ | ||
| # If it is not enabled on the server, raise error | ||
| if not self.server_features().get("v2_pull_enabled", False): | ||
| raise ClientError("Project delta is not supported by the server") | ||
|
|
||
| params = {"since": since} | ||
| if to: | ||
| params["to"] = to | ||
| resp = self.get(f"/v2/projects/{project_id}/delta", params) | ||
| resp_parsed = json.load(resp) | ||
| return ProjectDelta( | ||
| to_version=resp_parsed.get("to_version"), | ||
| items=[ | ||
| ProjectDeltaItem( | ||
| path=item["path"], | ||
| size=item.get("size"), | ||
| checksum=item.get("checksum"), | ||
| version=item.get("version"), | ||
| change=item.get("change"), | ||
| diffs=( | ||
| [ | ||
| ProjectDeltaItemDiff( | ||
| id=diff.get("id"), | ||
| ) | ||
| for diff in item.get("diffs", []) | ||
| ] | ||
| ), | ||
| ) | ||
| for item in resp_parsed.get("items", []) | ||
| ], | ||
| ) | ||
|
|
||
| def paginated_project_versions(self, project_path, page, per_page=100, descending=False): | ||
| """ | ||
| Get records of project's versions (history) using calculated pagination. | ||
|
|
@@ -789,11 +903,11 @@ def download_project(self, project_path, directory, version=None): | |
| :param project_path: Project's full name (<namespace>/<name>) | ||
| :type project_path: String | ||
|
|
||
| :param version: Project version to download, e.g. v42 | ||
| :type version: String | ||
|
|
||
| :param directory: Target directory | ||
| :type directory: String | ||
|
|
||
| :param version: Project version to download, e.g. v42 | ||
| :type version: String | ||
| """ | ||
| job = download_project_async(self, project_path, directory, version) | ||
| download_project_wait(job) | ||
|
|
@@ -1308,13 +1422,21 @@ def check_collaborators_members_support(self): | |
| if not is_version_acceptable(self.server_version(), f"{min_version}"): | ||
| raise NotImplementedError(f"This needs server at version {min_version} or later") | ||
|
|
||
| def check_v2_project_info_support(self): | ||
| """ | ||
| Check if the server is compatible with v2 endpoint for project info | ||
| """ | ||
| min_version = "2025.8.2" | ||
| if not is_version_acceptable(self.server_version(), f"{min_version}"): | ||
| raise NotImplementedError(f"This needs server at version {min_version} or later") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we catch this in client http requests? |
||
|
|
||
| def create_user( | ||
| self, | ||
| email: str, | ||
| password: str, | ||
| workspace_id: int, | ||
| workspace_role: WorkspaceRole, | ||
| username: str = None, | ||
| username: typing.Optional[str] = None, | ||
| notify_user: bool = False, | ||
| ) -> dict: | ||
| """ | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.