Loading package.json +17 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,12 @@ "dark": "src/assets/images/dark/refresh.svg" } }, { "command": "gl.openMrFile", "title": "Open Changed File In Local Project", "category": "GitLab", "icon": "$(go-to-file)" }, { "command": "gl.resolveThread", "title": "Resolve Thread", Loading Loading @@ -240,6 +246,10 @@ "command": "gl.checkoutMrBranch", "when": "false" }, { "command": "gl.openMrFile", "when": "false" }, { "command": "gl.showIssuesAssignedToMe", "when": "gitlab:validState" Loading Loading @@ -390,6 +400,13 @@ "group": "inline", "when": "commentController =~ /^gitlab-mr-/" } ], "editor/title": [ { "command": "gl.openMrFile", "when": "resourceScheme == 'gl-review' && resourceFilename != '' && isInDiffEditor", "group": "navigation@-99" } ] }, "viewsContainers": { Loading src/command_names.ts +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ export const USER_COMMANDS = { CLONE_WIKI: 'gl.cloneWiki', CREATE_SNIPPET_PATCH: 'gl.createSnippetPatch', APPLY_SNIPPET_PATCH: 'gl.applySnippetPatch', OPEN_MR_FILE: 'gl.openMrFile', }; /* Loading src/commands/open_mr_file.test.ts 0 → 100644 +45 −0 Original line number Diff line number Diff line import * as vscode from 'vscode'; import * as fs from 'fs'; import { VS_COMMANDS } from '../command_names'; import { toReviewUri } from '../review/review_uri'; import { mrVersion, reviewUriParams } from '../test_utils/entities'; import { openMrFile } from './open_mr_file'; import { gitExtensionWrapper } from '../git/git_extension_wrapper'; import { WrappedRepository } from '../git/wrapped_repository'; import { asMock } from '../test_utils/as_mock'; jest.mock('fs', () => ({ promises: { access: jest.fn(), }, })); describe('openMrFile', () => { beforeEach(() => { jest .spyOn(gitExtensionWrapper, 'getRepository') .mockReturnValue(({ getMr: () => ({ mrVersion }) } as unknown) as WrappedRepository); asMock(fs.promises.access).mockResolvedValue(undefined); }); it('calls VS Code open with the correct diff file', async () => { await openMrFile(toReviewUri({ ...reviewUriParams, path: 'new_file.js' })); expect(vscode.commands.executeCommand).toHaveBeenCalledWith( VS_COMMANDS.OPEN, vscode.Uri.file('/new_file.js'), ); }); it("calls shows information message when the file doesn't exist", async () => { asMock(fs.promises.access).mockRejectedValue(new Error()); await openMrFile(toReviewUri({ ...reviewUriParams, path: 'new_file.js' })); expect(vscode.commands.executeCommand).not.toHaveBeenCalled(); expect(vscode.window.showWarningMessage).toHaveBeenCalled(); }); it("throws assertion error if the diff can't be found", async () => { await expect( openMrFile(toReviewUri({ ...reviewUriParams, path: 'file_that_is_not_in_mr_diff.c' })), ).rejects.toThrowError(/Extension did not find the file/); }); }); src/commands/open_mr_file.ts 0 → 100644 +39 −0 Original line number Diff line number Diff line import * as vscode from 'vscode'; import * as path from 'path'; import * as assert from 'assert'; import { promises as fs } from 'fs'; import { VS_COMMANDS } from '../command_names'; import { fromReviewUri } from '../review/review_uri'; import { gitExtensionWrapper } from '../git/git_extension_wrapper'; import { removeLeadingSlash } from '../utils/remove_leading_slash'; /** returns true if file exists, false if it doesn't */ const tryToOpen = async (filePath: string): Promise<boolean> => { try { await fs.access(filePath); // throws if file doesn't exist } catch (e) { return false; } await vscode.commands.executeCommand(VS_COMMANDS.OPEN, vscode.Uri.file(filePath)); return true; }; const findDiffWithPath = (diffs: RestDiffFile[], relativePath: string): RestDiffFile | undefined => diffs.find(d => d.new_path === relativePath || d.old_path === relativePath); export const openMrFile = async (uri: vscode.Uri): Promise<void> => { const params = fromReviewUri(uri); assert(params.path); const repository = gitExtensionWrapper.getRepository(params.repositoryRoot); const cachedMr = repository.getMr(params.mrId); assert(cachedMr); const diff = findDiffWithPath(cachedMr.mrVersion.diffs, removeLeadingSlash(params.path)); assert(diff, 'Extension did not find the file in the MR, please refresh the side panel.'); const getFullPath = (relative: string) => path.join(params.repositoryRoot, relative); const opened = (await tryToOpen(getFullPath(diff.new_path))) || (await tryToOpen(getFullPath(diff.old_path))); if (!opened) await vscode.window.showWarningMessage( `The file ${params.path} doesn't exist in your local project`, ); }; src/extension.js +2 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ const { checkoutMrBranch } = require('./commands/checkout_mr_branch'); const { cloneWiki } = require('./commands/clone_wiki'); const { createSnippetPatch } = require('./commands/create_snippet_patch'); const { applySnippetPatch } = require('./commands/apply_snippet_patch'); const { openMrFile } = require('./commands/open_mr_file'); const wrapWithCatch = command => async (...args) => { try { Loading Loading @@ -89,6 +90,7 @@ const registerCommands = (context, outputChannel) => { issuableDataProvider.refresh(); currentBranchDataProvider.refresh(); }, [USER_COMMANDS.OPEN_MR_FILE]: openMrFile, [PROGRAMMATIC_COMMANDS.NO_IMAGE_REVIEW]: () => vscode.window.showInformationMessage("GitLab MR review doesn't support images yet."), }; Loading Loading
package.json +17 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,12 @@ "dark": "src/assets/images/dark/refresh.svg" } }, { "command": "gl.openMrFile", "title": "Open Changed File In Local Project", "category": "GitLab", "icon": "$(go-to-file)" }, { "command": "gl.resolveThread", "title": "Resolve Thread", Loading Loading @@ -240,6 +246,10 @@ "command": "gl.checkoutMrBranch", "when": "false" }, { "command": "gl.openMrFile", "when": "false" }, { "command": "gl.showIssuesAssignedToMe", "when": "gitlab:validState" Loading Loading @@ -390,6 +400,13 @@ "group": "inline", "when": "commentController =~ /^gitlab-mr-/" } ], "editor/title": [ { "command": "gl.openMrFile", "when": "resourceScheme == 'gl-review' && resourceFilename != '' && isInDiffEditor", "group": "navigation@-99" } ] }, "viewsContainers": { Loading
src/command_names.ts +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ export const USER_COMMANDS = { CLONE_WIKI: 'gl.cloneWiki', CREATE_SNIPPET_PATCH: 'gl.createSnippetPatch', APPLY_SNIPPET_PATCH: 'gl.applySnippetPatch', OPEN_MR_FILE: 'gl.openMrFile', }; /* Loading
src/commands/open_mr_file.test.ts 0 → 100644 +45 −0 Original line number Diff line number Diff line import * as vscode from 'vscode'; import * as fs from 'fs'; import { VS_COMMANDS } from '../command_names'; import { toReviewUri } from '../review/review_uri'; import { mrVersion, reviewUriParams } from '../test_utils/entities'; import { openMrFile } from './open_mr_file'; import { gitExtensionWrapper } from '../git/git_extension_wrapper'; import { WrappedRepository } from '../git/wrapped_repository'; import { asMock } from '../test_utils/as_mock'; jest.mock('fs', () => ({ promises: { access: jest.fn(), }, })); describe('openMrFile', () => { beforeEach(() => { jest .spyOn(gitExtensionWrapper, 'getRepository') .mockReturnValue(({ getMr: () => ({ mrVersion }) } as unknown) as WrappedRepository); asMock(fs.promises.access).mockResolvedValue(undefined); }); it('calls VS Code open with the correct diff file', async () => { await openMrFile(toReviewUri({ ...reviewUriParams, path: 'new_file.js' })); expect(vscode.commands.executeCommand).toHaveBeenCalledWith( VS_COMMANDS.OPEN, vscode.Uri.file('/new_file.js'), ); }); it("calls shows information message when the file doesn't exist", async () => { asMock(fs.promises.access).mockRejectedValue(new Error()); await openMrFile(toReviewUri({ ...reviewUriParams, path: 'new_file.js' })); expect(vscode.commands.executeCommand).not.toHaveBeenCalled(); expect(vscode.window.showWarningMessage).toHaveBeenCalled(); }); it("throws assertion error if the diff can't be found", async () => { await expect( openMrFile(toReviewUri({ ...reviewUriParams, path: 'file_that_is_not_in_mr_diff.c' })), ).rejects.toThrowError(/Extension did not find the file/); }); });
src/commands/open_mr_file.ts 0 → 100644 +39 −0 Original line number Diff line number Diff line import * as vscode from 'vscode'; import * as path from 'path'; import * as assert from 'assert'; import { promises as fs } from 'fs'; import { VS_COMMANDS } from '../command_names'; import { fromReviewUri } from '../review/review_uri'; import { gitExtensionWrapper } from '../git/git_extension_wrapper'; import { removeLeadingSlash } from '../utils/remove_leading_slash'; /** returns true if file exists, false if it doesn't */ const tryToOpen = async (filePath: string): Promise<boolean> => { try { await fs.access(filePath); // throws if file doesn't exist } catch (e) { return false; } await vscode.commands.executeCommand(VS_COMMANDS.OPEN, vscode.Uri.file(filePath)); return true; }; const findDiffWithPath = (diffs: RestDiffFile[], relativePath: string): RestDiffFile | undefined => diffs.find(d => d.new_path === relativePath || d.old_path === relativePath); export const openMrFile = async (uri: vscode.Uri): Promise<void> => { const params = fromReviewUri(uri); assert(params.path); const repository = gitExtensionWrapper.getRepository(params.repositoryRoot); const cachedMr = repository.getMr(params.mrId); assert(cachedMr); const diff = findDiffWithPath(cachedMr.mrVersion.diffs, removeLeadingSlash(params.path)); assert(diff, 'Extension did not find the file in the MR, please refresh the side panel.'); const getFullPath = (relative: string) => path.join(params.repositoryRoot, relative); const opened = (await tryToOpen(getFullPath(diff.new_path))) || (await tryToOpen(getFullPath(diff.old_path))); if (!opened) await vscode.window.showWarningMessage( `The file ${params.path} doesn't exist in your local project`, ); };
src/extension.js +2 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ const { checkoutMrBranch } = require('./commands/checkout_mr_branch'); const { cloneWiki } = require('./commands/clone_wiki'); const { createSnippetPatch } = require('./commands/create_snippet_patch'); const { applySnippetPatch } = require('./commands/apply_snippet_patch'); const { openMrFile } = require('./commands/open_mr_file'); const wrapWithCatch = command => async (...args) => { try { Loading Loading @@ -89,6 +90,7 @@ const registerCommands = (context, outputChannel) => { issuableDataProvider.refresh(); currentBranchDataProvider.refresh(); }, [USER_COMMANDS.OPEN_MR_FILE]: openMrFile, [PROGRAMMATIC_COMMANDS.NO_IMAGE_REVIEW]: () => vscode.window.showInformationMessage("GitLab MR review doesn't support images yet."), }; Loading