<repo_name>ianhi/jupyterlab-git<file_sep>/jupyterlab_git/tests/test_remote.py
import subprocess
from unittest.mock import Mock, patch

from jupyterlab_git.handlers import GitRemoteAddHandler

from .testutils import assert_http_error, ServerTest, maybe_future


class TestAddRemote(ServerTest):
    @patch("jupyterlab_git.git.execute")
    def test_git_add_remote_success_no_name(self, mock_execute):
        # Given
        path = "test_path"
        url = "http://github.com/myid/myrepository.git"
        mock_execute.return_value = maybe_future((0, "", ""))

        # When
        body = {
            "top_repo_path": path,
            "url": url,
        }
        response = self.tester.post(["remote", "add"], body=body)

        # Then
        command = ["git", "remote", "add", "origin", url]
        mock_execute.assert_called_once_with(command, cwd=path)

        assert response.status_code == 201
        payload = response.json()
        assert payload == {
            "code": 0,
            "command": " ".join(command),
        }

    @patch("jupyterlab_git.git.execute")
    def test_git_add_remote_success(self, mock_execute):
        # Given
        path = "test_path"
        url = "http://github.com/myid/myrepository.git"
        name = "distant"
        mock_execute.return_value = maybe_future((0, "", ""))

        # When
        body = {"top_repo_path": path, "url": url, "name": name}
        response = self.tester.post(["remote", "add"], body=body)

        # Then
        command = ["git", "remote", "add", name, url]
        mock_execute.assert_called_once_with(command, cwd=path)

        assert response.status_code == 201
        payload = response.json()
        assert payload == {
            "code": 0,
            "command": " ".join(command),
        }

    @patch("jupyterlab_git.git.execute")
    def test_git_add_remote_failure(self, mock_execute):
        # Given
        path = "test_path"
        url = "http://github.com/myid/myrepository.git"
        error_msg = "Fake failure"
        error_code = 128
        mock_execute.return_value = maybe_future((error_code, "", error_msg))

        # When
        body = {
            "top_repo_path": path,
            "url": url,
        }
        with assert_http_error(500):
            self.tester.post(["remote", "add"], body=body)

        # Then
        mock_execute.assert_called_once_with(
            ["git", "remote", "add", "origin", url], cwd=path
        )
<file_sep>/ROADMAP.md
 ## CI/CD:
 - Integration Testing
   - **What?** Test suite that actually exercises UI and API against an actual Git repo without mocking out Git calls.
   - **Why?** Enables us to better test against an actual Git process. Stepping stone to x-OS testing such as Windows.
 
 ## Features
 - Plaintext diffs
   - **What?** Diff of non-notebook files such as .py files
   - **Why?** Fully featured diff experience for most types of files
 - Credentials
   - **What?** Credential management during push/pull/clone without actually storing credentials
   - **Why?** Better UX when a user doesn't have credentials for accessing a Git repo.
 - Merge resolution
   - **What?** UI to handle the conflicts for notebook and plain text files.
   - **Why?** Various Git operations may result in conflicts.

 ## Maintenance
 - Issue & Bug triage
    - **What?** Triage issues and fix bugs in existing featutes 
    - **Why?** Operational maintenance of the extension
<file_sep>/jupyterlab_git/tests/test_settings.py
import os
from unittest.mock import Mock, patch

from packaging.version import parse

from jupyterlab_git import __version__
from jupyterlab_git.handlers import GitSettingsHandler

from .testutils import ServerTest, assert_http_error, maybe_future


class TestSettings(ServerTest):
    @patch("jupyterlab_git.git.execute")
    def test_git_get_settings_success(self, mock_execute):
        # Given
        git_version = "2.10.3"
        jlab_version = "2.1.42-alpha.24"
        mock_execute.return_value = maybe_future(
            (0, "git version {}.os_platform.42".format(git_version), "")
        )

        # When
        response = self.tester.get(["settings"], params={"version": jlab_version})

        # Then
        mock_execute.assert_called_once_with(["git", "--version"], cwd=os.curdir)

        assert response.status_code == 200
        payload = response.json()
        assert payload == {
            "frontendVersion": str(parse(jlab_version)),
            "gitVersion": git_version,
            "serverRoot": self.notebook.notebook_dir,
            "serverVersion": str(parse(__version__)),
        }

    @patch("jupyterlab_git.git.execute")
    def test_git_get_settings_no_git(self, mock_execute):
        # Given
        jlab_version = "2.1.42-alpha.24"
        mock_execute.side_effect = FileNotFoundError(
            "[Errno 2] No such file or directory: 'git'"
        )

        # When
        response = self.tester.get(["settings"], params={"version": jlab_version})

        # Then
        mock_execute.assert_called_once_with(["git", "--version"], cwd=os.curdir)

        assert response.status_code == 200
        payload = response.json()
        assert payload == {
            "frontendVersion": str(parse(jlab_version)),
            "gitVersion": None,
            "serverRoot": self.notebook.notebook_dir,
            "serverVersion": str(parse(__version__)),
        }

    @patch("jupyterlab_git.git.execute")
    def test_git_get_settings_no_jlab(self, mock_execute):
        # Given
        git_version = "2.10.3"
        mock_execute.return_value = maybe_future(
            (0, "git version {}.os_platform.42".format(git_version), "")
        )

        # When
        response = self.tester.get(["settings"])

        # Then
        mock_execute.assert_called_once_with(["git", "--version"], cwd=os.curdir)

        assert response.status_code == 200
        payload = response.json()
        assert payload == {
            "frontendVersion": None,
            "gitVersion": git_version,
            "serverRoot": self.notebook.notebook_dir,
            "serverVersion": str(parse(__version__)),
        }
<file_sep>/jupyterlab_git/__init__.py
"""Initialize the backend server extension
"""
# need this in order to show version in `jupyter serverextension list`
from ._version import __version__
from traitlets import List, Dict, Unicode
from traitlets.config import Configurable

from jupyterlab_git.handlers import setup_handlers
from jupyterlab_git.git import Git


class JupyterLabGit(Configurable):
    """
    Config options for jupyterlab_git

    Modeled after: https://github.com/jupyter/jupyter_server/blob/9dd2a9a114c045cfd8fd8748400c6a697041f7fa/jupyter_server/serverapp.py#L1040
    """

    actions = Dict(
        help="Actions to be taken after a git command. Each action takes a list of commands to execute (strings). Supported actions: post_init",
        config=True,
        trait=List(
            trait=Unicode(), help='List of commands to run. E.g. ["touch baz.py"]'
        )
        # TODO Validate
    )


def _jupyter_server_extension_paths():
    """Declare the Jupyter server extension paths."""
    return [{"module": "jupyterlab_git"}]


def load_jupyter_server_extension(nbapp):
    """Load the Jupyter server extension."""

    config = JupyterLabGit(config=nbapp.config)
    git = Git(nbapp.web_app.settings["contents_manager"], config)
    nbapp.web_app.settings["git"] = git
    setup_handlers(nbapp.web_app)
<file_sep>/binder/postBuild
#!/usr/bin/env bash
pip install .
jupyter serverextension enable --sys-prefix --py nbgitpuller
jupyter lab build --dev-build=False --minimize=False --debug
