From 0d9f9c387155ca66ee0bc2aca43b0223af0223fe Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sat, 5 Feb 2022 23:14:40 -0500 Subject: [PATCH] Adds get next comparison uris for GitHub Adds get previous line comparison uris for GitHub Improves perf of get previous comparison uris for GitHub Replaces HEAD usage with proper revision for GitHub Renames comparison uri methods for clarity --- .vscode/queries.github-graphql-nb | 2 +- src/commands/diffLineWithPrevious.ts | 2 +- src/commands/diffWithNext.ts | 2 +- src/commands/diffWithPrevious.ts | 2 +- src/commands/diffWithWorking.ts | 6 +- src/commands/openFileAtRevision.ts | 2 +- src/env/node/git/localGitProvider.ts | 18 +- src/git/gitProvider.ts | 15 +- src/git/gitProviderService.ts | 49 +---- src/git/models/commit.ts | 8 +- src/hovers/hovers.ts | 10 +- src/hovers/lineHoverController.ts | 17 -- src/premium/github/github.ts | 134 +++++++++++-- src/premium/github/githubGitProvider.ts | 250 +++++++++++++----------- 14 files changed, 298 insertions(+), 219 deletions(-) diff --git a/.vscode/queries.github-graphql-nb b/.vscode/queries.github-graphql-nb index a337a0773b6e7..50b3d67fad09a 100644 --- a/.vscode/queries.github-graphql-nb +++ b/.vscode/queries.github-graphql-nb @@ -1 +1 @@ -{"cells":[{"code":"### Get Default Branch & Tip","kind":"markdown"},{"code":"query getDefaultBranchAndTip(\n\t$owner: String!\n\t$repo: String!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tdefaultBranchRef {\n\t\t\tname\n\t\t\ttarget { oid }\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Get Branches","kind":"markdown"},{"code":"query getBranches(\n\t$owner: String!\n\t$repo: String!\n\t$branchQuery: String\n\t$cursor: String\n\t$limit: Int = 100\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\trefs(query: $branchQuery, refPrefix: \"refs/heads/\", first: $limit, after: $cursor, orderBy: { field: TAG_COMMIT_DATE, direction: DESC }) {\n\t\t\tpageInfo {\n\t\t\t\tendCursor\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\tname\n\t\t\t\ttarget {\n\t\t\t\t\toid\n\t\t\t\t\tcommitUrl\n\t\t\t\t\t...on Commit {\n\t\t\t\t\t\tauthoredDate\n\t\t\t\t\t\tcommittedDate\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Get Blame","kind":"markdown"},{"code":"query getBlame(\n\t$owner: String!\n\t$repo: String!\n\t$ref: GitObjectID!\n\t$path: String!\n) {\n\tviewer { name }\n\trepository(owner: $owner, name: $repo) {\n\t\tobject(oid: $ref) {\n\t\t\t...on Commit {\n\t\t\t\tblame(path: $path) {\n\t\t\t\t\tranges {\n\t\t\t\t\t\tstartingLine\n\t\t\t\t\t\tendingLine\n\t\t\t\t\t\tage\n\t\t\t\t\t\tcommit {\n\t\t\t\t\t\t\toid\n\t\t\t\t\t\t\tparents(first: 3) { nodes { oid } }\n\t\t\t\t\t\t\tmessage\n\t\t\t\t\t\t\tauthor {\n\t\t\t\t\t\t\t\tavatarUrl\n\t\t\t\t\t\t\t\tdate\n\t\t\t\t\t\t\t\temail\n\t\t\t\t\t\t\t\tname\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcommitter { date }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"54f28933055124d6ba3808a787f6947c929f9db0\",\n\t\"path\": \"src/keyboard.ts\"\n}","kind":"code"},{"code":"### Get Commit for File","kind":"markdown"},{"code":"query getCommitForFile(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n\t$path: String!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tref(qualifiedName: $ref) {\n\t\t\ttarget {\n\t\t\t\t... on Commit {\n\t\t\t\t\thistory(first: 1, path: $path) {\n\t\t\t\t\t\tnodes {\n\t\t\t\t\t\t\toid\n\t\t\t\t\t\t\tparents(first: 3) { nodes { oid } }\n\t\t\t\t\t\t\tmessage\n\t\t\t\t\t\t\tadditions\n\t\t\t\t\t\t\tchangedFiles\n\t\t\t\t\t\t\tdeletions\n\t\t\t\t\t\t\tauthor {\n\t\t\t\t\t\t\t\tdate\n\t\t\t\t\t\t\t\temail\n\t\t\t\t\t\t\t\tname\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcommitter { date }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"refs/heads/main\",\n\t\"path\": \"src/extension.ts\"\n}","kind":"code"},{"code":"### Get Current User","kind":"markdown"},{"code":"query getCurrentUser(\n\t$owner: String!\n\t$repo: String!\n) {\n\tviewer { name }\n\trepository(name: $repo owner: $owner) {\n\t\tviewerPermission\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Get Commit","kind":"markdown"},{"code":"query getCommit(\n\t$owner: String!\n\t$repo: String!\n\t$ref: GitObjectID!\n) {\n\trepository(name: $repo owner: $owner) {\n\t\tobject(oid: $ref) {\n\t\t\t...on Commit {\n\t\t\t\toid\n\t\t\t\tparents(first: 3) { nodes { oid } }\n\t\t\t\tmessage\n\t\t\t\tadditions\n\t\t\t\tchangedFiles\n\t\t\t\tdeletions\n\t\t\t\tauthor {\n\t\t\t\t\tdate\n\t\t\t\t\temail\n\t\t\t\t\tname\n\t\t\t\t}\n\t\t\t\tcommitter { date }\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"54f28933055124d6ba3808a787f6947c929f9db0\"\n}","kind":"code"},{"code":"### Get Commits","kind":"markdown"},{"code":"query getCommits(\n\t$owner: String!\n\t$repo: String!\n\t$ref: GitObjectID!\n) {\n\trepository(name: $repo owner: $owner) {\n\t\tobject(oid: $ref) {\n\t\t\t...on Commit {\n\t\t\t\toid\n\t\t\t\tparents(first: 3) { nodes { oid } }\n\t\t\t\tmessage\n\t\t\t\tadditions\n\t\t\t\tchangedFiles\n\t\t\t\tdeletions\n\t\t\t\tauthor {\n\t\t\t\t\tdate\n\t\t\t\t\temail\n\t\t\t\t\tname\n\t\t\t\t}\n\t\t\t\tcommitter { date }\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"54f28933055124d6ba3808a787f6947c929f9db0\"\n}","kind":"code"},{"code":"### Get Tags","kind":"markdown"},{"code":"query getTags(\n\t$owner: String!\n\t$repo: String!\n\t$tagQuery: String\n\t$cursor: String\n\t$limit: Int = 100\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\trefs(query: $tagQuery, refPrefix: \"refs/tags/\", first: $limit, after: $cursor, orderBy: { field: TAG_COMMIT_DATE, direction: DESC }) {\n\t\t\tpageInfo {\n\t\t\t\tendCursor\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\tname\n\t\t\t\ttarget {\n\t\t\t\t\toid\n\t\t\t\t\tcommitUrl\n\t\t\t\t\t...on Commit {\n\t\t\t\t\t\tauthoredDate\n\t\t\t\t\t\tcommittedDate\n\t\t\t\t\t\tmessage\n\t\t\t\t\t}\n\t\t\t\t\t...on Tag {\n\t\t\t\t\t\tmessage\n\t\t\t\t\t\ttagger { date }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Get collaborators ","kind":"markdown"},{"code":"query getCollaborators (\n\t$owner: String!\n\t$repo: String!\n\t$cursor: String\n\t$limit: Int = 100\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tcollaborators(affiliation: ALL, first: $limit, after: $cursor) {\n\t\t\tpageInfo {\n\t\t\t\tendCursor\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\tname\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Resolve reference","kind":"markdown"},{"code":"query resolveReference(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n\t$path: String!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tobject(expression: $ref) {\n\t\t\t... on Commit {\n\t\t\t\thistory(first: 1, path: $path) {\n\t\t\t\t\tnodes { oid }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"d790e9db047769de079f6838c3578f3a47bf5930^\",\n\t\"path\": \"CODE_OF_CONDUCT.md\"\n}","kind":"code"},{"code":"### Get branches that contain commit","kind":"markdown"},{"code":"query getCommitBranches(\n\t$owner: String!\n\t$repo: String!\n\t$since: GitTimestamp!\n\t$until: GitTimestamp!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\trefs(first: 20, refPrefix: \"refs/heads/\", orderBy: { field: TAG_COMMIT_DATE, direction: DESC }) {\n\t\t\tnodes {\n\t\t\t\tname\n\t\t\t\ttarget {\n\t\t\t\t\t... on Commit {\n\t\t\t\t\t\thistory(first: 3, since: $since until: $until) {\n\t\t\t\t\t\t\tnodes { oid }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"since\": \"2022-01-06T01:07:46-04:00\",\n\t\"until\": \"2022-01-06T01:07:46-05:00\"\n}","kind":"code"},{"code":"query getCommitBranch(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n\t$since: GitTimestamp!\n\t$until: GitTimestamp!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tref(qualifiedName: $ref) {\n\t\t\ttarget {\n\t\t\t\t... on Commit {\n\t\t\t\t\thistory(first: 3, since: $since until: $until) {\n\t\t\t\t\t\tnodes { oid }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"refs/heads/main\",\n\t\"since\": \"2022-01-06T01:07:46-04:00\",\n\t\"until\": \"2022-01-06T01:07:46-05:00\"\n}","kind":"code"},{"code":"### Get commit count for branch (ref)","kind":"markdown"},{"code":"query getCommitCount(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tref(qualifiedName: $ref) {\n\t\t\ttarget {\n\t\t\t\t... on Commit {\n\t\t\t\t\thistory(first: 1) {\n\t\t\t\t\t\ttotalCount\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"refs/heads/main\"\n}","kind":"code"}]} \ No newline at end of file +{"cells":[{"code":"### Get Default Branch & Tip","kind":"markdown"},{"code":"query getDefaultBranchAndTip(\n\t$owner: String!\n\t$repo: String!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tdefaultBranchRef {\n\t\t\tname\n\t\t\ttarget { oid }\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Get Branches","kind":"markdown"},{"code":"query getBranches(\n\t$owner: String!\n\t$repo: String!\n\t$branchQuery: String\n\t$cursor: String\n\t$limit: Int = 100\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\trefs(query: $branchQuery, refPrefix: \"refs/heads/\", first: $limit, after: $cursor, orderBy: { field: TAG_COMMIT_DATE, direction: DESC }) {\n\t\t\tpageInfo {\n\t\t\t\tendCursor\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\tname\n\t\t\t\ttarget {\n\t\t\t\t\toid\n\t\t\t\t\tcommitUrl\n\t\t\t\t\t...on Commit {\n\t\t\t\t\t\tauthoredDate\n\t\t\t\t\t\tcommittedDate\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Get Blame","kind":"markdown"},{"code":"query getBlame(\n\t$owner: String!\n\t$repo: String!\n\t$ref: GitObjectID!\n\t$path: String!\n) {\n\tviewer { name }\n\trepository(owner: $owner, name: $repo) {\n\t\tobject(oid: $ref) {\n\t\t\t...on Commit {\n\t\t\t\tblame(path: $path) {\n\t\t\t\t\tranges {\n\t\t\t\t\t\tstartingLine\n\t\t\t\t\t\tendingLine\n\t\t\t\t\t\tage\n\t\t\t\t\t\tcommit {\n\t\t\t\t\t\t\toid\n\t\t\t\t\t\t\tparents(first: 3) { nodes { oid } }\n\t\t\t\t\t\t\tmessage\n\t\t\t\t\t\t\tauthor {\n\t\t\t\t\t\t\t\tavatarUrl\n\t\t\t\t\t\t\t\tdate\n\t\t\t\t\t\t\t\temail\n\t\t\t\t\t\t\t\tname\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcommitter { date }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"54f28933055124d6ba3808a787f6947c929f9db0\",\n\t\"path\": \"src/keyboard.ts\"\n}","kind":"code"},{"code":"### Get Commit for File","kind":"markdown"},{"code":"query getCommitForFile(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n\t$path: String!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tref(qualifiedName: $ref) {\n\t\t\ttarget {\n\t\t\t\t... on Commit {\n\t\t\t\t\thistory(first: 1, path: $path) {\n\t\t\t\t\t\tnodes {\n\t\t\t\t\t\t\toid\n\t\t\t\t\t\t\tparents(first: 3) { nodes { oid } }\n\t\t\t\t\t\t\tmessage\n\t\t\t\t\t\t\tadditions\n\t\t\t\t\t\t\tchangedFiles\n\t\t\t\t\t\t\tdeletions\n\t\t\t\t\t\t\tauthor {\n\t\t\t\t\t\t\t\tdate\n\t\t\t\t\t\t\t\temail\n\t\t\t\t\t\t\t\tname\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcommitter { date }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"refs/heads/main\",\n\t\"path\": \"src/extension.ts\"\n}","kind":"code"},{"code":"### Get Current User","kind":"markdown"},{"code":"query getCurrentUser(\n\t$owner: String!\n\t$repo: String!\n) {\n\tviewer { name }\n\trepository(name: $repo owner: $owner) {\n\t\tviewerPermission\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Get Commit","kind":"markdown"},{"code":"query getCommit(\n\t$owner: String!\n\t$repo: String!\n\t$ref: GitObjectID!\n) {\n\trepository(name: $repo owner: $owner) {\n\t\tobject(oid: $ref) {\n\t\t\t...on Commit {\n\t\t\t\toid\n\t\t\t\tparents(first: 3) { nodes { oid } }\n\t\t\t\tmessage\n\t\t\t\tadditions\n\t\t\t\tchangedFiles\n\t\t\t\tdeletions\n\t\t\t\tauthor {\n\t\t\t\t\tdate\n\t\t\t\t\temail\n\t\t\t\t\tname\n\t\t\t\t}\n\t\t\t\tcommitter { date }\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"54f28933055124d6ba3808a787f6947c929f9db0\"\n}","kind":"code"},{"code":"### Get Commits","kind":"markdown"},{"code":"query getCommits(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n\t$path: String\n\t$author: CommitAuthor\n\t$cursor: String\n\t$limit: Int = 100\n) {\n\tviewer { name }\n\trepository(name: $repo, owner: $owner) {\n\t\tobject(expression: $ref) {\n\t\t\t... on Commit {\n\t\t\t\thistory(first: $limit, author: $author, path: $path, after: $cursor) {\n\t\t\t\t\tpageInfo {\n\t\t\t\t\t\tendCursor\n\t\t\t\t\t\thasNextPage\n\t\t\t\t\t}\n\t\t\t\t\tnodes {\n\t\t\t\t\t\t... on Commit {\n\t\t\t\t\t\t\toid\n\t\t\t\t\t\t\tmessage\n\t\t\t\t\t\t\tparents(first: 3) { nodes { oid } }\n\t\t\t\t\t\t\tadditions\n\t\t\t\t\t\t\tchangedFiles\n\t\t\t\t\t\t\tdeletions\n\t\t\t\t\t\t\tauthor {\n\t\t\t\t\t\t\t\tavatarUrl\n\t\t\t\t\t\t\t\tdate\n\t\t\t\t\t\t\t\temail\n\t\t\t\t\t\t\t\tname\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcommitter {\n\t\t\t\t\t\t\t\t date\n\t\t\t\t\t\t\t\t email\n\t\t\t\t\t\t\t\t name\n\t\t\t\t\t\t\t }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"5374a1de9b3a46eb43d2863529839e8b1870814e~1\",\n\t\"path\": \"src/extension.ts\"\n}","kind":"code"},{"code":"### Get Tags","kind":"markdown"},{"code":"query getTags(\n\t$owner: String!\n\t$repo: String!\n\t$tagQuery: String\n\t$cursor: String\n\t$limit: Int = 100\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\trefs(query: $tagQuery, refPrefix: \"refs/tags/\", first: $limit, after: $cursor, orderBy: { field: TAG_COMMIT_DATE, direction: DESC }) {\n\t\t\tpageInfo {\n\t\t\t\tendCursor\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\tname\n\t\t\t\ttarget {\n\t\t\t\t\toid\n\t\t\t\t\tcommitUrl\n\t\t\t\t\t...on Commit {\n\t\t\t\t\t\tauthoredDate\n\t\t\t\t\t\tcommittedDate\n\t\t\t\t\t\tmessage\n\t\t\t\t\t}\n\t\t\t\t\t...on Tag {\n\t\t\t\t\t\tmessage\n\t\t\t\t\t\ttagger { date }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Get collaborators ","kind":"markdown"},{"code":"query getCollaborators (\n\t$owner: String!\n\t$repo: String!\n\t$cursor: String\n\t$limit: Int = 100\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tcollaborators(affiliation: ALL, first: $limit, after: $cursor) {\n\t\t\tpageInfo {\n\t\t\t\tendCursor\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\tname\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\"\n}","kind":"code"},{"code":"### Resolve reference","kind":"markdown"},{"code":"query resolveReference(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n\t$path: String!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tobject(expression: $ref) {\n\t\t\t... on Commit {\n\t\t\t\thistory(first: 1, path: $path) {\n\t\t\t\t\tnodes { oid }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"d790e9db047769de079f6838c3578f3a47bf5930^\",\n\t\"path\": \"CODE_OF_CONDUCT.md\"\n}","kind":"code"},{"code":"### Get branches that contain commit","kind":"markdown"},{"code":"query getCommitBranches(\n\t$owner: String!\n\t$repo: String!\n\t$since: GitTimestamp!\n\t$until: GitTimestamp!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\trefs(first: 20, refPrefix: \"refs/heads/\", orderBy: { field: TAG_COMMIT_DATE, direction: DESC }) {\n\t\t\tnodes {\n\t\t\t\tname\n\t\t\t\ttarget {\n\t\t\t\t\t... on Commit {\n\t\t\t\t\t\thistory(first: 3, since: $since until: $until) {\n\t\t\t\t\t\t\tnodes { oid }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"since\": \"2022-01-06T01:07:46-04:00\",\n\t\"until\": \"2022-01-06T01:07:46-05:00\"\n}","kind":"code"},{"code":"query getCommitBranch(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n\t$since: GitTimestamp!\n\t$until: GitTimestamp!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tref(qualifiedName: $ref) {\n\t\t\ttarget {\n\t\t\t\t... on Commit {\n\t\t\t\t\thistory(first: 3, since: $since until: $until) {\n\t\t\t\t\t\tnodes { oid }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"refs/heads/main\",\n\t\"since\": \"2022-01-06T01:07:46-04:00\",\n\t\"until\": \"2022-01-06T01:07:46-05:00\"\n}","kind":"code"},{"code":"### Get commit count for branch (ref)","kind":"markdown"},{"code":"query getCommitCount(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n) {\n\trepository(owner: $owner, name: $repo) {\n\t\tref(qualifiedName: $ref) {\n\t\t\ttarget {\n\t\t\t\t... on Commit {\n\t\t\t\t\thistory(first: 1) {\n\t\t\t\t\t\ttotalCount\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"refs/heads/main\"\n}","kind":"code"},{"code":"query getCommitRefs(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n\t$path: String\n\t$since: GitTimestamp\n\t$until: GitTimestamp\n\t$limit: Int = 1\n) {\n\tviewer { name }\n\trepository(name: $repo, owner: $owner) {\n\t\tref(qualifiedName: $ref) {\n\t\t\thistory(first: $limit, path: $path, since: $since, until: $until) {\n\t\t\t\tnodes { oid, message }\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"refs/heads/main\",\n\t\"path\": \"extension.ts\",\n\t\"limit\": 2\n}","kind":"code"},{"code":"query getCommit(\n\t$owner: String!\n\t$repo: String!\n\t$ref: GitObjectID!\n) {\n\trepository(name: $repo owner: $owner) {\n\t\tobject(oid: $ref) {\n\t\t\t...on Commit {\n\t\t\t\toid\n\t\t\t\tparents(first: 3) { nodes { oid } }\n\t\t\t\tmessage\n\t\t\t\tadditions\n\t\t\t\tchangedFiles\n\t\t\t\tdeletions\n\t\t\t\tauthor {\n\t\t\t\t\tdate\n\t\t\t\t\temail\n\t\t\t\t\tname\n\t\t\t\t}\n\t\t\t\tcommitter { date }\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"54f28933055124d6ba3808a787f6947c929f9db0\"\n}","kind":"code"},{"code":"query getCommitDate(\n\t$owner: String!\n\t$repo: String!\n\t$ref: GitObjectID!\n) {\n\trepository(name: $repo owner: $owner) {\n\t\tobject(oid: $ref) {\n\t\t\t...on Commit {\n\t\t\t\tcommitter { date }\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"a03ff942c40665c451bd4c7768f46e3e5f00e97c\"\n}","kind":"code"},{"code":"query getNextCommitCursor(\n\t$owner: String!\n\t$repo: String!\n\t$ref: String!\n\t$path: String!\n\t$since: GitTimestamp!\n) {\n\trepository(name: $repo owner: $owner) {\n\t\tobject(expression: $ref) {\n\t\t\t... on Commit {\n\t\t\t\thistory(first:1, path: $path, since: $since) {\n\t\t\t\t\ttotalCount\n\t\t\t\t\tpageInfo { startCursor }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"b062e960b6ee5ca7ac081dd84d9217bd4b2051e0\",\n \"path\": \"src/extension.ts\",\n \"since\": \"2021-11-03T02:46:29-04:00\"\n}","kind":"code"},{"code":"query getNextCommit(\n\t$owner: String!\n\t$repo: String!\n $ref: String!\n $path: String!\n\t$before: String!\n) {\trepository(name: $repo owner: $owner) {\n object(expression: $ref) {\n ... on Commit {\n history(last:4, path: $path, before: $before) {\n totalCount\n pageInfo {\n startCursor\n }\n nodes {\n oid\n message\n committedDate\n }\n }\n }\n }\n }\n}\n\nvariables {\n\t\"owner\": \"eamodio\",\n\t\"repo\": \"vscode-gitlens\",\n\t\"ref\": \"496c35eaeff2c33d3f1256a25d83198ace6aa6b0\",\n \"path\": \"src/extension.ts\",\n \"before\": \"496c35eaeff2c33d3f1256a25d83198ace6aa6b0 4\"\n}","kind":"code"}]} \ No newline at end of file diff --git a/src/commands/diffLineWithPrevious.ts b/src/commands/diffLineWithPrevious.ts index 0dcc5e81bf40d..75f2125a671fe 100644 --- a/src/commands/diffLineWithPrevious.ts +++ b/src/commands/diffLineWithPrevious.ts @@ -32,7 +32,7 @@ export class DiffLineWithPreviousCommand extends ActiveEditorCommand { const gitUri = args.commit?.getGitUri() ?? (await GitUri.fromUri(uri)); try { - const diffUris = await this.container.git.getPreviousLineDiffUris( + const diffUris = await this.container.git.getPreviousComparisonUrisForLine( gitUri.repoPath!, gitUri, args.line, diff --git a/src/commands/diffWithNext.ts b/src/commands/diffWithNext.ts index 273adcbd1609b..55a755716a9e3 100644 --- a/src/commands/diffWithNext.ts +++ b/src/commands/diffWithNext.ts @@ -41,7 +41,7 @@ export class DiffWithNextCommand extends ActiveEditorCommand { const gitUri = args.commit?.getGitUri() ?? (await GitUri.fromUri(uri)); try { - const diffUris = await this.container.git.getNextDiffUris( + const diffUris = await this.container.git.getNextComparisonUris( gitUri.repoPath!, gitUri, gitUri.sha, diff --git a/src/commands/diffWithPrevious.ts b/src/commands/diffWithPrevious.ts index 8bab0e188abab..958e13589dbc5 100644 --- a/src/commands/diffWithPrevious.ts +++ b/src/commands/diffWithPrevious.ts @@ -82,7 +82,7 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand { // } try { - const diffUris = await this.container.git.getPreviousDiffUris( + const diffUris = await this.container.git.getPreviousComparisonUris( gitUri.repoPath!, gitUri, gitUri.sha, diff --git a/src/commands/diffWithWorking.ts b/src/commands/diffWithWorking.ts index 3c3783703ff50..a1fe1fd933b7e 100644 --- a/src/commands/diffWithWorking.ts +++ b/src/commands/diffWithWorking.ts @@ -37,7 +37,11 @@ export class DiffWithWorkingCommand extends ActiveEditorCommand { if (args.inDiffRightEditor) { try { - const diffUris = await this.container.git.getPreviousDiffUris(gitUri.repoPath!, gitUri, gitUri.sha, 0); + const diffUris = await this.container.git.getPreviousComparisonUris( + gitUri.repoPath!, + gitUri, + gitUri.sha, + ); gitUri = diffUris?.previous ?? gitUri; } catch (ex) { Logger.error( diff --git a/src/commands/openFileAtRevision.ts b/src/commands/openFileAtRevision.ts index 5a3fef5c0953b..bae765ca33a2c 100644 --- a/src/commands/openFileAtRevision.ts +++ b/src/commands/openFileAtRevision.ts @@ -60,7 +60,7 @@ export class OpenFileAtRevisionCommand extends ActiveEditorCommand { const blame = await this.container.git.getBlameForLine(gitUri, editorLine); if (blame != null) { if (blame.commit.isUncommitted) { - const diffUris = await blame.commit.getPreviousLineDiffUris( + const diffUris = await blame.commit.getPreviousComparisonUrisForLine( gitUri, editorLine, gitUri.sha, diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 9c9281d6d53d4..5c904b96ee802 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -1073,7 +1073,7 @@ export class LocalGitProvider implements GitProvider, Disposable { @log() async getBlameForLine( uri: GitUri, - editorLine: number, + editorLine: number, // 0-based, Git is 1-based document?: TextDocument | undefined, options?: { forceSingleLine?: boolean }, ): Promise { @@ -1126,7 +1126,7 @@ export class LocalGitProvider implements GitProvider, Disposable { @log({ args: { 2: '' } }) async getBlameForLineContents( uri: GitUri, - editorLine: number, + editorLine: number, // 0-based, Git is 1-based contents: string, options?: { forceSingleLine?: boolean }, ): Promise { @@ -1831,7 +1831,7 @@ export class LocalGitProvider implements GitProvider, Disposable { @log() async getDiffForLine( uri: GitUri, - editorLine: number, + editorLine: number, // 0-based, Git is 1-based ref1: string | undefined, ref2?: string, ): Promise { @@ -2672,7 +2672,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log() - async getNextDiffUris( + async getNextComparisonUris( repoPath: string, uri: Uri, ref: string | undefined, @@ -2719,7 +2719,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log() - async getNextUri( + private async getNextUri( repoPath: string, uri: Uri, ref?: string, @@ -2775,7 +2775,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log() - async getPreviousDiffUris( + async getPreviousComparisonUris( repoPath: string, uri: Uri, ref: string | undefined, @@ -2852,10 +2852,10 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log() - async getPreviousLineDiffUris( + async getPreviousComparisonUrisForLine( repoPath: string, uri: Uri, - editorLine: number, + editorLine: number, // 0-based, Git is 1-based ref: string | undefined, skip: number = 0, ): Promise<{ current: GitUri; previous: GitUri | undefined; line: number } | undefined> { @@ -2971,7 +2971,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log() - async getPreviousUri( + private async getPreviousUri( repoPath: string, uri: Uri, ref?: string, diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index db80e7ba2158d..344ad7b7b1ff9 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -295,35 +295,26 @@ export interface GitProvider extends Disposable { ): Promise; getMergeStatus(repoPath: string): Promise; getRebaseStatus(repoPath: string): Promise; - getNextDiffUris( + getNextComparisonUris( repoPath: string, uri: Uri, ref: string | undefined, skip?: number, ): Promise<{ current: GitUri; next: GitUri | undefined; deleted?: boolean | undefined } | undefined>; - getNextUri(repoPath: string, uri: Uri, ref?: string, skip?: number): Promise; - getPreviousDiffUris( + getPreviousComparisonUris( repoPath: string, uri: Uri, ref: string | undefined, skip?: number, firstParent?: boolean, ): Promise<{ current: GitUri; previous: GitUri | undefined } | undefined>; - getPreviousLineDiffUris( + getPreviousComparisonUrisForLine( repoPath: string, uri: Uri, editorLine: number, ref: string | undefined, skip?: number, ): Promise<{ current: GitUri; previous: GitUri | undefined; line: number } | undefined>; - getPreviousUri( - repoPath: string, - uri: Uri, - ref?: string, - skip?: number, - editorLine?: number, - firstParent?: boolean, - ): Promise; getIncomingActivity( repoPath: string, options?: { diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index 194d5cb3a48a5..d5b85d9f73541 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -1264,75 +1264,44 @@ export class GitProviderService implements Disposable { } @log() - async getNextDiffUris( + getNextComparisonUris( repoPath: string | Uri, uri: Uri, ref: string | undefined, skip: number = 0, ): Promise<{ current: GitUri; next: GitUri | undefined; deleted?: boolean } | undefined> { - // If we have no ref (or staged ref) there is no next commit - if (ref == null || ref.length === 0) return undefined; + if (!ref) return Promise.resolve(undefined); const { provider, path } = this.getProvider(repoPath); - return provider.getNextDiffUris(path, uri, ref, skip); + return provider.getNextComparisonUris(path, uri, ref, skip); } @log() - async getNextUri( - repoPath: string | Uri, - uri: Uri, - ref?: string, - skip: number = 0, - // editorLine?: number - ): Promise { - // If we have no ref (or staged ref) there is no next commit - if (ref == null || ref.length === 0 || GitRevision.isUncommittedStaged(ref)) return undefined; - - const { provider, path } = this.getProvider(repoPath); - return provider.getNextUri(path, uri, ref, skip); - } - - @log() - async getPreviousDiffUris( + getPreviousComparisonUris( repoPath: string | Uri, uri: Uri, ref: string | undefined, skip: number = 0, firstParent: boolean = false, ): Promise<{ current: GitUri; previous: GitUri | undefined } | undefined> { - if (ref === GitRevision.deletedOrMissing) return undefined; + if (ref === GitRevision.deletedOrMissing) return Promise.resolve(undefined); const { provider, path } = this.getProvider(repoPath); - return provider.getPreviousDiffUris(path, uri, ref, skip, firstParent); + return provider.getPreviousComparisonUris(path, uri, ref, skip, firstParent); } @log() - async getPreviousLineDiffUris( + getPreviousComparisonUrisForLine( repoPath: string | Uri, uri: Uri, editorLine: number, ref: string | undefined, skip: number = 0, ): Promise<{ current: GitUri; previous: GitUri | undefined; line: number } | undefined> { - if (ref === GitRevision.deletedOrMissing) return undefined; - - const { provider, path } = this.getProvider(repoPath); - return provider.getPreviousLineDiffUris(path, uri, editorLine, ref, skip); - } - - @log() - async getPreviousUri( - repoPath: string | Uri, - uri: Uri, - ref?: string, - skip: number = 0, - editorLine?: number, - firstParent: boolean = false, - ): Promise { - if (ref === GitRevision.deletedOrMissing) return undefined; + if (ref === GitRevision.deletedOrMissing) return Promise.resolve(undefined); const { provider, path } = this.getProvider(repoPath); - return provider.getPreviousUri(path, uri, ref, skip, editorLine, firstParent); + return provider.getPreviousComparisonUrisForLine(path, uri, editorLine, ref, skip); } async getPullRequestForBranch( diff --git a/src/git/models/commit.ts b/src/git/models/commit.ts index 0516d18fa4b63..1eb202a2ef31a 100644 --- a/src/git/models/commit.ts +++ b/src/git/models/commit.ts @@ -406,10 +406,10 @@ export class GitCommit implements GitRevisionReference { }); } - @memoize((u, e, r) => `${u.toString()}|${e}|${r ?? ''}`) - getPreviousLineDiffUris(uri: Uri, editorLine: number, ref: string | undefined) { + @memoize((u, e, r) => `${u.toString()}|${e}|${r ?? ''}`) + getPreviousComparisonUrisForLine(uri: Uri, editorLine: number, ref: string | undefined) { return this.file?.path - ? this.container.git.getPreviousLineDiffUris(this.repoPath, uri, editorLine, ref) + ? this.container.git.getPreviousComparisonUrisForLine(this.repoPath, uri, editorLine, ref) : Promise.resolve(undefined); } @@ -494,7 +494,9 @@ export class GitCommitIdentity { export interface GitCommitLine { sha: string; previousSha?: string | undefined; + /** The original (previous) line number prior to this commit; 1-based */ originalLine: number; + /** The current line number in this commit; 1-based */ line: number; } diff --git a/src/hovers/hovers.ts b/src/hovers/hovers.ts index ffe4e5b1e2c30..8fb3ffc462e9e 100644 --- a/src/hovers/hovers.ts +++ b/src/hovers/hovers.ts @@ -15,7 +15,7 @@ export namespace Hovers { export async function changesMessage( commit: GitCommit, uri: GitUri, - editorLine: number, + editorLine: number, // 0-based, Git is 1-based document: TextDocument, ): Promise { const documentRef = uri.sha; @@ -76,7 +76,7 @@ export namespace Hovers { let previous; let current; if (commit.isUncommitted) { - const diffUris = await commit.getPreviousLineDiffUris(uri, editorLine, documentRef); + const diffUris = await commit.getPreviousComparisonUrisForLine(uri, editorLine, documentRef); if (diffUris?.previous == null) return undefined; message = `[$(compare-changes)](${DiffWithCommand.getMarkdownCommandArgs({ @@ -144,7 +144,7 @@ export namespace Hovers { export async function localChangesMessage( fromCommit: GitCommit | undefined, uri: GitUri, - editorLine: number, + editorLine: number, // 0-based, Git is 1-based hunk: GitDiffHunk, ): Promise { const diff = getDiffFromHunk(hunk); @@ -191,7 +191,7 @@ export namespace Hovers { export async function detailsMessage( commit: GitCommit, uri: GitUri, - editorLine: number, + editorLine: number, // 0-based, Git is 1-based format: string, dateFormat: string | null, options?: { @@ -224,7 +224,7 @@ export namespace Hovers { if (options?.cancellationToken?.isCancellationRequested) return new MarkdownString(); const [previousLineDiffUris, autolinkedIssuesOrPullRequests, pr, presence] = await Promise.all([ - commit.isUncommitted ? commit.getPreviousLineDiffUris(uri, editorLine, uri.sha) : undefined, + commit.isUncommitted ? commit.getPreviousComparisonUrisForLine(uri, editorLine, uri.sha) : undefined, getAutoLinkedIssuesOrPullRequests(message, remotes), options?.pullRequests?.pr ?? getPullRequestForCommit(commit.ref, remotes, { diff --git a/src/hovers/lineHoverController.ts b/src/hovers/lineHoverController.ts index 808d2b925266f..baa834b8b0544 100644 --- a/src/hovers/lineHoverController.ts +++ b/src/hovers/lineHoverController.ts @@ -116,23 +116,6 @@ export class LineHoverController implements Disposable { ); if (!wholeLine && range.start.character !== position.character) return undefined; - // // Get the full commit message -- since blame only returns the summary - // let logCommit = lineState?.logCommit; - // if (logCommit == null && !commit.isUncommitted) { - // logCommit = await this.container.git.getCommitForFile(commit.repoPath, commit.uri, { - // ref: commit.sha, - // }); - // if (logCommit != null) { - // // Preserve the previous commit from the blame commit - // logCommit.previousSha = commit.previousSha; - // logCommit.previousFileName = commit.previousFileName; - - // if (lineState != null) { - // lineState.logCommit = logCommit; - // } - // } - // } - let editorLine = position.line; const line = editorLine + 1; const commitLine = commit.lines.find(l => l.line === line) ?? commit.lines[0]; diff --git a/src/premium/github/github.ts b/src/premium/github/github.ts index 4cf4a5da1aed4..2d2842502d9a7 100644 --- a/src/premium/github/github.ts +++ b/src/premium/github/github.ts @@ -521,7 +521,6 @@ export class GitHubApi { ranges { startingLine endingLine - age commit { oid parents(first: 3) { nodes { oid } } @@ -1093,12 +1092,13 @@ export class GitHubApi { options?: { after?: string; before?: string; - limit?: number; + first?: number; + last?: number; path?: string; - since?: Date; - until?: Date; + since?: string; + until?: string; }, - ): Promise { + ): Promise | undefined> { const cc = Logger.getCorrelationContext(); interface QueryResult { @@ -1107,7 +1107,9 @@ export class GitHubApi { object: | { history: { - nodes: { oid: string }[]; + pageInfo: GitHubPageInfo; + totalCount: number; + nodes: GitHubCommitRef[]; }; } | null @@ -1124,7 +1126,8 @@ export class GitHubApi { $ref: String! $after: String $before: String - $limit: Int = 1 + $first: Int + $last: Int $path: String $since: GitTimestamp $until: GitTimestamp @@ -1132,7 +1135,9 @@ export class GitHubApi { repository(name: $repo, owner: $owner) { object(expression: $ref) { ... on Commit { - history(first: $limit, path: $path, since: $since, until: $until, after: $after, before: $before) { + history(first: $first, last: $last, path: $path, since: $since, until: $until, after: $after, before: $before) { + pageInfo { startCursor, endCursor, hasNextPage, hasPreviousPage } + totalCount nodes { oid } } } @@ -1145,19 +1150,102 @@ export class GitHubApi { repo: repo, ref: ref, path: options?.path, - limit: Math.max(1, options?.limit ?? 1), + first: options?.first, + last: options?.last, after: options?.after, before: options?.before, - since: options?.since?.toISOString(), - until: options?.until?.toISOString(), + since: options?.since, + until: options?.until, }); const history = rsp?.repository?.object?.history; - if (history == null) return []; + if (history == null) return undefined; - return history.nodes.map(n => n.oid); + return { + pageInfo: history.pageInfo, + totalCount: history.totalCount, + values: history.nodes, + }; } catch (ex) { debugger; - return this.handleRequestError(ex, cc, []); + return this.handleRequestError(ex, cc, undefined); + } + } + + @debug({ args: { 0: '' } }) + async getNextCommitRefs( + token: string, + owner: string, + repo: string, + ref: string, + path: string, + sha: string, + ): Promise { + // Get the commit date of the current commit + const commitDate = await this.getCommitDate(token, owner, repo, sha); + if (commitDate == null) return []; + + // Get a resultset (just need the cursor and totals), to get the page info we need to construct a cursor to page backwards + let result = await this.getCommitRefs(token, owner, repo, ref, { path: path, first: 1, since: commitDate }); + if (result == null) return []; + + // Construct a cursor to allow use to walk backwards in time (starting at the tip going back in time until the commit date) + const cursor = `${result.pageInfo.startCursor!.split(' ', 1)[0]} ${result.totalCount}`; + + let last; + [, last] = cursor.split(' ', 2); + // We can't ask for more commits than are left in the cursor (but try to get more to be safe, since the date isn't exact enough) + last = Math.min(parseInt(last, 10), 5); + + // Get the set of refs before the cursor + result = await this.getCommitRefs(token, owner, repo, ref, { path: path, last: last, before: cursor }); + if (result == null) return []; + + const nexts: string[] = []; + + for (const { oid } of result.values) { + if (oid === sha) break; + + nexts.push(oid); + } + + return nexts.reverse(); + } + + private async getCommitDate(token: string, owner: string, repo: string, sha: string): Promise { + const cc = Logger.getCorrelationContext(); + + interface QueryResult { + repository: + | { + object: { committer: { date: string } } | null | undefined; + } + | null + | undefined; + } + + try { + const query = `query getCommitDate( + $owner: String! + $repo: String! + $sha: GitObjectID! +) { + repository(name: $repo, owner: $owner) { + object(oid: $sha) { + ... on Commit { committer { date } } + } + } +}`; + + const rsp = await this.graphql(token, query, { + owner: owner, + repo: repo, + sha: sha, + }); + const date = rsp?.repository?.object?.committer.date; + return date; + } catch (ex) { + debugger; + return this.handleRequestError(ex, cc, undefined); } } @@ -1549,7 +1637,6 @@ export interface GitHubBlame { export interface GitHubBlameRange { startingLine: number; endingLine: number; - age: number; commit: GitHubCommit; } @@ -1576,6 +1663,10 @@ export interface GitHubCommit { files?: Endpoints['GET /repos/{owner}/{repo}/commits/{ref}']['response']['data']['files']; } +export interface GitHubCommitRef { + oid: string; +} + export type GitHubContributor = Endpoints['GET /repos/{owner}/{repo}/contributors']['response']['data'][0]; interface GitHubIssueOrPullRequest { @@ -1588,6 +1679,19 @@ interface GitHubIssueOrPullRequest { url: string; } +export interface GitHubPagedResult { + pageInfo: GitHubPageInfo; + totalCount: number; + values: T[]; +} + +interface GitHubPageInfo { + startCursor?: string | null; + endCursor?: string | null; + hasNextPage: boolean; + hasPreviousPage: boolean; +} + type GitHubPullRequestState = 'OPEN' | 'CLOSED' | 'MERGED'; interface GitHubPullRequest { diff --git a/src/premium/github/githubGitProvider.ts b/src/premium/github/githubGitProvider.ts index 4deb313a208f0..9c10fec3c2e4e 100644 --- a/src/premium/github/githubGitProvider.ts +++ b/src/premium/github/githubGitProvider.ts @@ -402,7 +402,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { // const sha = await this.resolveReferenceCore(uri.repoPath!, metadata, uri.sha); // if (sha == null) return undefined; - const ref = uri.sha ?? 'HEAD'; + const ref = uri.sha ?? (await metadata.getRevision()).revision; const blame = await github.getBlame( session?.accessToken, metadata.repo.owner, @@ -453,6 +453,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { } for (let i = range.startingLine; i <= range.endingLine; i++) { + // GitHub doesn't currently support returning the original line number, so we are just using the current one const line: GitCommitLine = { sha: c.oid, originalLine: i, line: i }; commit.lines.push(line); @@ -500,7 +501,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { @log() async getBlameForLine( uri: GitUri, - editorLine: number, + editorLine: number, // 0-based, Git is 1-based document?: TextDocument | undefined, options?: { forceSingleLine?: boolean }, ): Promise { @@ -547,7 +548,8 @@ export class GitHubGitProvider implements GitProvider, Disposable { relativePath, ); - const range = blame.ranges.find(r => r.startingLine === editorLine); + const startingLine = editorLine + 1; + const range = blame.ranges.find(r => r.startingLine === startingLine); if (range == null) return undefined; const c = range.commit; @@ -571,6 +573,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { ); for (let i = range.startingLine; i <= range.endingLine; i++) { + // GitHub doesn't currently support returning the original line number, so we are just using the current one const line: GitCommitLine = { sha: c.oid, originalLine: i, line: i }; commit.lines.push(line); @@ -582,7 +585,8 @@ export class GitHubGitProvider implements GitProvider, Disposable { lineCount: range.endingLine - range.startingLine + 1, }, commit: commit, - line: { sha: c.oid, originalLine: range.startingLine, line: editorLine }, + // GitHub doesn't currently support returning the original line number, so we are just using the current one + line: { sha: c.oid, originalLine: range.startingLine, line: range.startingLine }, }; } catch (ex) { debugger; @@ -594,7 +598,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { @log({ args: { 2: '' } }) async getBlameForLineContents( _uri: GitUri, - _editorLine: number, + _editorLine: number, // 0-based, Git is 1-based _contents: string, _options?: { forceSingleLine?: boolean }, ): Promise { @@ -917,7 +921,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { session?.accessToken, metadata.repo.owner, metadata.repo.name, - options?.ref ?? 'HEAD', + options?.ref ?? (await metadata.getRevision()).revision, file, ); if (commit == null) return undefined; @@ -1080,7 +1084,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { @log() async getDiffForLine( _uri: GitUri, - _editorLine: number, + _editorLine: number, // 0-based, Git is 1-based _ref1: string | undefined, _ref2?: string, ): Promise { @@ -1134,7 +1138,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { try { const { metadata, github, session } = await this.ensureRepositoryContext(repoPath); - const ref = options?.ref ?? 'HEAD'; + const ref = options?.ref ?? (await metadata.getRevision()).revision; const result = await github.getCommits(session?.accessToken, metadata.repo.owner, metadata.repo.name, ref, { all: options?.all, authors: options?.authors, @@ -1518,7 +1522,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { // range = new Range(range.end, range.start); // } - const ref = options?.ref ?? 'HEAD'; + const ref = options?.ref ?? (await metadata.getRevision()).revision; const result = await github.getCommits(session?.accessToken, metadata.repo.owner, metadata.repo.name, ref, { all: options?.all, cursor: options?.cursor, @@ -1710,119 +1714,57 @@ export class GitHubGitProvider implements GitProvider, Disposable { } @log() - async getNextDiffUris( + async getNextComparisonUris( repoPath: string, uri: Uri, ref: string | undefined, skip: number = 0, ): Promise<{ current: GitUri; next: GitUri | undefined; deleted?: boolean } | undefined> { - // If we have no ref (or staged ref) there is no next commit + // If we have no ref there is no next commit if (!ref) return undefined; - const relativePath = this.getRelativePath(uri, repoPath); - - return { - current: - skip === 0 - ? GitUri.fromFile(relativePath, repoPath, ref) - : (await this.getNextUri(repoPath, uri, ref, skip - 1))!, - next: await this.getNextUri(repoPath, uri, ref, skip), - }; - } - - @log() - async getNextUri( - _repoPath: string, - _uri: Uri, - ref?: string, - _skip: number = 0, - // editorLine?: number - ): Promise { - // If we have no ref (or staged ref) there is no next commit - if (!ref || GitRevision.isUncommittedStaged(ref)) return undefined; - return undefined; - - // const cc = Logger.getCorrelationContext(); - - // // const relativePath = this.getRelativePath(uri, repoPath); - - // try { - // const context = await this.ensureRepositoryContext(repoPath); - // if (context == null) return undefined; - // const { metadata, github, remotehub, session } = context; + const cc = Logger.getCorrelationContext(); - // const relativePath = this.getRelativePath(uri, remotehub.getProviderRootUri(uri)); + try { + const context = await this.ensureRepositoryContext(repoPath); + if (context == null) return undefined; - // const refs = await github.getCommitRefs( - // session.accessToken, - // metadata.repo.owner, - // metadata.repo.name, - // ref ?? 'HEAD', - // { - // path: relativePath, - // limit: skip + 2, - // before: `${ref} 0`, - // }, - // ); + const { metadata, github, remotehub, session } = context; + const relativePath = this.getRelativePath(uri, remotehub.getProviderRootUri(uri)); + const revision = await metadata.getRevision(); - // const nextRef = refs[skip]; - // if (nextRef == null) return undefined; + const refs = await github.getNextCommitRefs( + session.accessToken, + metadata.repo.owner, + metadata.repo.name, + revision.revision, + relativePath, + ref, + ); - // const next = await this.getBestRevisionUri(repoPath, relativePath, nextRef); - // return new GitUri(next); - // } catch (ex) { - // Logger.error(ex, cc); - // debugger; + return { + current: + skip === 0 + ? GitUri.fromFile(relativePath, repoPath, ref) + : new GitUri(await this.getBestRevisionUri(repoPath, relativePath, refs[skip - 1])), + next: new GitUri(await this.getBestRevisionUri(repoPath, relativePath, refs[skip])), + }; + } catch (ex) { + Logger.error(ex, cc); + debugger; - // throw ex; - // } + throw ex; + } } @log() - async getPreviousDiffUris( + async getPreviousComparisonUris( repoPath: string, uri: Uri, ref: string | undefined, skip: number = 0, - firstParent: boolean = false, - ): Promise<{ current: GitUri; previous: GitUri | undefined } | undefined> { - if (ref === GitRevision.deletedOrMissing) return undefined; - - const relativePath = this.getRelativePath(uri, repoPath); - - // If we are at a commit, diff commit with previous - const current = - skip === 0 - ? GitUri.fromFile(relativePath, repoPath, ref) - : (await this.getPreviousUri(repoPath, uri, ref, skip - 1, undefined, firstParent))!; - if (current == null || current.sha === GitRevision.deletedOrMissing) return undefined; - - return { - current: current, - previous: await this.getPreviousUri(repoPath, uri, ref, skip, undefined, firstParent), - }; - } - - @log() - async getPreviousLineDiffUris( - _repoPath: string, - _uri: Uri, - _editorLine: number, - _ref: string | undefined, - _skip: number = 0, - ): Promise<{ current: GitUri; previous: GitUri | undefined; line: number } | undefined> { - return undefined; - } - - @log() - async getPreviousUri( - repoPath: string, - uri: Uri, - ref?: string, - skip: number = 0, - _editorLine?: number, _firstParent: boolean = false, - ): Promise { + ): Promise<{ current: GitUri; previous: GitUri | undefined } | undefined> { if (ref === GitRevision.deletedOrMissing) return undefined; const cc = Logger.getCorrelationContext(); @@ -1834,29 +1776,113 @@ export class GitHubGitProvider implements GitProvider, Disposable { try { const context = await this.ensureRepositoryContext(repoPath); if (context == null) return undefined; - const { metadata, github, remotehub, session } = context; + const { metadata, github, remotehub, session } = context; const relativePath = this.getRelativePath(uri, remotehub.getProviderRootUri(uri)); const offset = ref != null ? 1 : 0; - const refs = await github.getCommitRefs( + const result = await github.getCommitRefs( session.accessToken, metadata.repo.owner, metadata.repo.name, - ref ?? 'HEAD', + ref ? ref : (await metadata.getRevision()).revision, { path: relativePath, - limit: offset + skip + 1, + first: offset + skip + 1, }, ); + if (result == null) return undefined; - const previous = await this.getBestRevisionUri( - repoPath, - relativePath, - refs[offset + skip] ?? GitRevision.deletedOrMissing, - ); - return new GitUri(previous); + // If we are at a commit, diff commit with previous + const current = + skip === 0 + ? GitUri.fromFile(relativePath, repoPath, ref) + : new GitUri( + await this.getBestRevisionUri( + repoPath, + relativePath, + result.values[offset + skip - 1]?.oid ?? GitRevision.deletedOrMissing, + ), + ); + if (current == null || current.sha === GitRevision.deletedOrMissing) return undefined; + + return { + current: current, + previous: new GitUri( + await this.getBestRevisionUri( + repoPath, + relativePath, + result.values[offset + skip]?.oid ?? GitRevision.deletedOrMissing, + ), + ), + }; + } catch (ex) { + Logger.error(ex, cc); + debugger; + + throw ex; + } + } + + @log() + async getPreviousComparisonUrisForLine( + repoPath: string, + uri: Uri, + editorLine: number, // 0-based, Git is 1-based + ref: string | undefined, + skip: number = 0, + ): Promise<{ current: GitUri; previous: GitUri | undefined; line: number } | undefined> { + if (ref === GitRevision.deletedOrMissing) return undefined; + + const cc = Logger.getCorrelationContext(); + + try { + const context = await this.ensureRepositoryContext(repoPath); + if (context == null) return undefined; + + const { remotehub } = context; + + let relativePath = this.getRelativePath(uri, remotehub.getProviderRootUri(uri)); + + // FYI, GitHub doesn't currently support returning the original line number, nor the previous sha, so this is untrustworthy + + let current = GitUri.fromFile(relativePath, repoPath, ref); + let currentLine = editorLine; + let previous; + let previousLine = editorLine; + let nextLine = editorLine; + + for (let i = 0; i < Math.max(0, skip) + 2; i++) { + const blameLine = await this.getBlameForLine(previous ?? current, nextLine, undefined, { + forceSingleLine: true, + }); + if (blameLine == null) break; + + // Diff with line ref with previous + ref = blameLine.commit.sha; + relativePath = blameLine.commit.file?.path ?? blameLine.commit.file?.originalPath ?? relativePath; + nextLine = blameLine.line.originalLine - 1; + + const gitUri = GitUri.fromFile(relativePath, repoPath, ref); + if (previous == null) { + previous = gitUri; + previousLine = nextLine; + } else { + current = previous; + currentLine = previousLine; + previous = gitUri; + previousLine = nextLine; + } + } + + if (current == null) return undefined; + + return { + current: current, + previous: previous, + line: (currentLine ?? editorLine) + 1, // 1-based + }; } catch (ex) { Logger.error(ex, cc); debugger;