提交 174a9557 编写于 作者: T Tomas Vik

feat(view issues-and-mrs): checkout local branch for merge request

Credit: [@Musisimaru](https://gitlab.com/Musisimaru) (originally
    introduced in
    [!229](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/229))

This is a copy paste of the code contributed by Mussimaru in
https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/229
This code doesn't compile, but I wanted to include it as a record that
he's done most of the work.
上级 34f55649
......@@ -169,6 +169,10 @@
"command": "gl.createComment",
"title": "Add comment now",
"category": "GitLab"
},
{
"command": "gl.checkoutMrBranch",
"title": "Checkout MR branch"
}
],
"menus": {
......@@ -201,6 +205,10 @@
"command": "gl.createComment",
"when": "false"
},
{
"command": "gl.checkoutMrBranch",
"when": "false"
},
{
"command": "gl.showIssuesAssignedToMe",
"when": "gitlab:validState"
......@@ -281,6 +289,12 @@
"group": "navigation"
}
],
"view/item/context": [
{
"command": "gl.checkoutMrBranch",
"when": "view =~ /issuesAndMrs/ && viewItem == mr-item-from-branch"
}
],
"comments/comment/title": [
{
"command": "gl.startEditingComment",
......
......@@ -31,6 +31,7 @@ export const USER_COMMANDS = {
CANCEL_EDITING_COMMENT: 'gl.cancelEditingComment',
SUBMIT_COMMENT_EDIT: 'gl.submitCommentEdit',
CREATE_COMMENT: 'gl.createComment',
CHECKOUT_MR_BRANCH: 'gl.checkoutMrBranch',
};
/*
......
import * as vscode from 'vscode';
import * as sidebar from '../sidebar.js';
import { GitExtension, Repository } from '../api/git';
import { MrItemModel } from '../data_providers/items/mr_item_model';
import { anotherWorkspace, mr, workspace } from '../test_utils/entities';
import { createFakeRepository, FakeGitExtension } from '../test_utils/fake_git_extension';
import { checkoutMrBranch } from './checkout_mr_branch';
import { gitExtensionWrapper } from '../git/git_extension_wrapper';
jest.mock('../sidebar.js');
vscode.window.showInformationMessage = jest.fn();
vscode.window.showErrorMessage = jest.fn();
describe('MR branch commands', () => {
describe('Checkout branch by Merge request', () => {
let commandData: MrItemModel;
let fakeExtension: FakeGitExtension;
let firstWorkspace: GitLabWorkspace;
let secondWorkspace: GitLabWorkspace;
let firstRepository: Repository;
let secondRepository: Repository;
beforeEach(() => {
firstWorkspace = { ...workspace };
secondWorkspace = { ...anotherWorkspace };
});
afterEach(() => {
(vscode.window.showInformationMessage as jest.Mock).mockReset();
(vscode.window.showWarningMessage as jest.Mock).mockReset();
});
describe('If merge request from local branch', () => {
describe('Basic functionality', () => {
beforeEach(() => {
firstRepository = createFakeRepository(firstWorkspace.uri);
secondRepository = createFakeRepository(secondWorkspace.uri);
fakeExtension = new FakeGitExtension(firstRepository, secondRepository);
jest
.spyOn(gitExtensionWrapper, 'Extension', 'get')
.mockReturnValue((fakeExtension as unknown) as GitExtension);
commandData = new MrItemModel(mr, firstWorkspace);
checkoutByMRFromLocalBranch(commandData);
});
it('(local-branch) Branch fetch message', () => {
expect((vscode.window.showInformationMessage as jest.Mock).mock.calls[0]).toEqual([
'Fetching branches...',
]);
});
it('(local-branch) Was checkout', async () => {
await expect(firstRepository.checkout).toBeCalled();
});
it('(local-branch) Was fetching before checkout', async () => {
await expect(firstRepository.checkout).toBeCalled();
expect(firstRepository.fetch).toBeCalled();
});
it('(local-branch) There were no error messages', () => {
expect(vscode.window.showErrorMessage).not.toBeCalled();
});
it('(local-branch) Sidebar was refreshed', () => {
expect(sidebar.refresh).toBeCalled();
});
it('(local-branch) Message about success', () => {
const callsCount = (vscode.window.showInformationMessage as jest.Mock).mock.calls.length;
expect(
(vscode.window.showInformationMessage as jest.Mock).mock.calls[callsCount - 1],
).toEqual([`Branch successfully changed to ${mr.source_branch}`]);
});
});
describe('Multi-root Workspaces', () => {
beforeEach(() => {
commandData = new MrItemModel(mr, secondWorkspace);
checkoutByMRFromLocalBranch(commandData);
});
it('(multi-root) The branch was checkout from right repository', async () => {
await expect(secondRepository.checkout).toBeCalled();
});
it('(multi-root) The branch from second repository was not checkout', async () => {
await expect(secondRepository.checkout).toBeCalled();
expect(firstRepository.fetch).not.toBeCalled();
expect(firstRepository.checkout).not.toBeCalled();
});
});
});
});
});
import * as vscode from 'vscode';
import * as assert from 'assert';
import * as sidebar from '../sidebar.js';
import { MrItemModel } from '../data_providers/items/mr_item_model';
import { gitExtensionWrapper } from '../git/git_extension_wrapper';
import { UserFriendlyError } from '../errors/user_friendly_error';
import { handleError } from '../log';
/**
* Command will checkout source branch by merge request in current git. Merge request must be from local branch.
* @param data item of view from the left sidebar
*/
export const checkoutMrBranch = async (data: MrItemModel): Promise<void> => {
// todo: Change data.workspace to data.repository (issue #345)
assert(data.mr.target_project_id === data.mr.source_project_id);
const { showInformationMessage } = vscode.window;
const sourceBranchName = data.mr.source_branch as string;
let branchNameForCheckout: string;
try {
const repos = gitExtensionWrapper.getRepositoriesByWorkspace(data.workspace);
if (repos.length > 1) {
throw new Error(
`You have more then one repos in one workspace. Extension can't work with this case yet. But we will fix it on soon.`,
);
}
const repo = repos[0];
showInformationMessage('Fetching branches...');
// merge from local branch
branchNameForCheckout = sourceBranchName;
await repo.fetch();
await repo.checkout(sourceBranchName);
assert(
repo.state.HEAD,
"We can't read repository HEAD. We suspect that your `git head` command fails and we can't continue till it succeeds",
);
const currentBranchName = repo.state.HEAD.name;
if (currentBranchName !== branchNameForCheckout) {
throw new Error(
`The branch name after the checkout (${currentBranchName}) is not the branch that the extension tried to check out (${branchNameForCheckout}). This is an unexpected error, please inspect your repository before making any further changes.`,
);
}
sidebar.refresh();
showInformationMessage(`Branch successfully changed to ${sourceBranchName}`);
} catch (e) {
handleError(
new UserFriendlyError(
e.stderr || `${(e as Error).message}` || `Couldn't checkout branch ${sourceBranchName}`,
e,
),
);
}
};
......@@ -29,6 +29,7 @@ const {
} = require('./commands/mr_discussion_commands');
const { fileDecorationProvider } = require('./review/file_decoration_provider');
const { checkVersion } = require('./utils/check_version');
const { checkoutMrBranch } = require('./commands/checkout_mr_branch');
vscode.gitLabWorkflow = {
sidebarDataProviders: [],
......@@ -87,6 +88,7 @@ const registerCommands = (context, outputChannel) => {
[USER_COMMANDS.CANCEL_EDITING_COMMENT]: cancelEdit,
[USER_COMMANDS.SUBMIT_COMMENT_EDIT]: submitEdit,
[USER_COMMANDS.CREATE_COMMENT]: createComment,
[USER_COMMANDS.CHECKOUT_MR_BRANCH]: checkoutMrBranch,
[PROGRAMMATIC_COMMANDS.NO_IMAGE_REVIEW]: () =>
vscode.window.showInformationMessage("GitLab MR review doesn't support images yet."),
};
......
......@@ -32,6 +32,8 @@ export const mr: RestMr = {
sha: '69ad609e8891b8aa3db85a35cd2c5747705bd76a',
source_project_id: 9999,
target_project_id: 9999,
source_branch: 'feature-a',
target_branch: 'main',
};
export const diffFile: RestDiffFile = {
......
......@@ -25,6 +25,8 @@ interface RestMr extends RestIssuable {
sha: string;
source_project_id: number;
target_project_id: number;
target_branch: string;
source_branch: string;
}
interface RestMrVersion {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册