Skip to content
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

Implement ui to support multiple remotes #1146

Merged
merged 30 commits into from
Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
261c15e
implement name-url pair for adding remote repo
BoscoCHW Jul 7, 2022
c1e6e90
implement name-url pair for adding remote repo
BoscoCHW Jul 7, 2022
75c9628
Merge branch 'issue-234' of github.com:BoscoCHW/jupyterlab-git into i…
BoscoCHW Jul 11, 2022
2b0987b
Style Add Remote form
BoscoCHW Jul 11, 2022
b40ba77
show existing remote on add remote form
BoscoCHW Jul 12, 2022
ae6785f
Implement backend api to show remote url info
BoscoCHW Jul 13, 2022
f2287fd
Refactor remote_show function to handle verbose case
BoscoCHW Jul 13, 2022
5af1c3b
Implement remote dialog box using React
BoscoCHW Jul 14, 2022
eda196a
Style remote dialog
BoscoCHW Jul 14, 2022
fd7451a
Add remove remote button
BoscoCHW Jul 14, 2022
f6b1da6
Implement backend to remove remote
BoscoCHW Jul 15, 2022
7b205d9
Document codes
BoscoCHW Jul 15, 2022
b8588a9
Show push remote url only
BoscoCHW Jul 18, 2022
c009874
Implement pushing options for multiple remotes
BoscoCHW Jul 18, 2022
1f7bac9
Change GitRemoteDetailsShowHandler successful code
BoscoCHW Jul 21, 2022
b085bbc
Attempting to implement the DELETE method for removing a remote
BoscoCHW Jul 21, 2022
afb6e9e
style existing remote list with the grid api
BoscoCHW Jul 22, 2022
99df0f3
Fix git remote remove route bug
BoscoCHW Jul 22, 2022
5e505c0
Implement advanced push dialog box
BoscoCHW Jul 22, 2022
f077fc0
Show remote url in advanced push dialog and increase text font size
BoscoCHW Jul 22, 2022
dd214d7
Move dialog action buttons to just below input fields and display mes…
BoscoCHW Jul 29, 2022
30fdc42
Display loading message when getting remote information and handle no…
BoscoCHW Jul 29, 2022
386bf3b
Add tests for remote_show and remote_remove
BoscoCHW Aug 2, 2022
94f3f10
Remove cancel button from add remote dialog
BoscoCHW Aug 3, 2022
651ef2e
Change command gitAddRemote to gitManageRemote
BoscoCHW Aug 3, 2022
9f3ee72
Rename files to reflect command name 'ManageRemote'
BoscoCHW Aug 3, 2022
ecff43a
Refactor manageRemote command to let the dialog handle the adding and…
BoscoCHW Aug 3, 2022
1618609
Comment out tests for addRemote command
BoscoCHW Aug 3, 2022
9c686a4
Remove test for git:add-remote command
BoscoCHW Aug 5, 2022
c799be3
Add tests for component 'ManageRemoteDialogue'
BoscoCHW Aug 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 35 additions & 5 deletions jupyterlab_git/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -1494,24 +1494,54 @@ async def remote_add(self, path, url, name=DEFAULT_REMOTE_NAME):

return response

async def remote_show(self, path):
async def remote_show(self, path, verbose=False):
"""Handle call to `git remote show` command.
Args:
path (str): Git repository path

verbose (bool): true if details are needed, otherwise, false
Returns:
List[str]: Known remotes
if not verbose: List[str]: Known remotes
if verbose: List[ { name: str, url: str } ]: Known remotes
"""
command = ["git", "remote", "show"]
command = ["git", "remote"]
if verbose:
command.extend(["-v", "show"])
else:
command.append("show")

code, output, error = await execute(command, cwd=path)
response = {"code": code, "command": " ".join(command)}

if code == 0:
response["remotes"] = [r.strip() for r in output.splitlines()]
if verbose:
response["remotes"] = [
{"name": r.split("\t")[0], "url": r.split("\t")[1][:-7]}
for r in output.splitlines()
if "(push)" in r
]
else:
response["remotes"] = [r.strip() for r in output.splitlines()]
else:
response["message"] = error

return response

async def remote_remove(self, path, name):
"""Handle call to `git remote remove <name>` command.
Args:
path (str): Git repository path
name (str): Remote name
"""
command = ["git", "remote", "remove", name]

code, _, error = await execute(command, cwd=path)
response = {"code": code, "command": " ".join(command)}

if code != 0:
response["message"] = error

return response

async def ensure_gitignore(self, path):
"""Handle call to ensure .gitignore file exists and the
next append will be on a new line (this means an empty file
Expand Down
57 changes: 50 additions & 7 deletions jupyterlab_git/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,37 @@ async def post(self, path: str = ""):
self.finish(json.dumps(output))


class GitRemoteDetailsShowHandler(GitHandler):
"""Handler for 'git remote -v'."""

@tornado.web.authenticated
async def get(self, path: str = ""):
"""GET request handler to retrieve existing remotes."""
local_path = self.url2localpath(path)
output = await self.git.remote_show(local_path, verbose=True)
if output["code"] == 0:
self.set_status(200)
else:
self.set_status(500)
self.finish(json.dumps(output))


class GitRemoteRemoveHandler(GitHandler):
"""Handler for 'git remote remove <name>'."""

@tornado.web.authenticated
async def delete(self, path: str = "", name: str = ""):
"""DELETE request handler to remove a remote."""
local_path = self.url2localpath(path)

output = await self.git.remote_remove(local_path, name)
if output["code"] == 0:
self.set_status(204)
else:
self.set_status(500)
self.finish(json.dumps(output))


class GitResetHandler(GitHandler):
"""
Handler for 'git reset <filename>'.
Expand Down Expand Up @@ -871,6 +902,7 @@ def setup_handlers(web_app):
("/push", GitPushHandler),
("/remote/add", GitRemoteAddHandler),
("/remote/fetch", GitFetchHandler),
("/remote/show", GitRemoteDetailsShowHandler),
("/reset", GitResetHandler),
("/reset_to_commit", GitResetToCommitHandler),
("/show_prefix", GitShowPrefixHandler),
Expand All @@ -890,12 +922,23 @@ def setup_handlers(web_app):

# add the baseurl to our paths
base_url = web_app.settings["base_url"]
git_handlers = [
(url_path_join(base_url, NAMESPACE + path_regex + endpoint), handler)
for endpoint, handler in handlers_with_path
] + [
(url_path_join(base_url, NAMESPACE + endpoint), handler)
for endpoint, handler in handlers
]
git_handlers = (
[
(url_path_join(base_url, NAMESPACE + path_regex + endpoint), handler)
for endpoint, handler in handlers_with_path
]
+ [
(url_path_join(base_url, NAMESPACE + endpoint), handler)
for endpoint, handler in handlers
]
+ [
(
url_path_join(
base_url, NAMESPACE + path_regex + r"/remote/(?P<name>\w+)"
),
GitRemoteRemoveHandler,
)
]
)

web_app.add_handlers(".*", git_handlers)
82 changes: 80 additions & 2 deletions jupyterlab_git/tests/test_remote.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import json
from unittest.mock import patch

import os
import pytest
import tornado

from jupyterlab_git.git import Git
from jupyterlab_git.handlers import NAMESPACE

from .testutils import assert_http_error, maybe_future


Expand Down Expand Up @@ -101,3 +101,81 @@ async def test_git_add_remote_failure(mock_execute, jp_fetch, jp_root_dir):
mock_execute.assert_called_once_with(
["git", "remote", "add", "origin", url], cwd=str(local_path)
)


@patch("jupyterlab_git.git.execute")
async def test_git_remote_show(mock_execute, jp_root_dir):
# Given
local_path = jp_root_dir / "test_path"
mock_execute.return_value = maybe_future(
(0, os.linesep.join(["origin", "test"]), "")
)

# When
output = await Git().remote_show(str(local_path), False)

# Then
command = ["git", "remote", "show"]
mock_execute.assert_called_once_with(command, cwd=str(local_path))
assert output == {
"code": 0,
"command": " ".join(command),
"remotes": ["origin", "test"],
}


@patch("jupyterlab_git.git.execute")
async def test_git_remote_show_verbose(mock_execute, jp_fetch, jp_root_dir):
# Given
local_path = jp_root_dir / "test_path"
url = "http://github.com/myid/myrepository.git"
process_output = os.linesep.join(
[f"origin\t{url} (fetch)", f"origin\t{url} (push)"]
)
mock_execute.return_value = maybe_future((0, process_output, ""))

# When
response = await jp_fetch(
NAMESPACE,
local_path.name,
"remote",
"show",
method="GET",
)

# Then
command = ["git", "remote", "-v", "show"]
mock_execute.assert_called_once_with(command, cwd=str(local_path))

assert response.code == 200
payload = json.loads(response.body)
assert payload == {
"code": 0,
"command": " ".join(command),
"remotes": [
{"name": "origin", "url": "http://github.com/myid/myrepository.git"}
],
}


@patch("jupyterlab_git.git.execute")
async def test_git_remote_remove(mock_execute, jp_fetch, jp_root_dir):
# Given
local_path = jp_root_dir / "test_path"
mock_execute.return_value = maybe_future((0, "", ""))

# When
name = "origin"
response = await jp_fetch(
NAMESPACE,
local_path.name,
"remote",
name,
method="DELETE",
)

# Then
command = ["git", "remote", "remove", name]
mock_execute.assert_called_once_with(command, cwd=str(local_path))

assert response.code == 204
4 changes: 2 additions & 2 deletions schema/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
},
{
"command": "git:push",
"args": { "force": true }
"args": { "advanced": true }
},
{
"command": "git:pull"
Expand All @@ -113,7 +113,7 @@
"command": "git:reset-to-remote"
},
{
"command": "git:add-remote"
"command": "git:manage-remote"
},
{
"command": "git:terminal-command"
Expand Down
Loading