/
githubmirror
/
lazygit
Обзор
Документация
Войти
/
githubmirror
/
lazygit
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
pkg/commands/git_commands/github_test.go
482 строки
13 KB
Stefan Haller
Carry aggregate check state with GitHub pull requests
31 июл 2026, 10:01
31 июл 2026, 10:01
ff26f61
Код
Авторство
О чём код?
package git_commands import ( "testing" "github.com/jesseduffield/lazygit/pkg/commands/hosting_service" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/stretchr/testify/assert" ) func TestGetRepoInfoFromURL(t *testing.T) { cases := []struct { name string url string expected hosting_service.RepoInformation }{ { name: "SSH URL", url: "git@github.com:jesseduffield/lazygit.git", expected: hosting_service.RepoInformation{ Owner: "jesseduffield", Repository: "lazygit", }, }, { name: "HTTPS URL", url: "https://github.com/jesseduffield/lazygit.git", expected: hosting_service.RepoInformation{ Owner: "jesseduffield", Repository: "lazygit", }, }, { name: "HTTPS URL without .git", url: "https://github.com/jesseduffield/lazygit", expected: hosting_service.RepoInformation{ Owner: "jesseduffield", Repository: "lazygit", }, }, { name: "SSH URL with org nesting", url: "git@github.com:my-org/sub-group/lazygit.git", expected: hosting_service.RepoInformation{ Owner: "my-org/sub-group", Repository: "lazygit", }, }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { result, err := hosting_service.GetRepoInfoFromURL(c.url) assert.NoError(t, err) assert.Equal(t, c.expected, result) }) } } func TestGraphQLEndpoint(t *testing.T) { cases := []struct { host string expected string }{ {"github.com", "https://api.github.com/graphql"}, {"www.github.com", "https://api.github.com/graphql"}, {"GITHUB.com", "https://api.github.com/graphql"}, {"ghe.example.com", "https://ghe.example.com/api/graphql"}, {"ghe.example.com:8443", "https://ghe.example.com:8443/api/graphql"}, } for _, c := range cases { t.Run(c.host, func(t *testing.T) { assert.Equal(t, c.expected, graphQLEndpoint(c.host)) }) } } func TestFetchPullRequestsQueryFetchesOnlyAggregateCheckState(t *testing.T) { query, variables := fetchPullRequestsQuery([]string{"feature"}, "owner", "repo") assert.Contains(t, query, "headRef {") assert.Contains(t, query, "... on Commit {") assert.Contains(t, query, "statusCheckRollup {") assert.NotContains(t, query, "contexts") assert.Equal(t, map[string]string{ "owner": "owner", "repo": "repo", "branch1": "feature", }, variables) } func TestParsePullRequestsResponse(t *testing.T) { t.Run("flattens aliases and normalizes drafts", func(t *testing.T) { response := []byte(`{ "data": { "repository": { "a1": { "edges": [ { "node": { "title": "Add feature", "headRefName": "feature", "number": 42, "url": "https://github.com/jesseduffield/lazygit/pull/42", "headRepositoryOwner": {"login": "contributor"}, "state": "OPEN", "isDraft": false, "headRef": { "target": { "statusCheckRollup": {"state": "SUCCESS"} } } } } ] }, "a2": { "edges": [ { "node": { "title": "Draft feature", "headRefName": "draft-feature", "number": 43, "url": "https://github.com/jesseduffield/lazygit/pull/43", "headRepositoryOwner": {"login": "contributor"}, "state": "OPEN", "isDraft": true, "headRef": null } } ] } } } }`) prs, err := parsePullRequestsResponse(response) assert.NoError(t, err) assert.ElementsMatch(t, []*models.GithubPullRequest{ { HeadRefName: "feature", Number: 42, Title: "Add feature", State: "OPEN", ChecksState: "SUCCESS", Url: "https://github.com/jesseduffield/lazygit/pull/42", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"}, }, { HeadRefName: "draft-feature", Number: 43, Title: "Draft feature", State: "DRAFT", Url: "https://github.com/jesseduffield/lazygit/pull/43", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"}, }, }, prs) }) t.Run("returns an empty slice for an empty result", func(t *testing.T) { prs, err := parsePullRequestsResponse([]byte(`{"data":{"repository":{}}}`)) assert.NoError(t, err) assert.Empty(t, prs) }) t.Run("rejects malformed JSON", func(t *testing.T) { prs, err := parsePullRequestsResponse([]byte(`{"data":`)) assert.Error(t, err) assert.Nil(t, prs) }) } func TestGenerateGithubPullRequestMap(t *testing.T) { cases := []struct { name string prs []*models.GithubPullRequest branches []*models.Branch remotes []*models.Remote expected map[string]*models.GithubPullRequest }{ { name: "empty inputs", prs: []*models.GithubPullRequest{}, branches: []*models.Branch{}, remotes: []*models.Remote{}, expected: map[string]*models.GithubPullRequest{}, }, { name: "matches PR to branch tracking origin", prs: []*models.GithubPullRequest{ { HeadRefName: "feature-branch", Number: 42, Title: "Add feature", State: "OPEN", ChecksState: "PENDING", Url: "https://github.com/jesseduffield/lazygit/pull/42", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"}, }, }, branches: []*models.Branch{ { Name: "feature-branch", UpstreamRemote: "origin", UpstreamBranch: "feature-branch", }, }, remotes: []*models.Remote{ { Name: "origin", Urls: []string{"git@github.com:jesseduffield/lazygit.git"}, }, }, expected: map[string]*models.GithubPullRequest{ "feature-branch": { HeadRefName: "feature-branch", Number: 42, Title: "Add feature", State: "OPEN", ChecksState: "PENDING", Url: "https://github.com/jesseduffield/lazygit/pull/42", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"}, }, }, }, { name: "does not match branch without upstream", prs: []*models.GithubPullRequest{ { HeadRefName: "feature-branch", Number: 42, Title: "Add feature", State: "OPEN", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"}, }, }, branches: []*models.Branch{ { Name: "feature-branch", // no upstream set }, }, remotes: []*models.Remote{ { Name: "origin", Urls: []string{"git@github.com:jesseduffield/lazygit.git"}, }, }, expected: map[string]*models.GithubPullRequest{}, }, { name: "matches fork PR to branch tracking fork remote", prs: []*models.GithubPullRequest{ { HeadRefName: "fix-bug", Number: 99, Title: "Fix bug", State: "OPEN", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"}, }, }, branches: []*models.Branch{ { Name: "fix-bug", UpstreamRemote: "contributor", UpstreamBranch: "fix-bug", }, }, remotes: []*models.Remote{ { Name: "origin", Urls: []string{"git@github.com:jesseduffield/lazygit.git"}, }, { Name: "contributor", Urls: []string{"git@github.com:contributor/lazygit.git"}, }, }, expected: map[string]*models.GithubPullRequest{ "fix-bug": { HeadRefName: "fix-bug", Number: 99, Title: "Fix bug", State: "OPEN", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"}, }, }, }, { name: "does not match when owner differs", prs: []*models.GithubPullRequest{ { HeadRefName: "feature-branch", Number: 42, Title: "Add feature", State: "OPEN", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "someone-else"}, }, }, branches: []*models.Branch{ { Name: "feature-branch", UpstreamRemote: "origin", UpstreamBranch: "feature-branch", }, }, remotes: []*models.Remote{ { Name: "origin", Urls: []string{"git@github.com:jesseduffield/lazygit.git"}, }, }, expected: map[string]*models.GithubPullRequest{}, }, { name: "matches when UpstreamRemote is a full URL", prs: []*models.GithubPullRequest{ { HeadRefName: "my-branch", Number: 55, Title: "Full URL upstream", State: "OPEN", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"}, }, }, branches: []*models.Branch{ { Name: "my-branch", UpstreamRemote: "git@github.com:contributor/lazygit.git", UpstreamBranch: "my-branch", }, }, remotes: []*models.Remote{ { Name: "origin", Urls: []string{"git@github.com:jesseduffield/lazygit.git"}, }, }, expected: map[string]*models.GithubPullRequest{ "my-branch": { HeadRefName: "my-branch", Number: 55, Title: "Full URL upstream", State: "OPEN", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "contributor"}, }, }, }, { name: "uses first PR when branch name is reused (API returns newest first)", prs: []*models.GithubPullRequest{ // API returns newest first (CREATED_AT DESC) { HeadRefName: "update-sponsors", Number: 50, Title: "Newest PR", State: "CLOSED", Url: "https://github.com/jesseduffield/lazygit/pull/50", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"}, }, { HeadRefName: "update-sponsors", Number: 30, Title: "Middle PR", State: "OPEN", Url: "https://github.com/jesseduffield/lazygit/pull/30", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"}, }, { HeadRefName: "update-sponsors", Number: 10, Title: "Oldest PR", State: "CLOSED", Url: "https://github.com/jesseduffield/lazygit/pull/10", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"}, }, }, branches: []*models.Branch{ { Name: "update-sponsors", UpstreamRemote: "origin", UpstreamBranch: "update-sponsors", }, }, remotes: []*models.Remote{ { Name: "origin", Urls: []string{"git@github.com:jesseduffield/lazygit.git"}, }, }, expected: map[string]*models.GithubPullRequest{ "update-sponsors": { HeadRefName: "update-sponsors", Number: 50, Title: "Newest PR", State: "CLOSED", Url: "https://github.com/jesseduffield/lazygit/pull/50", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"}, }, }, }, { name: "matches with HTTPS remote URL", prs: []*models.GithubPullRequest{ { HeadRefName: "my-pr", Number: 10, Title: "My PR", State: "MERGED", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"}, }, }, branches: []*models.Branch{ { Name: "my-pr", UpstreamRemote: "origin", UpstreamBranch: "my-pr", }, }, remotes: []*models.Remote{ { Name: "origin", Urls: []string{"https://github.com/jesseduffield/lazygit.git"}, }, }, expected: map[string]*models.GithubPullRequest{ "my-pr": { HeadRefName: "my-pr", Number: 10, Title: "My PR", State: "MERGED", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "jesseduffield"}, }, }, }, { name: "matches when owner casing differs", prs: []*models.GithubPullRequest{ { HeadRefName: "fix-case-insensitive", Number: 42, Title: "Fix case insensitive", State: "OPEN", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "Jesseduffield"}, // Uppercase J }, }, branches: []*models.Branch{ { Name: "fix-case-insensitive", UpstreamRemote: "origin", UpstreamBranch: "fix-case-insensitive", }, }, remotes: []*models.Remote{ { Name: "origin", Urls: []string{"git@github.com:jesseduffield/lazygit.git"}, // Lowercase j }, }, expected: map[string]*models.GithubPullRequest{ "fix-case-insensitive": { HeadRefName: "fix-case-insensitive", Number: 42, Title: "Fix case insensitive", State: "OPEN", HeadRepositoryOwner: models.GithubRepositoryOwner{Login: "Jesseduffield"}, }, }, }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { result := GenerateGithubPullRequestMap(c.prs, c.branches, c.remotes) assert.Equal(t, c.expected, result) }) } }