Skip to content

Commit

Permalink
Git history for a selected file (#864) (#980)
Browse files Browse the repository at this point in the history
* Add history context menu button in the file browser (#863)

* Add --follow option to Git log command (#864)

* Display Git history for selected file (#864)

* Apply suggestions from code review

Co-authored-by: Frédéric Collonval <[email protected]>

* Add styling to selected history file item

* Add selected file history for modified files

* Add 'No History Found' fallback

- Covers git-ignored files edge case

* Apply suggestions from code review

Improve readability

Co-authored-by: Frédéric Collonval <[email protected]>

* Fix tests for history (#864)

* Add single file log test (#864)

Co-authored-by: Frédéric Collonval <[email protected]>
  • Loading branch information
navn-r and fcollonval authored Aug 3, 2021
1 parent 96bef45 commit 02c6d9a
Show file tree
Hide file tree
Showing 21 changed files with 883 additions and 176 deletions.
48 changes: 27 additions & 21 deletions jupyterlab_git/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,16 +432,24 @@ async def status(self, path):

return data

async def log(self, path, history_count=10):
async def log(self, path, history_count=10, follow_path=None):
"""
Execute git log command & return the result.
"""
is_single_file = follow_path != None
cmd = [
"git",
"log",
"--pretty=format:%H%n%an%n%ar%n%s",
("-%d" % history_count),
]
if is_single_file:
cmd = cmd + [
"--numstat",
"--follow",
"--",
follow_path,
]
code, my_output, my_error = await execute(
cmd,
cwd=path,
Expand All @@ -450,30 +458,28 @@ async def log(self, path, history_count=10):
return {"code": code, "command": " ".join(cmd), "message": my_error}

result = []
if is_single_file:
# an extra newline get outputted when --numstat is used
my_output = my_output.replace("\n\n", "\n")
line_array = my_output.splitlines()
i = 0
PREVIOUS_COMMIT_OFFSET = 4
PREVIOUS_COMMIT_OFFSET = 5 if is_single_file else 4
while i < len(line_array):
commit = {
"commit": line_array[i],
"author": line_array[i + 1],
"date": line_array[i + 2],
"commit_msg": line_array[i + 3],
"pre_commit": "",
}

if is_single_file:
commit["is_binary"] = line_array[i + 4].startswith("-\t-\t")

if i + PREVIOUS_COMMIT_OFFSET < len(line_array):
result.append(
{
"commit": line_array[i],
"author": line_array[i + 1],
"date": line_array[i + 2],
"commit_msg": line_array[i + 3],
"pre_commit": line_array[i + PREVIOUS_COMMIT_OFFSET],
}
)
else:
result.append(
{
"commit": line_array[i],
"author": line_array[i + 1],
"date": line_array[i + 2],
"commit_msg": line_array[i + 3],
"pre_commit": "",
}
)
commit["pre_commit"] = line_array[i + PREVIOUS_COMMIT_OFFSET]

result.append(commit)
i += PREVIOUS_COMMIT_OFFSET
return {"code": code, "commits": result}

Expand Down
7 changes: 5 additions & 2 deletions jupyterlab_git/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ async def post(self, path: str = ""):

class GitLogHandler(GitHandler):
"""
Handler for 'git log --pretty=format:%H-%an-%ar-%s'.
Handler for 'git log'.
Fetches Commit SHA, Author Name, Commit Date & Commit Message.
"""

Expand All @@ -208,7 +208,10 @@ async def post(self, path: str = ""):
"""
body = self.get_json_body()
history_count = body.get("history_count", 25)
result = await self.git.log(self.url2localpath(path), history_count)
follow_path = body.get("follow_path")
result = await self.git.log(
self.url2localpath(path), history_count, follow_path
)

if result["code"] != 0:
self.set_status(500)
Expand Down
4 changes: 2 additions & 2 deletions jupyterlab_git/tests/test_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ async def test_log_handler(mock_git, jp_fetch, jp_root_dir):
)

# Then
mock_git.log.assert_called_with(str(local_path), 20)
mock_git.log.assert_called_with(str(local_path), 20, None)

assert response.code == 200
payload = json.loads(response.body)
Expand All @@ -301,7 +301,7 @@ async def test_log_handler_no_history_count(mock_git, jp_fetch, jp_root_dir):
)

# Then
mock_git.log.assert_called_with(str(local_path), 25)
mock_git.log.assert_called_with(str(local_path), 25, None)

assert response.code == 200
payload = json.loads(response.body)
Expand Down
Loading

0 comments on commit 02c6d9a

Please sign in to comment.