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

Add git stash #1228

Merged
merged 48 commits into from
Jun 2, 2023
Merged

Add git stash #1228

merged 48 commits into from
Jun 2, 2023

Conversation

shawnesquivel
Copy link
Contributor

@shawnesquivel shawnesquivel commented Feb 28, 2023

Add #309 to use git stash

  • git stash save -m 'message'
  • git stash drop
  • git stash pop
  • git stash apply
add.git.stash.-.apr.3.2023.mov

@github-actions
Copy link

Binder 👈 Launch a binder notebook on branch shawnesquivel/jupyterlab-git/issue-309

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Mar 2, 2023

Hi @fcollonval, I am running into this assertion error. For some reason, my response body has the environment attached to it as well. Do you know how I might fix this error? I have added GitStashHandler, Git.stash, and test_stash

test_stash.py
@patch("jupyterlab_git.git.execute")
async def test_git_stash(mock_execute, jp_fetch, jp_root_dir):
    # Given
    # Creates a temporary directory created by pytest's tmp_path fixture and concatenates the string "test_path" to it.
    local_path = jp_root_dir / "test_path"
    # 0 = success code, "" = no output, "" = no error
    mock_execute.return_value = maybe_future((0, "", ""))
    # When
    #

    # jp_fetch is a fixture that returns a function that can be used to make HTTP requests to the Jupyter server.
    """
    jp_fetch(
        NAMESPACE, # NAMESPACE is the prefix of the url
        local_path.name, # local_path.name is the name of the folder
        "stash", # stash is the name of the handler
        body, empty because git stash doesn't take any arguments
        method="POST", # method is the http method
    )
    """
    response = await jp_fetch(
        NAMESPACE,
        local_path.name,
        "stash",
        body=json.dumps({}),
        method="POST",
    )
    # Then
    command = ["git", "stash"]
    # Checks that the mock function was called with the correct arguments
    mock_execute.assert_called_once_with(command, cwd=str(local_path))

    assert response.code == 201
    # json.loads turns a string into a dictionary
    payload = json.loads(response.body)
    assert payload == {
        "code": 0,
        "command": " ".join(command),
    }

Error when I run the test for `test_stash.py`: looks like the environment is being passed too?
  • AssertionError: expected call not found.
  • Expected: execute(['git', 'stash'], cwd='/private/var/folders/cb/t008bpbd6g99lpcgx3fdzpzh0000gn/T/pytest-of-shawnesquivel/pytest-14/test_git_stash0/root_dir/test_path')
  • Actual: execute(['git', 'stash'], cwd='/private/var/folders/cb/t008bpbd6g99lpcgx3fdzpzh0000gn/T/pytest-of-shawnesquivel/pytest-14/test_git_stash0/root_dir/test_path', env={'MallocNanoZone': '0', 'USER': 'shawnesquivel', 'SECURITYSESSIONID': '186b4', 'COMMAND_MODE': 'unix2003', '__CFBundleIdentifier': 'com.microsoft.VSCode', 'PATH': '/Library/Frameworks/Python.framework/Versions/3.11/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/shawnesquivel/miniconda3/bin:/Users/shawnesquivel/miniconda3/condabin:/Library/Frameworks/Python.framework/Versions/3.11/bin', 'HOME': '/private/var/folders/cb/t008bpbd6g99lpcgx3fdzpzh0000gn/T/pytest-of-shawnesquivel/pytest-14/test_git_stash0/home', 'SHELL': '/bin/zsh', 'LaunchInstanceID': 'D923BD7F-CF2A-4CCC-9CB5-AD30391E2A18', '__CF_USER_TEXT_ENCODING': '0x1F5:0x0:0x52', 'XPC_SERVICE_NAME': '0', 'SSH_AUTH_SOCK': '/private/tmp/com.apple.launchd.GDFjTvYS6P/Listeners', 'XPC_FLAGS': '0x0', 'LOGNAME': 'shawnesquivel', 'TMPDIR': '/var/folders/cb/t008bpbd6g99lpcgx3fdzpzh0000gn/T/', 'ORIGINAL_XDG_CURRENT_DESKTOP': 'undefined', 'SHLVL': '1', 'PWD': '/Users/shawnesquivel/Documents/GitHub/jupyterlab-git', 'OLDPWD': '/Users/shawnesquivel/Documents/GitHub/jupyterlab-git', 'ZSH': '/Users/shawnesquivel/.oh-my-zsh', 'PAGER': 'less', 'LESS': '-R', 'LSCOLORS': 'Gxfxcxdxbxegedabagacad', 'CONDA_EXE': '/Users/shawnesquivel/miniconda3/bin/conda', 'CONDA_PYTHON_EXE': '/Users/shawnesquivel/miniconda3/bin/python', 'CONDA_SHLVL': '1', 'CONDA_PREFIX': '/Users/shawnesquivel/miniconda3', 'CONDA_DEFAULT_ENV': 'base', 'CONDA_PROMPT_MODIFIER': '(base) ', 'TERM_PROGRAM': 'vscode', 'TERM_PROGRAM_VERSION': '1.75.1', 'LANG': 'en_US.UTF-8', 'COLORTERM': 'truecolor', 'GIT_ASKPASS': '/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass.sh', 'VSCODE_GIT_ASKPASS_NODE': '/Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper (Plugin).app/Contents/MacOS/Code Helper (Plugin)', 'VSCODE_GIT_ASKPASS_EXTRA_ARGS': '--ms-enable-electron-run-as-node', 'VSCODE_GIT_ASKPASS_MAIN': '/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass-main.js', 'VSCODE_GIT_IPC_HANDLE': '/var/folders/cb/t008bpbd6g99lpcgx3fdzpzh0000gn/T/vscode-git-b5aa93e9ba.sock', 'VSCODE_INJECTION': '1', 'ZDOTDIR': '/Users/shawnesquivel', 'USER_ZDOTDIR': '/Users/shawnesquivel', 'TERM': 'xterm-256color', '_CE_M': '', 'CE_CONDA': '', '': '/Library/Frameworks/Python.framework/Versions/3.11/bin/pytest', 'PYTEST_CURRENT_TEST': 'jupyterlab_git/tests/test_stash.py::test_git_stash (call)', 'PYTHONPATH': '/Users/shawnesquivel/Documents/GitHub/jupyterlab-git:/Library/Frameworks/Python.framework/Versions/3.11/bin:/Library/Frameworks/Python.framework/Versions/3.11/lib/python311.zip:/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11:/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload:/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages', 'JUPYTER_CONFIG_DIR': '/private/var/folders/cb/t008bpbd6g99lpcgx3fdzpzh0000gn/T/pytest-of-shawnesquivel/pytest-14/test_git_stash0/config', 'JUPYTER_DATA_DIR': '/private/var/folders/cb/t008bpbd6g99lpcgx3fdzpzh0000gn/T/pytest-of-shawnesquivel/pytest-14/test_git_stash0/data', 'JUPYTER_RUNTIME_DIR': '/private/var/folders/cb/t008bpbd6g99lpcgx3fdzpzh0000gn/T/pytest-of-shawnesquivel/pytest-14/test_git_stash0/runtime', 'GIT_TERMINAL_PROMPT': '0'})

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Mar 3, 2023

