mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-10-06 05:57:38 -04:00
Reading a change in lazygit and saying something about it on GitHub means finding the line again in the browser: open the pull request, find the commit, find the file, scroll to the line. The line is already under the cursor here. Bind G in the focused main view, the key the commits panel opens the pull request with, to open it at the line the selection is on. The URL names the commits whose diff is on screen, so that the line numbers of the diff are the ones the page shows, the file by the SHA-256 of its repo-relative path, and the line by the side of the diff it is on: R for the new version of the file, L for the old one, where a deleted line is. GitHub documents none of that; the form was read off the URLs its own pages carry. One commit is named by its hash. A range of them is named by the commit the range starts after and the commit it ends at, the form the chooser above a pull request's files uses. The commit a range starts after is the parent of its oldest commit; where the range starts where the pull request itself does, that parent is none of the pull request's own commits, and the keyword BASE stands for it. Which branch's pull request that is depends on the panel beneath: the checked-out branch below the commits panel, the branch drilled into below the sub-commits panel, and whichever of those the commit files panel was entered from. Panels showing a diff that no pull request has a view of don't answer, and the command isn't offered over their diffs at all. Neither is it offered over a diff that is not the commit's own, where the line numbers on screen are not the ones the page shows: a diff against another ref in diffing mode, and the custom patch, whose lines sit at the numbers the patch gives them. A pull request holds only the commits of its branch that are pushed, and its pages say they can't find any other commit. So the command refuses where a commit of the diff is not one of the pull request's. Amend a commit in the middle of the branch, and the diffs of the commits below it still open; the ones above it sit on hashes the remote doesn't have. A commit from before the branch, in a main branch already, is refused too. Only GitHub pull requests are known, since that is where the pull request data comes from. The whole path can't be exercised headlessly: no pull request reaches the model without a GitHub token, so the test covers where the command is offered and the three reasons it refuses. The URL is unit-tested instead, both the anchor of a line and the way the commits are named. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
116 lines
3.7 KiB
Go
116 lines
3.7 KiB
Go
package controllers
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestGithubPullRequestLineURL(t *testing.T) {
|
|
const prURL = "https://github.com/jesseduffield/lazygit/pull/1234"
|
|
const commitHash = "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b"
|
|
|
|
// The anchor names the file by the SHA-256 of its repo-relative path, taken over
|
|
// exactly those bytes: no leading slash, no trailing newline, forward slashes.
|
|
const fileHash = "067980d6efc4249367ceb61b0d93a00bca100a0ddb6d4a72b6dbb0eb9d3825cc" // "dir/file1"
|
|
|
|
scenarios := []struct {
|
|
name string
|
|
path string
|
|
info types.DiffLineInfo
|
|
expected string
|
|
}{
|
|
{
|
|
name: "an added line is on the right side of the diff",
|
|
path: "dir/file1",
|
|
info: types.DiffLineInfo{Type: types.DiffLineAdded, NewLine: 12},
|
|
expected: prURL + "/changes/" + commitHash + "#diff-" + fileHash + "R12",
|
|
},
|
|
{
|
|
name: "a deleted line is on the left side, at the line it sat on",
|
|
path: "dir/file1",
|
|
// A deletion's NewLine is only where it sits in the new version of the
|
|
// file; the line it is, is the old one.
|
|
info: types.DiffLineInfo{Type: types.DiffLineDeleted, NewLine: 12, OldLine: 34},
|
|
expected: prURL + "/changes/" + commitHash + "#diff-" + fileHash + "L34",
|
|
},
|
|
{
|
|
name: "a context line is on the right side too",
|
|
path: "dir/file1",
|
|
info: types.DiffLineInfo{Type: types.DiffLineContext, NewLine: 7, OldLine: 5},
|
|
expected: prURL + "/changes/" + commitHash + "#diff-" + fileHash + "R7",
|
|
},
|
|
{
|
|
name: "a hunk header points at the first line of its hunk",
|
|
path: "dir/file1",
|
|
info: types.DiffLineInfo{Type: types.DiffLineHunkHeader, NewLine: 20},
|
|
expected: prURL + "/changes/" + commitHash + "#diff-" + fileHash + "R20",
|
|
},
|
|
{
|
|
name: "the header naming a file points at the file alone",
|
|
path: "dir/file1",
|
|
info: types.DiffLineInfo{Type: types.DiffLineFileHeader},
|
|
expected: prURL + "/changes/" + commitHash + "#diff-" + fileHash,
|
|
},
|
|
{
|
|
name: "a row that is no line of the file points at the file alone",
|
|
path: "dir/file1",
|
|
info: types.DiffLineInfo{Type: types.DiffLineOther},
|
|
expected: prURL + "/changes/" + commitHash + "#diff-" + fileHash,
|
|
},
|
|
{
|
|
name: "a file at the root of the repo",
|
|
path: "file1",
|
|
info: types.DiffLineInfo{Type: types.DiffLineAdded, NewLine: 1},
|
|
expected: prURL + "/changes/" + commitHash +
|
|
"#diff-c147efcfc2d7ea666a9e4f5187b115c90903f0fc896a56df9a6ef5d8f3fc9f31R1",
|
|
},
|
|
}
|
|
|
|
for _, s := range scenarios {
|
|
t.Run(s.name, func(t *testing.T) {
|
|
assert.Equal(t, s.expected, githubPullRequestLineURL(prURL, commitHash, s.path, s.info))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGithubCommitRange(t *testing.T) {
|
|
hashPool := &utils.StringPool{}
|
|
newest := models.NewCommit(hashPool, models.NewCommitOpts{Hash: "newest"})
|
|
oldest := models.NewCommit(hashPool, models.NewCommitOpts{Hash: "oldest"})
|
|
|
|
scenarios := []struct {
|
|
name string
|
|
commits []*models.Commit
|
|
baseHash string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "a single commit is named on its own",
|
|
commits: []*models.Commit{newest},
|
|
baseHash: "parent",
|
|
expected: "newest",
|
|
},
|
|
{
|
|
name: "a range is named as the commits it lies between",
|
|
commits: []*models.Commit{newest, oldest},
|
|
baseHash: "parent",
|
|
expected: "parent..newest",
|
|
},
|
|
{
|
|
name: "a range starting where the pull request does lies above BASE",
|
|
commits: []*models.Commit{newest, oldest},
|
|
expected: "BASE..newest",
|
|
},
|
|
}
|
|
|
|
for _, s := range scenarios {
|
|
t.Run(s.name, func(t *testing.T) {
|
|
assert.Equal(t, s.expected, githubCommitRange(s.commits, s.baseHash))
|
|
})
|
|
}
|
|
}
|