summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/api.js17
-rw-r--r--app/assets/javascripts/ide/services/index.js3
-rw-r--r--app/assets/javascripts/ide/stores/actions/merge_request.js32
-rw-r--r--app/assets/javascripts/ide/stores/actions/project.js29
-rw-r--r--changelogs/unreleased/49663-branch-to-mr-connection.yml5
-rw-r--r--spec/javascripts/api_spec.js34
-rw-r--r--spec/javascripts/ide/stores/actions/merge_request_spec.js93
-rw-r--r--spec/javascripts/ide/stores/actions/project_spec.js1
8 files changed, 203 insertions, 11 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 85eb08cc97d..8754c253881 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -12,6 +12,7 @@ const Api = {
projectsPath: '/api/:version/projects.json',
projectPath: '/api/:version/projects/:id',
projectLabelsPath: '/:namespace_path/:project_path/labels',
+ projectMergeRequestsPath: '/api/:version/projects/:id/merge_requests',
projectMergeRequestPath: '/api/:version/projects/:id/merge_requests/:mrid',
projectMergeRequestChangesPath: '/api/:version/projects/:id/merge_requests/:mrid/changes',
projectMergeRequestVersionsPath: '/api/:version/projects/:id/merge_requests/:mrid/versions',
@@ -111,6 +112,22 @@ const Api = {
return axios.get(url);
},
+ /**
+ * Get all Merge Requests for a project, eventually filtering based on
+ * supplied parameters
+ * @param projectPath
+ * @param params
+ * @returns {Promise}
+ */
+ projectMergeRequests(projectPath, params = {}) {
+ const url = Api.buildUrl(Api.projectMergeRequestsPath).replace(
+ ':id',
+ encodeURIComponent(projectPath),
+ );
+
+ return axios.get(url, { params });
+ },
+
// Return Merge Request for project
projectMergeRequest(projectPath, mergeRequestId, params = {}) {
const url = Api.buildUrl(Api.projectMergeRequestPath)
diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js
index 13449592e62..ba33b6826d6 100644
--- a/app/assets/javascripts/ide/services/index.js
+++ b/app/assets/javascripts/ide/services/index.js
@@ -40,6 +40,9 @@ export default {
getProjectData(namespace, project) {
return Api.project(`${namespace}/${project}`);
},
+ getProjectMergeRequests(projectId, params = {}) {
+ return Api.projectMergeRequests(projectId, params);
+ },
getProjectMergeRequestData(projectId, mergeRequestId, params = {}) {
return Api.projectMergeRequest(projectId, mergeRequestId, params);
},
diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js
index 18c24369996..362ced248a1 100644
--- a/app/assets/javascripts/ide/stores/actions/merge_request.js
+++ b/app/assets/javascripts/ide/stores/actions/merge_request.js
@@ -4,6 +4,38 @@ import service from '../../services';
import * as types from '../mutation_types';
import { activityBarViews } from '../../constants';
+export const getMergeRequestsForBranch = ({ commit }, { projectId, branchId } = {}) =>
+ service
+ .getProjectMergeRequests(`${projectId}`, {
+ source_branch: branchId,
+ order_by: 'created_at',
+ per_page: 1,
+ })
+ .then(({ data }) => {
+ if (data.length > 0) {
+ const currentMR = data[0];
+
+ commit(types.SET_MERGE_REQUEST, {
+ projectPath: projectId,
+ mergeRequestId: currentMR.iid,
+ mergeRequest: currentMR,
+ });
+
+ commit(types.SET_CURRENT_MERGE_REQUEST, `${currentMR.iid}`);
+ }
+ })
+ .catch(e => {
+ flash(
+ __(`Error fetching merge requests for ${branchId}`),
+ 'alert',
+ document,
+ null,
+ false,
+ true,
+ );
+ throw e;
+ });
+
export const getMergeRequestData = (
{ commit, dispatch, state },
{ projectId, mergeRequestId, targetProjectId = null, force = false } = {},
diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js
index b65f631c99c..06ed5c0b572 100644
--- a/app/assets/javascripts/ide/stores/actions/project.js
+++ b/app/assets/javascripts/ide/stores/actions/project.js
@@ -136,17 +136,24 @@ export const openBranch = ({ dispatch, state }, { projectId, branchId, basePath
return dispatch('getFiles', {
projectId,
branchId,
- }).then(() => {
- if (basePath) {
- const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
- const treeEntryKey = Object.keys(state.entries).find(
- key => key === path && !state.entries[key].pending,
- );
- const treeEntry = state.entries[treeEntryKey];
+ })
+ .then(() => {
+ if (basePath) {
+ const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
+ const treeEntryKey = Object.keys(state.entries).find(
+ key => key === path && !state.entries[key].pending,
+ );
+ const treeEntry = state.entries[treeEntryKey];
- if (treeEntry) {
- dispatch('handleTreeEntryAction', treeEntry);
+ if (treeEntry) {
+ dispatch('handleTreeEntryAction', treeEntry);
+ }
}
- }
- });
+ })
+ .then(() => {
+ dispatch('getMergeRequestsForBranch', {
+ projectId,
+ branchId,
+ });
+ });
};
diff --git a/changelogs/unreleased/49663-branch-to-mr-connection.yml b/changelogs/unreleased/49663-branch-to-mr-connection.yml
new file mode 100644
index 00000000000..d92ed6fd3bf
--- /dev/null
+++ b/changelogs/unreleased/49663-branch-to-mr-connection.yml
@@ -0,0 +1,5 @@
+---
+title: Link to most recent MR from a branch
+merge_request: 25689
+author:
+type: added
diff --git a/spec/javascripts/api_spec.js b/spec/javascripts/api_spec.js
index 1e9470970ff..e537e0e8afc 100644
--- a/spec/javascripts/api_spec.js
+++ b/spec/javascripts/api_spec.js
@@ -139,6 +139,40 @@ describe('Api', () => {
});
});
+ describe('projectMergeRequests', () => {
+ const projectPath = 'abc';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests`;
+
+ it('fetches all merge requests for a project', done => {
+ const mockData = [{ source_branch: 'foo' }, { source_branch: 'bar' }];
+ mock.onGet(expectedUrl).reply(200, mockData);
+ Api.projectMergeRequests(projectPath)
+ .then(({ data }) => {
+ expect(data.length).toEqual(2);
+ expect(data[0].source_branch).toBe('foo');
+ expect(data[1].source_branch).toBe('bar');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('fetches merge requests filtered with passed params', done => {
+ const params = {
+ source_branch: 'bar',
+ };
+ const mockData = [{ source_branch: 'bar' }];
+ mock.onGet(expectedUrl, { params }).reply(200, mockData);
+
+ Api.projectMergeRequests(projectPath, params)
+ .then(({ data }) => {
+ expect(data.length).toEqual(1);
+ expect(data[0].source_branch).toBe('bar');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
describe('projectMergeRequest', () => {
it('fetches a merge request', done => {
const projectPath = 'abc';
diff --git a/spec/javascripts/ide/stores/actions/merge_request_spec.js b/spec/javascripts/ide/stores/actions/merge_request_spec.js
index 9bfc7c397b8..a5839630657 100644
--- a/spec/javascripts/ide/stores/actions/merge_request_spec.js
+++ b/spec/javascripts/ide/stores/actions/merge_request_spec.js
@@ -2,6 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import store from '~/ide/stores';
import actions, {
+ getMergeRequestsForBranch,
getMergeRequestData,
getMergeRequestChanges,
getMergeRequestVersions,
@@ -27,6 +28,98 @@ describe('IDE store merge request actions', () => {
resetStore(store);
});
+ describe('getMergeRequestsForBranch', () => {
+ describe('success', () => {
+ const mrData = { iid: 2, source_branch: 'bar' };
+ const mockData = [mrData];
+
+ describe('base case', () => {
+ beforeEach(() => {
+ spyOn(service, 'getProjectMergeRequests').and.callThrough();
+ mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests/).reply(200, mockData);
+ });
+
+ it('calls getProjectMergeRequests service method', done => {
+ store
+ .dispatch('getMergeRequestsForBranch', { projectId: 'abcproject', branchId: 'bar' })
+ .then(() => {
+ expect(service.getProjectMergeRequests).toHaveBeenCalledWith('abcproject', {
+ source_branch: 'bar',
+ order_by: 'created_at',
+ per_page: 1,
+ });
+
+ done();
+ })
+ .catch(done.fail);
+ });
+
+ it('sets the "Merge Request" Object', done => {
+ store
+ .dispatch('getMergeRequestsForBranch', { projectId: 'abcproject', branchId: 'bar' })
+ .then(() => {
+ expect(Object.keys(store.state.projects.abcproject.mergeRequests).length).toEqual(1);
+ expect(Object.keys(store.state.projects.abcproject.mergeRequests)[0]).toEqual('2');
+ expect(store.state.projects.abcproject.mergeRequests[2]).toEqual(
+ jasmine.objectContaining(mrData),
+ );
+ done();
+ })
+ .catch(done.fail);
+ });
+
+ it('sets "Current Merge Request" object to the most recent MR', done => {
+ store
+ .dispatch('getMergeRequestsForBranch', { projectId: 'abcproject', branchId: 'bar' })
+ .then(() => {
+ expect(store.state.currentMergeRequestId).toEqual('2');
+ done();
+ })
+ .catch(done.fail);
+ });
+ });
+
+ describe('no merge requests for branch available case', () => {
+ beforeEach(() => {
+ spyOn(service, 'getProjectMergeRequests').and.callThrough();
+ mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests/).reply(200, []);
+ });
+
+ it('does not fail if there are no merge requests for current branch', done => {
+ store
+ .dispatch('getMergeRequestsForBranch', { projectId: 'abcproject', branchId: 'foo' })
+ .then(() => {
+ expect(Object.keys(store.state.projects.abcproject.mergeRequests).length).toEqual(0);
+ expect(store.state.currentMergeRequestId).toEqual('');
+ done();
+ })
+ .catch(done.fail);
+ });
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onGet(/api\/(.*)\/projects\/abcproject\/merge_requests/).networkError();
+ });
+
+ it('flashes message, if error', done => {
+ const flashSpy = spyOnDependency(actions, 'flash');
+
+ getMergeRequestsForBranch({ commit() {} }, { projectId: 'abcproject', branchId: 'bar' })
+ .then(() => {
+ fail('Expected getMergeRequestsForBranch to throw an error');
+ })
+ .catch(() => {
+ expect(flashSpy).toHaveBeenCalled();
+ expect(flashSpy.calls.argsFor(0)[0]).toEqual('Error fetching merge requests for bar');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+ });
+
describe('getMergeRequestData', () => {
describe('success', () => {
beforeEach(() => {
diff --git a/spec/javascripts/ide/stores/actions/project_spec.js b/spec/javascripts/ide/stores/actions/project_spec.js
index 7d8c9edd965..7b0963713fb 100644
--- a/spec/javascripts/ide/stores/actions/project_spec.js
+++ b/spec/javascripts/ide/stores/actions/project_spec.js
@@ -249,6 +249,7 @@ describe('IDE store project actions', () => {
['setCurrentBranchId', branch.branchId],
['getBranchData', branch],
['getFiles', branch],
+ ['getMergeRequestsForBranch', branch],
]);
})
.then(done)