Nevermind, I figured it out with @basokant! I was just missing some parameters. I'm unblocked now.

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Mar 7, 2023

@fcollonval

Upon writing some more tests, I ran into this block of code. I think I'm getting the hang of using it but I'm confused upon reading the jp_fetch documentation. For example, when calling jp_fetch, we pass some parameters such as the git commands (stash) or in the test_remote example (remote, add). However, upon looking into the jp_fetch fixture, the parameters look different.

Why is this?

Using jp_fetch

await jp_fetch(
            NAMESPACE,
            local_path.name,
            "remote",
            "add",
            body=json.dumps(body),
            method="POST",
        )

Definition of jp_fetch

@pytest.fixture
def jp_fetch**(jp_serverapp, http_server_client, jp_auth_header, jp_base_url):**
    """Sends an (asynchronous) HTTP request to a test server.
    The fixture is a factory; it can be called like
    a function inside a unit test. Here's a basic
    example of how use this fixture:
 code-block:: python

        async def my_test(jp_fetch):
            response = await jp_fetch("api", "spec.yaml")
            ...

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Mar 8, 2023

Just an update to this issue. I was able to successfully create a button that calls git stash!

I currently re-used the Pull Button component badge/action button as a placeholder. I'm not sure if I should create a new button for stash.

I still need to

  • write more tests
  • somehow show the git stash list in the UI. i was thinking of another toggle menu that says "Stashed" underneath untracked. Would I need to create another command for git stash list? E.g. if we reload the page, it should check if there are any stashed changes.
  • repeat everything i've done for git stash pop

git stash list

@fcollonval
Copy link
Member

Hey @shawnesquivel

The concept of fixtures in Pytest can be confusing.

Taking the example from the link above:

import pytest


class Fruit:
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        return self.name == other.name


@pytest.fixture
def my_fruit():
    return Fruit("apple")


@pytest.fixture
def fruit_basket(my_fruit):
    return [Fruit("banana"), my_fruit]


def test_my_fruit_in_basket(my_fruit, fruit_basket):
    assert my_fruit in fruit_basket

What pytest is doing with that code:

  • Create the AST of the code.
  • Every functions named test_* are gathered to be executed
  • For every functions, look in the fixtures registry for a fixture (aka a function) with the name of the input argument.
  • Execute the fixture functions requested as arguments
  • Pass to the test function the output of the fixture function

So in regular Python way, the test call is actually:

fruit = my_fruit()
basket = fruit_basket(fruit)
test_my_fruit_in_basket(fruit, basket)

Note that the returned value can be anything. In particular for jp_fetch it is actually a function. Let's describe a simpler example:

import pytest

@pytest.fixture
def my_fruit():
    return "banana"


@pytest.fixture
def cook_with(my_fruit):
    def cook(*ingredients):
        return f"Delicious food combining {my_fruit} and {', '.join(ingredients)}"
    return cook


def test_my_fruit_in_basket(my_fruit, cook_with):
    assert my_fruit in cook_with("sugar", "butter")

The cook_with signature is not the fixture signature but the internal cook signature.

For jp_fetch, you will find the actual function signature at https://github.com/jupyter-server/pytest-jupyter/blob/78e8ace0c57080704533857a60b76b7ed548cf63/pytest_jupyter/jupyter_server.py#L302

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Mar 14, 2023

image

Some pair programming with @basokant and we got further! 😄

Update:

  • added handlers for git stash show and git stash list
  • can now see the files changed for each entry in the stash

Next Steps:

  • Update UI
  • Add delete / apply / handlers

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Mar 18, 2023

Hi @fcollonval ,

Question 1:
When I call git stash, this is what should happen:

  1. The changes are stashed ✅
  2. The file should revert the changes

Can you provide some guidance as to how I can do step 2? I had an idea to use:

  • in refreshStash, git stash list is used to get all the file names that were modified in that stash
  • for each file name that was changed, maybe this._revertFile(file) could be used to revert the file. however, the files in the stash entry are not file objects that are typically used in revertFile.

Question 2:
I need to do something similar with git stash pop <index> - I am able to call the command and remove the latest entry from the stash, but I don't see the changes get re-applied to the file. I think it's related to my previous question for git stash.

Question 3:
How can I make the UI refresh when I make a make a stash change?

Question 4:
I want to allow the user to be able to add a message for the stash, for example: git stash save "Changed button"

How can I make a dialogue box that allows the user to enter the stash message when they click the stash button?

@fcollonval
Copy link
Member

Great work 🚀

Question 1: When I call git stash, this is what should happen:

1. The changes are stashed white_check_mark
2. The file should revert the changes

Can you provide some guidance as to how I can do step 2? I had an idea to use:

* in `refreshStash`, `git stash list` is used to get all the file names that were modified in that stash

* for each file name that was changed, maybe `this._revertFile(file)` could be used to revert the file. however, the files in the stash entry are not `file` objects that are typically used in revertFile.

I'm not sure to correctly understand the question. Do you want to update the file status in FileList component or the file content if it is opened in an editor?

If you want to update the file status, you can call GitExtension.refresh:

async refresh(): Promise<void> {

Question 2: I need to do something similar with git stash pop <index> - I am able to call the command and remove the latest entry from the stash, but I don't see the changes get re-applied to the file. I think it's related to my previous question for git stash.

Waiting for more info see Q1

Question 3: How can I make the UI refresh when I make a make a stash change?

Usually this is done by listening to a signal emitting model changes. See for multiple examples:

componentDidMount(): void {

You can use a React component UseSignal to refresh only a small tree or components when an event is emitted. See e.g.:

<UseSignal signal={this._model.headChanged}>

Question 4: I want to allow the user to be able to add a message for the stash, for example: git stash save "Changed button"

How can I make a dialogue box that allows the user to enter the stash message when they click the stash button?

You can make use of the JupyterLab helper InputDialog.getText: see https://github.com/jupyterlab/jupyterlab/blob/358e470dd7bf37806827b4ad4e2c4c4fb234d1f3/packages/apputils/test/inputdialog.spec.ts#L213

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Mar 20, 2023

Thank you for the feedback!

Related to q1 - on VS code, when I click git stash, the stashed changes disappear from the file(s) affected.

git.stash.-.vs.code.mov

Currently, when I call the git stash command in the JL extension, the stashes get stored in the stash, but the changes don't disappear from the file. Related to my git stash apply implementation, I don't see any stashes being applied to the file when I call it, and I think this is related.

git.stash.-.jlg.blocker.mov

@shawnesquivel
Copy link
Contributor Author

Forgot to tag you on the previous reply – @fcollonval

@shawnesquivel
Copy link
Contributor Author

For Q3, it is related to my previous question, I want the entire file to refresh so that the stash changes will be removed (if I stash) or re-applied (if I apply/drop). So I'm not sure where to emit the signal from so that I can achieve this.

@shawnesquivel
Copy link
Contributor Author

Hi @fcollonval, I worked on it a little more and I think I have a new issue that I don't really understand. It may make my previous questions a little ignorant of the bigger issue. Please see the video below:

When I call the git stash in the terminal, the command runs. However, the changes don't get removed from the UI. Also, if I check the git stash list, you can see that the stash entry does get updated.

git.stash.issue.march.23.2023.mov

@fcollonval
Copy link
Member

Hey @shawnesquivel,

To force reloading a file for it to match the disk content, you can use the GitExtension._revertFile method:

private _revertFile(path: string): void {

When I call the git stash in the terminal, the command runs. However, the changes don't get removed from the UI. Also, if I check the git stash list, you can see that the stash entry does get updated.

When you do modification outside the UI, there is no way for the UI to know a modification happens. The file status is updated because it is polled regularly - you could do that for stash list to see it appearing. But for the file content, there is no mechanism. At best, JupyterLab should tell you the next time you try to save the file that it has been modified.

@fcollonval
Copy link
Member

Does that help you to move forward?

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Mar 24, 2023

@fcollonval

To force reloading a file for it to match the disk content, you can use the GitExtension._revertFile method:

private _revertFile(path: string): void {

When you do modification outside the UI, there is no way for the UI to know a modification happens. The file status is updated because it is polled regularly - you could do that for stash list to see it appearing. But for the file content, there is no mechanism. At best, JupyterLab should tell you the next time you try to save the file that it has been modified.

I get the same issue when I click the stash button manually (inside the UI - see video).

So if I wanted to revert all the files affected, I could just pass each file that was changed into the revertFile?

git.stash.ui.issue.-.march.24.2023.mov

@shawnesquivel
Copy link
Contributor Author

Hey @fcollonval , forgot to tag you in the response above again, but hopefully it notified you.

@fcollonval
Copy link
Member

So if I wanted to revert all the files affected, I could just pass each file that was changed into the revertFile?

Yes this should do the trick

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Apr 3, 2023

Hi @fcollonval ,

I made it a little prettier 😄 Please see the top post for the latest demo/UI.

Let me know what you think.

i'll move on to finishing the tests and starting playwright otherwise.

Also, is there a way to check the Build tests in the VS code without pushing? Lots of them are "prettier" issues. I'm not sure if it's something I can fix.

@fcollonval
Copy link
Member

i'll move on to finishing the tests and starting playwright otherwise.

👍

Also, is there a way to check the Build tests in the VS code without pushing? Lots of them are "prettier" issues. I'm not sure if it's something I can fix.

You can run locally all or some of the following commands:

# Fix linter
jlpm run eslint
# Check linter
jlpm run eslint:check
# Run the TS/JS tests
jlpm run test
 
# Python formatting
black .
# Python formatting checks
black . --check
 
# Run the Python tests
pytest jupyterlab_git -r ap

Copy link
Member

@fcollonval fcollonval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @shawnesquivel

Here is a first large review of your code. Overall the code looks code.

jupyterlab_git/git.py Outdated Show resolved Hide resolved
jupyterlab_git/git.py Outdated Show resolved Hide resolved
jupyterlab_git/git.py Outdated Show resolved Hide resolved
jupyterlab_git/git.py Outdated Show resolved Hide resolved
jupyterlab_git/git.py Outdated Show resolved Hide resolved
src/tokens.ts Outdated Show resolved Hide resolved
src/model.ts Outdated Show resolved Hide resolved
src/model.ts Show resolved Hide resolved
src/model.ts Outdated
await this.refreshStash();

if (this._stash?.length > 0) {
this._stash[0].files.forEach(file => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you get the list before calling the task handler? The trouble is that it can take time to refresh the stash and we should revert the file as quickly as possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this create an issue? If we revert the files before stashing, then we may stash the reverted file, thereby losing the changes that we wanted to stash..

try {

// Grab the list
const stashFiles = this._stash[index].files;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happen if index is undefined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I changed it so that it will apply the first stash if no index is provided.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also changed the index from an optional argument to required.

Copy link
Member

@fcollonval fcollonval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @shawnesquivel

Here is a first large review of your code. Overall the code looks code.

@fcollonval
Copy link
Member

I tried to test online but the environment seems broken ➡️ Binder

image

@shawnesquivel
Copy link
Contributor Author

Thanks @fcollonval. I just finished going through all the PR comments and have some feedback and follow up questions that I left in the resolved threads.

@shawnesquivel
Copy link
Contributor Author

Hi @fcollonval, I'm getting some build errors:

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Apr 8, 2023

Hi @fcollonval , I'm getting some build errors. Could you provide any suggestions to fix them?

Build Error 1: I'm getting this signal connection issue, even though my signal does connect regularly when I run Jupyter Lab.

Signal connects normally here:
image
However, the issue is gone and the test passes if I use optional chaining (see snippet), but none of the other signals do that so I'm wondering if that's OK?


    model.stashChanged?.connect((_, args) => {
      console.log('signal connected:', args);
      this.setState({
        stash: args.newValue as any
      });
    }, this);
Error Messages: Test failing with signal connect

● GitPanel › #render() › should render Commit and Push if there is a remote branch

TypeError: Cannot read properties of undefined (reading 'connect')

  219 |     console.log('GitPanel componentDidMount, model:', this.props.model);
  220 |
> 221 |     model.stashChanged.connect(async (_, args) => {
      |                        ^
  222 |       console.log('signal connected:', args);
  223 |       this.setState({
  224 |         stash: args.newValue as any

  at GitPanel.componentDidMount (src/components/GitPanel.tsx:221:24)
  at fn (node_modules/enzyme/src/ShallowWrapper.js:429:22)
  at Object.batchedUpdates (node_modules/@wojtekmaj/enzyme-adapter-react-17/src/ReactSeventeenAdapter.js:754:16)
  at new ShallowWrapper (node_modules/enzyme/src/ShallowWrapper.js:428:26)
  at Object.shallow (node_modules/enzyme/src/shallow.js:10:10)
  at Object.<anonymous> (tests/test-components/GitPanel.spec.tsx:277:21)

● GitPanel › #render() › should render Commit if there is no remote branch

TypeError: Cannot read properties of undefined (reading 'connect')

  219 |     console.log('GitPanel componentDidMount, model:', this.props.model);
  220 |
> 221 |     model.stashChanged.connect(async (_, args) => {
      |                        ^
  222 |       console.log('signal connected:', args);
  223 |       this.setState({
  224 |         stash: args.newValue as any

  at GitPanel.componentDidMount (src/components/GitPanel.tsx:221:24)
  at fn (node_modules/enzyme/src/ShallowWrapper.js:429:22)
  at Object.batchedUpdates (node_modules/@wojtekmaj/enzyme-adapter-react-17/src/ReactSeventeenAdapter.js:754:16)
  at new ShallowWrapper (node_modules/enzyme/src/ShallowWrapper.js:428:26)
  at Object.shallow (node_modules/enzyme/src/shallow.js:10:10)
  at Object.<anonymous> (tests/test-components/GitPanel.spec.tsx:296:21)

● GitPanel › #render() › should render Commit if there is a remote branch but commitAndPush is false

TypeError: Cannot read properties of undefined (reading 'connect')

  219 |     console.log('GitPanel componentDidMount, model:', this.props.model);
  220 |
> 221 |     model.stashChanged.connect(async (_, args) => {
      |                        ^
  222 |       console.log('signal connected:', args);
  223 |       this.setState({
  224 |         stash: args.newValue as any

  at GitPanel.componentDidMount (src/components/GitPanel.tsx:221:24)
  at fn (node_modules/enzyme/src/ShallowWrapper.js:429:22)
  at Object.batchedUpdates (node_modules/@wojtekmaj/enzyme-adapter-react-17/src/ReactSeventeenAdapter.js:754:16)
  at new ShallowWrapper (node_modules/enzyme/src/ShallowWrapper.js:428:26)
  at Object.shallow (node_modules/enzyme/src/shallow.js:10:10)

Build Error 2 - Fail to load server extension
It is recommending that I run pip install --upgrade jupyterlab-git but I'm not sure if that will ruin my dev environment.

Running jupyter server extension list
jupyterlab_git 0.41.0 OK

Running jupyter lab extension list
jupyterlab_git 0.41.0 OK

Error messages onsole.error Failed to load the jupyterlab-git server extension settings Error: The versions of the JupyterLab Git server frontend and backend do not match. The @jupyterlab/git frontend extension has version: 0.41.0 while the python package has version 0.1.0. Please install identical version of jupyterlab-git Python package and the @jupyterlab/git extension. Try running: pip install --upgrade jupyterlab-git at Object.activate (/Users/shawnesquivel/GitHub/jupyterlab-git/src/index.ts:116:13) at processTicksAndRejections (node:internal/process/task_queues:95:5) at Object. (/Users/shawnesquivel/GitHub/jupyterlab-git/tests/plugin.spec.ts:128:25)
  127 |   } catch (error) {
  128 |     // If we fall here, nothing will be loaded in the frontend.
> 129 |     console.error(
      |             ^
  130 |       trans.__('Failed to load the jupyterlab-git server extension settings'),
  131 |       error
  132 |     );

  at Object.activate (src/index.ts:129:13)
  at Object.<anonymous> (tests/plugin.spec.ts:128:25)

console.error
  Failed to load the jupyterlab-git server extension settings ResponseError: Git server extension is unavailable. Please ensure you have installed the JupyterLab Git server extension by running: pip install --upgrade jupyterlab-git. To confirm that the server extension is installed, run: jupyter server extension list.
      at Object.getServerSettings (/Users/shawnesquivel/GitHub/jupyterlab-git/src/server.ts:32:15)
      at Object.activate (/Users/shawnesquivel/GitHub/jupyterlab-git/src/index.ts:96:28)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)
      at Object.<anonymous> (/Users/shawnesquivel/GitHub/jupyterlab-git/tests/plugin.spec.ts:159:25) {
run jupyter server extension list

upyter_server_fileid enabled
- Validating jupyter_server_fileid...
Package jupyter_server_fileid took 0.0023s to import
jupyter_server_fileid 0.7.0 OK
jupyter_server_mathjax enabled
- Validating jupyter_server_mathjax...
Package jupyter_server_mathjax took 0.0011s to import
jupyter_server_mathjax OK
jupyter_server_terminals enabled
- Validating jupyter_server_terminals...
Package jupyter_server_terminals took 0.0066s to import
jupyter_server_terminals 0.4.4 OK
jupyter_server_ydoc enabled
- Validating jupyter_server_ydoc...
Package jupyter_server_ydoc took 0.0381s to import
jupyter_server_ydoc 0.6.1 OK
jupyterlab enabled
- Validating jupyterlab...
Package jupyterlab took 0.0514s to import
jupyterlab 3.6.1 OK
jupyterlab_git enabled
- Validating jupyterlab_git...
Package jupyterlab_git took 0.0254s to import
jupyterlab_git 0.41.0 OK
nbclassic enabled
- Validating nbclassic...
Package nbclassic took 0.0000s to import
A _jupyter_server_extension_points function was not found in nbclassic. Instead, a _jupyter_server_extension_paths function was found and will be used for now. This function name will be deprecated in future releases of Jupyter Server.
nbclassic 0.5.2 OK
nbdime enabled
- Validating nbdime...
Package nbdime took 0.0000s to import
nbdime 3.1.1 OK
notebook_shim enabled
- Validating notebook_shim...
Package notebook_shim took 0.0000s to import
A _jupyter_server_extension_points function was not found in notebook_shim. Instead, a _jupyter_server_extension_paths function was found and will be used for now. This function name will be deprecated in future releases of Jupyter Server.
notebook_shim OK

@shawnesquivel
Copy link
Contributor Author

Hi @fcollonval, related to the playwright installation, I'm facing an error. Following the instructions outlined here: https://github.com/jupyterlab/jupyterlab-git/tree/master/ui-tests

Steps 0, 1, and 2 work.

When I run step 3 jlpm install inside ui-tests, I get the following build error. It says it failed to install canvas. Any suggestions?

jlpm install - error message

yarn install v1.21.1
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
warning "@jupyterlab/galata > @lumino/[email protected]" has unmet peer dependency "[email protected]".
warning "@jupyterlab/galata > @jupyterlab/application > @jupyterlab/[email protected]" has unmet peer dependency "react@^17.0.1".
warning "@jupyterlab/galata > @jupyterlab/cells > @jupyterlab/codemirror > [email protected]" has unmet peer dependency "yjs@^13.5.17".
[4/4] 🔨 Building fresh packages...
[-/3] ⠂ waiting...
[2/3] ⠂ leveldown
error /Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas: Command failed.
Exit code: 1
Command: node-pre-gyp install --fallback-to-build
Arguments:
Directory: /Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas
Output:
node-pre-gyp info it worked if it ends with ok
node-pre-gyp info using [email protected]
node-pre-gyp info using [email protected] | darwin | arm64
node-pre-gyp info check checked for "/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas/build/Release/canvas.node" (not found)
node-pre-gyp http GET https://github.com/Automattic/node-canvas/releases/download/v2.9.0/canvas-v2.9.0-node-v108-darwin-unknown-arm64.tar.gz
node-pre-gyp ERR! install response status 404 Not Found on https://github.com/Automattic/node-canvas/releases/download/v2.9.0/canvas-v2.9.0-node-v108-darwin-unknown-arm64.tar.gz
node-pre-gyp WARN Pre-built binaries not installable for [email protected] and [email protected] (node-v108 ABI, unknown) (falling back to source compile with node-gyp)
node-pre-gyp WARN Hit error response status 404 Not Found on https://github.com/Automattic/node-canvas/releases/download/v2.9.0/canvas-v2.9.0-node-v108-darwin-unknown-arm64.tar.gz
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | darwin | arm64
gyp info ok
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | darwin | arm64
gyp info find Python using Python version 3.10.9 found at "/Users/shawnesquivel/miniconda3/bin/python3"
gyp info spawn /Users/shawnesquivel/miniconda3/bin/python3
gyp info spawn args [
gyp info spawn args '/usr/local/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args 'binding.gyp',
gyp info spawn args '-f',
gyp info spawn args 'make',
gyp info spawn args '-I',
gyp info spawn args '/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/Users/shawnesquivel/Library/Caches/node-gyp/18.14.2/include/node/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/Users/shawnesquivel/Library/Caches/node-gyp/18.14.2',
gyp info spawn args '-Dnode_gyp_dir=/usr/local/lib/node_modules/npm/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=/Users/shawnesquivel/Library/Caches/node-gyp/18.14.2/<(target_arch)/node.lib',
gyp info spawn args '-Dmodule_root_dir=/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas',
gyp info spawn args '-Dnode_engine=v8',
gyp info spawn args '--depth=.',
gyp info spawn args '--no-parallel',
gyp info spawn args '--generator-output',
gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.'
gyp info spawn args ]
/bin/sh: pkg-config: command not found
gyp: Call to 'pkg-config pixman-1 --libs' returned exit status 127 while in binding.gyp. while trying to load binding.gyp
gyp ERR! configure error
gyp ERR! stack Error: gyp failed with exit code: 1
gyp ERR! stack at ChildProcess.onCpExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:325:16)
gyp ERR! stack at ChildProcess.emit (node:events:513:28)
gyp ERR! stack at ChildProcess._handle.onexit (node:internal/child_process:291:12)
gyp ERR! System Darwin 22.1.0
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "configure" "--fallback-to-build" "--module=/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas/build/Release/canvas.node" "--module_name=canvas" "--module_path=/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas/build/Release" "--napi_version=8" "--node_abi_napi=napi" "--napi_build_version=0" "--node_napi_label=node-v108"
gyp ERR! cwd /Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas
gyp ERR! node -v v18.14.2
gyp ERR! node-gyp -v v9.3.1
gyp ERR! not ok
node-pre-gyp ERR! build error
node-pre-gyp ERR! stack Error: Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js configure --fallback-to-build --module=/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas/build/Release/canvas.node --module_name=canvas --module_path=/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas/build/Release --napi_version=8 --node_abi_napi=napi --napi_build_version=0 --node_napi_label=node-v108' (1)
node-pre-gyp ERR! stack at ChildProcess. (/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/@mapbox/node-pre-gyp/lib/util/compile.js:89:23)
node-pre-gyp ERR! stack at ChildProcess.emit (node:events:513:28)
node-pre-gyp ERR! stack at maybeClose (node:internal/child_process:1091:16)
node-pre-gyp ERR! stack at ChildProcess._handle.onexit (node:internal/child_process:302:5)
node-pre-gyp ERR! System Darwin 22.1.0
node-pre-gyp ERR! command "/usr/local/bin/node" "/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas
node-pre-gyp ERR! node -v v18.14.2
node-pre-gyp ERR! node-pre-gyp -v v1.0.8
node-pre-gyp ERR! not ok
Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js configure --fallback-to-build --module=/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas/build/Release/canvas.node --module_name=canvas --module_path=/Users/shawnesquivel/GitHub/jupyterlab-git/ui-tests/node_modules/canvas/build/Release --napi_version=8 --node_abi_napi=napi --napi_build_version=0 --node_napi_label=node-v108' (1)

Copy link
Member

@fcollonval fcollonval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot @shawnesquivel the Python code looks great and the TypeScript code is quite good. I have a couple of comments and regarding the trouble with canvas, could you try rebasing this PR on master. I think you will benefit from the fixes merged last week.

jupyterlab_git/tests/test_stash.py Outdated Show resolved Hide resolved
jupyterlab_git/tests/test_stash.py Outdated Show resolved Hide resolved
src/commandsAndMenu.tsx Outdated Show resolved Hide resolved
src/commandsAndMenu.tsx Outdated Show resolved Hide resolved
src/commandsAndMenu.tsx Outdated Show resolved Hide resolved
src/commandsAndMenu.tsx Outdated Show resolved Hide resolved
src/model.ts Show resolved Hide resolved
src/model.ts Outdated Show resolved Hide resolved
src/model.ts Outdated Show resolved Hide resolved
src/tokens.ts Show resolved Hide resolved
@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Apr 17, 2023

Hi @fcollonval, as mentioned in our last meeting, these pytests are not passing. They don't seem to be related to my changes, so it would be great if you could take a look before merging. However, I'm still writing the playwright tests.

SKIPPED [1] jupyterlab_git/tests/test_hybridcontents.py:11: could not import 'hybridcontents': No module named 'hybridcontents'
SKIPPED [1] jupyterlab_git/tests/test_jupytext.py:7: could not import 'jupytext': No module named 'jupytext'
FAILED jupyterlab_git/tests/test_integrations.py::test_git_show_prefix - subprocess.CalledProcessError: Command '['git', 'checkout', '-b', 'bas...
FAILED jupyterlab_git/tests/test_integrations.py::test_git_show_prefix_symlink - subprocess.CalledProcessError: Command '['git', 'checkout', '-b', 'bas...

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Apr 18, 2023

Hi @fcollonval !

Tests Failing to Update UI After Running Build

  • When viewing my test-repository by using the jlpm playwright codegen [localhost:8889](http://localhost:8889) , the UI looks as expected from my latest changes

image

  • Running jlpm run build:prod and jupyter lab --config ./ui-tests/jupyter_server_test_config.py, then running
jupyter lab --config ./ui-tests/jupyter_server_test_config.py
jlpm playwright test git-stash.spec.ts
  • Viewing the failed test, it looks like the UI hasn’t updated to reflect the latest changes as it’s missing the 3 buttons from the first picture

image

  • Additionally, if I run jupyter lab and view the test-repository in the browser, we can see that the UI reflects the latest changes.

image

- So the question is, why isn’t the test showing the latest UI updates even after running jlpm run build:prod?

Steps to Troubleshoot

  • Tried clearing browser cache
  • Tried starting a new terminal and running build / server commands there
  • Tried killing the other instances of jupyter lab

@fcollonval
Copy link
Member

@shawnesquivel could it be that if the side panel width is to small action buttons get out of the viewport (you could test that locally by resizing the panel to be very small). If this is the case, try updating the CSS rules on the stash description to have it display an ellipsis when overflow occurs.

If not let me know I'll try to have a look locally.

@fcollonval
Copy link
Member

Hi @fcollonval, as mentioned in our last meeting, these pytests are not passing. They don't seem to be related to my changes, so it would be great if you could take a look before merging. However, I'm still writing the playwright tests.

SKIPPED [1] jupyterlab_git/tests/test_hybridcontents.py:11: could not import 'hybridcontents': No module named 'hybridcontents'
SKIPPED [1] jupyterlab_git/tests/test_jupytext.py:7: could not import 'jupytext': No module named 'jupytext'
FAILED jupyterlab_git/tests/test_integrations.py::test_git_show_prefix - subprocess.CalledProcessError: Command '['git', 'checkout', '-b', 'bas...
FAILED jupyterlab_git/tests/test_integrations.py::test_git_show_prefix_symlink - subprocess.CalledProcessError: Command '['git', 'checkout', '-b', 'bas...

The skipped ones are because you do not have some optional dependencies installed. Don't worry the CI gets you covered.

For the two failing tests, it could be interesting to get more information about the error. But my guess is that it is related to the OS. As they are working on the CI and it is not related as you mentioned, let's move forward.

@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Apr 20, 2023

Hi @fcollonval !

I worked with @basokant to get some more integration tests done. I also ended up finishing the rest (I think)!

Some of the methods are a little hacky, I used "timeout" since there were multiple waiting dependencies (wait for revertFile, wait for stash list to re-update).

I think I could also clean up some of the expect methods too, since I think the toBeTruthy might not be working as I expect.

The tests seem to have passed in my local env, but something is going wrong when pushing to GitHub.

Let me know what the last steps should be to get this fixed up before the end of the fellowship 😄

@shawnesquivel shawnesquivel marked this pull request as ready for review April 20, 2023 15:59
@shawnesquivel
Copy link
Contributor Author

shawnesquivel commented Apr 20, 2023

HI @fcollonval , I added the changes mentioned in today's meeting. All my tests are passing now! Looks like the test failing is not related to this issue?

1) tests/merge-commit.spec.ts:59:7 › Merge commit tests › should diff file after clicking ────────

    Error: proxy.waitForSelector: Target closed
    =========================== logs ===========================
    waiting for locator('.jp-git-diff-root') to be visible
    ============================================================

      69 |       .waitFor({ state: 'visible' });
      70 |
    > 71 |     expect(page.waitForSelector('.jp-git-diff-root')).toBeTruthy();
         |                 ^
      72 |   });
      73 |
      74 |   test('should revert merge commit', async ({ page }) => {

        at /home/runner/work/jupyterlab-git/jupyterlab-git/ui-tests/tests/merge-commit.spec.ts:71:[17](https://github.com/jupyterlab/jupyterlab-git/actions/runs/4756525454/jobs/8452388215?pr=1228#step:12:18)

    Test finished within timeout of 60000ms, but tearing down "context" ran out of time.
    Please allow more time for the test, since teardown is attributed towards the test timeout budget.

Copy link
Member

@fcollonval fcollonval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot @shawnesquivel

Overall it looks very good. Would you be able to finish it up? Otherwise I'm happy to finish the PR.

You are correct the integration failure is not related.

jupyterlab_git/handlers.py Outdated Show resolved Hide resolved
src/commandsAndMenu.tsx Outdated Show resolved Hide resolved
src/components/GitPanel.tsx Outdated Show resolved Hide resolved
src/components/GitPanel.tsx Outdated Show resolved Hide resolved
src/style/FileListStyle.ts Outdated Show resolved Hide resolved
src/tokens.ts Outdated Show resolved Hide resolved
@shawnesquivel
Copy link
Contributor Author

Hi @fcollonval , I added the final changes you requested! Let me know if there's anything else.

@fcollonval
Copy link
Member

Kicking the CI

@fcollonval fcollonval closed this May 30, 2023
@fcollonval fcollonval reopened this May 30, 2023
jupyterlab_git/git.py Outdated Show resolved Hide resolved
jupyterlab_git/git.py Outdated Show resolved Hide resolved
jupyterlab_git/git.py Outdated Show resolved Hide resolved
jupyterlab_git/git.py Outdated Show resolved Hide resolved
src/components/GitPanel.tsx Outdated Show resolved Hide resolved
src/model.ts Outdated Show resolved Hide resolved
src/model.ts Outdated Show resolved Hide resolved
src/model.ts Outdated Show resolved Hide resolved
src/model.ts Outdated Show resolved Hide resolved
src/model.ts Outdated Show resolved Hide resolved
@fcollonval fcollonval merged commit 8666a36 into jupyterlab:master Jun 2, 2023
@fcollonval fcollonval mentioned this pull request Aug 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants