Commit f5aed7cf authored by Stan Hu's avatar Stan Hu

Merge branch 'ce-to-ee-2018-09-04' into 'master'

CE upstream - 2018-09-04 09:22 UTC

See merge request gitlab-org/gitlab-ee!7225
parents c0f59e91 2714b09b
......@@ -4,6 +4,7 @@ import { n__, s__, sprintf } from '~/locale';
import { mergeUrlParams, webIDEUrl } from '~/lib/utils/url_utility';
import Icon from '~/vue_shared/components/icon.vue';
import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
import tooltip from '~/vue_shared/directives/tooltip';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
export default {
......@@ -13,6 +14,9 @@ export default {
clipboardButton,
TooltipOnTruncate,
},
directives: {
tooltip,
},
props: {
mr: {
type: Object,
......@@ -40,10 +44,19 @@ export default {
});
},
webIdePath() {
return mergeUrlParams({
target_project: this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath ?
this.mr.targetProjectFullPath : '',
}, webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`));
if (this.mr.canPushToSourceBranch) {
return mergeUrlParams({
target_project: this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath ?
this.mr.targetProjectFullPath : '',
}, webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`));
}
return null;
},
ideButtonTitle() {
return !this.mr.canPushToSourceBranch
? s__('mrWidget|You are not allowed to edit this project directly. Please fork to make changes.')
: '';
},
},
};
......@@ -93,13 +106,22 @@ export default {
v-if="mr.isOpen"
class="branch-actions"
>
<a
v-if="!mr.sourceBranchRemoved"
:href="webIdePath"
class="btn btn-default inline js-web-ide d-none d-md-inline-block"
<span
v-tooltip
:title="ideButtonTitle"
data-placement="bottom"
tabindex="0"
>
{{ s__("mrWidget|Open in Web IDE") }}
</a>
<a
v-if="!mr.sourceBranchRemoved"
:href="webIdePath"
:class="{ disabled: !mr.canPushToSourceBranch }"
class="btn btn-default inline js-web-ide d-none d-md-inline-block"
role="button"
>
{{ s__("mrWidget|Open in Web IDE") }}
</a>
</span>
<button
:disabled="mr.sourceBranchRemoved"
data-target="#modal_merge_info"
......
......@@ -9,6 +9,28 @@ class BuildDetailsEntity < JobEntity
expose :metadata, using: BuildMetadataEntity
expose :artifact, if: -> (*) { can?(current_user, :read_build, build) } do
expose :download_path, if: -> (*) { build.artifacts? } do |build|
download_project_job_artifacts_path(project, build)
end
expose :browse_path, if: -> (*) { build.browsable_artifacts? } do |build|
browse_project_job_artifacts_path(project, build)
end
expose :keep_path, if: -> (*) { build.has_expiring_artifacts? && can?(current_user, :update_build, build) } do |build|
keep_project_job_artifacts_path(project, build)
end
expose :expire_at, if: -> (*) { build.artifacts_expire_at.present? } do |build|
build.artifacts_expire_at
end
expose :expired, if: -> (*) { build.artifacts_expire_at.present? } do |build|
build.artifacts_expired?
end
end
expose :erased_by, if: -> (*) { build.erased? }, using: UserEntity
expose :erase_path, if: -> (*) { build.erasable? && can?(current_user, :erase_build, build) } do |build|
erase_project_job_path(project, build)
......
---
title: Send artifact information in job API
merge_request: 50460
author:
type: other
---
title: Disable Web IDE button if user is not allowed to push the source branch.
merge_request: 21288
author:
type: added
......@@ -8784,6 +8784,9 @@ msgstr ""
msgid "mrWidget|This project is archived, write access has been disabled"
msgstr ""
msgid "mrWidget|You are not allowed to edit this project directly. Please fork to make changes."
msgstr ""
msgid "mrWidget|You can merge this merge request manually using the"
msgstr ""
......
......@@ -4,7 +4,7 @@ module QA
module Scenario
module Test
module Integration
class ObjectStorage < Test::Instance
class ObjectStorage < Test::Instance::All
tags :object_storage
end
end
......
......@@ -135,7 +135,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
end
end
context 'when requesting JSON' do
context 'when requesting JSON with failed job' do
let(:merge_request) { create(:merge_request, source_project: project) }
before do
......@@ -149,10 +149,60 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
it 'exposes needed information' do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('job/job_details')
expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z})
expect(json_response['merge_request']['path']).to match(%r{merge_requests/\d+\z})
expect(json_response['new_issue_path']).to include('/issues/new')
end
end
context 'when request JSON for successful job' do
let(:merge_request) { create(:merge_request, source_project: project) }
let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
before do
project.add_developer(user)
sign_in(user)
allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)
get_show(id: job.id, format: :json)
end
it 'exposes needed information' do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('job/job_details')
expect(json_response['artifact']['download_path']).to match(%r{artifacts/download})
expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse})
expect(json_response['artifact']).not_to have_key(:expired)
expect(json_response['artifact']).not_to have_key(:expired_at)
expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z})
expect(json_response.dig('merge_request', 'path')).to match(%r{merge_requests/\d+\z})
expect(json_response['new_issue_path'])
.to include('/issues/new')
end
context 'when request JSON for successful job with expired artifacts' do
let(:merge_request) { create(:merge_request, source_project: project) }
let(:job) { create(:ci_build, :success, :artifacts, :expired, pipeline: pipeline) }
before do
project.add_developer(user)
sign_in(user)
allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)
get_show(id: job.id, format: :json)
end
it 'exposes needed information' do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('job/job_details')
expect(json_response['artifact']).not_to have_key(:download_path)
expect(json_response['artifact']).not_to have_key(:browse_path)
expect(json_response['artifact']['expired']).to eq(true)
expect(json_response['artifact']['expire_at']).not_to be_empty
expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z})
expect(json_response.dig('merge_request', 'path')).to match(%r{merge_requests/\d+\z})
end
end
end
......
......@@ -18,7 +18,29 @@
"tooltip": { "type": "string" },
"has_details": { "type": "boolean" },
"details_path": { "type": "string" },
"favicon": { "type": "string" }
"favicon": { "type": "string" },
"action": {
"type": "object",
"required": [
"icon",
"title",
"path",
"method"
],
"properties": {
"icon": {
"type": "string",
"enum": [
"retry",
"play",
"cancel"
]
},
"title": { "type": "string" },
"path": { "type": "string" },
"method": { "$ref": "http_method.json" }
}
}
},
"additionalProperties": false
}
{
"type": "string",
"description": "HTTP methods that the API can specify to send.",
"enum": [ "post", "get", "put", "patch" ]
}
{
"type": "object",
"properties": {
"download_path": { "type": "string"},
"browse_path": { "type": "string"},
"keep_path": { "type": "string"},
"expired": { "type": "boolean" },
"expire_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}
{
"description": "Basic job information",
"type": "object",
"required": [
"id",
......@@ -13,12 +14,18 @@
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"started": { "type": "boolean" } ,
"started": {
"oneOf": [
{ "type": "string", "format": "date-time" },
{ "type": "boolean" }
]
},
"build_path": { "type": "string" },
"retry_path": { "type": "string" },
"playable": { "type": "boolean" },
"created_at": { "type": "string" },
"updated_at": { "type": "string" },
"status": { "$ref": "ci_detailed_status.json" }
"status": { "$ref": "../ci_detailed_status.json" }
},
"additionalProperties": false
"additionalProperties": true
}
{
"allOf": [{ "$ref": "job.json" }],
"description": "An extension of job.json with more detailed information",
"properties": {
"artifact": { "$ref": "artifact.json" }
}
}
......@@ -13,7 +13,7 @@
"groups": { "optional": true },
"latest_statuses": {
"type": "array",
"items": { "$ref": "job.json" },
"items": { "$ref": "job/job.json" },
"optional": true
},
"status": { "$ref": "ci_detailed_status.json" },
......
......@@ -114,28 +114,31 @@ describe('MRWidgetHeader', () => {
});
describe('with an open merge request', () => {
const mrDefaultOptions = {
iid: 1,
divergedCommitsCount: 12,
sourceBranch: 'mr-widget-refactor',
sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>',
sourceBranchRemoved: false,
targetBranchPath: 'foo/bar/commits-path',
targetBranchTreePath: 'foo/bar/tree/path',
targetBranch: 'master',
isOpen: true,
canPushToSourceBranch: true,
emailPatchesPath: '/mr/email-patches',
plainDiffPath: '/mr/plainDiffPath',
statusPath: 'abc',
sourceProjectFullPath: 'root/gitlab-ce',
targetProjectFullPath: 'gitlab-org/gitlab-ce',
};
afterEach(() => {
vm.$destroy();
});
beforeEach(() => {
vm = mountComponent(Component, {
mr: {
iid: 1,
divergedCommitsCount: 12,
sourceBranch: 'mr-widget-refactor',
sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>',
sourceBranchRemoved: false,
targetBranchPath: 'foo/bar/commits-path',
targetBranchTreePath: 'foo/bar/tree/path',
targetBranch: 'master',
isOpen: true,
emailPatchesPath: '/mr/email-patches',
plainDiffPath: '/mr/plainDiffPath',
statusPath: 'abc',
sourceProjectFullPath: 'root/gitlab-ce',
targetProjectFullPath: 'gitlab-org/gitlab-ce',
},
mr: Object.assign({}, mrDefaultOptions),
});
});
......@@ -151,11 +154,21 @@ describe('MRWidgetHeader', () => {
const button = vm.$el.querySelector('.js-web-ide');
expect(button.textContent.trim()).toEqual('Open in Web IDE');
expect(button.classList.contains('disabled')).toBe(false);
expect(button.getAttribute('href')).toEqual(
'/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=gitlab-org%2Fgitlab-ce',
);
});
it('renders web ide button in disabled state with no href', () => {
const mr = Object.assign({}, mrDefaultOptions, { canPushToSourceBranch: false });
vm = mountComponent(Component, { mr });
const link = vm.$el.querySelector('.js-web-ide');
expect(link.classList.contains('disabled')).toBe(true);
expect(link.getAttribute('href')).toBeNull();
});
it('renders web ide button with blank query string if target & source project branch', done => {
vm.mr.targetProjectFullPath = 'root/gitlab-ce';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment