Commit 2995b8b1 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-01-29

# Conflicts:
#	qa/qa/page/project/show.rb

[ci skip]
parents 33ead173 55f28ebb
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
import _ from 'underscore'; import _ from 'underscore';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { s__ } from './locale';
import { isInIssuePage, updateTooltipTitle } from './lib/utils/common_utils'; import { isInIssuePage, updateTooltipTitle } from './lib/utils/common_utils';
import Flash from './flash'; import flash from './flash';
import axios from './lib/utils/axios_utils';
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'; const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'; const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd';
...@@ -441,13 +443,15 @@ class AwardsHandler { ...@@ -441,13 +443,15 @@ class AwardsHandler {
if (this.isUserAuthored($emojiButton)) { if (this.isUserAuthored($emojiButton)) {
this.userAuthored($emojiButton); this.userAuthored($emojiButton);
} else { } else {
$.post(awardUrl, { axios.post(awardUrl, {
name: emoji, name: emoji,
}, (data) => { })
.then(({ data }) => {
if (data.ok) { if (data.ok) {
callback(); callback();
} }
}).fail(() => new Flash('Something went wrong on our end.')); })
.catch(() => flash(s__('Something went wrong on our end.')));
} }
} }
......
...@@ -84,7 +84,7 @@ export default { ...@@ -84,7 +84,7 @@ export default {
return !this.showLess || (index < this.defaultRenderCount && this.showLess); return !this.showLess || (index < this.defaultRenderCount && this.showLess);
}, },
avatarUrl(user) { avatarUrl(user) {
return user.avatar || user.avatar_url; return user.avatar || user.avatar_url || gon.default_avatar_url;
}, },
assigneeUrl(user) { assigneeUrl(user) {
return `${this.rootPath}${user.username}`; return `${this.rootPath}${user.username}`;
......
...@@ -492,7 +492,7 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -492,7 +492,7 @@ function UsersSelect(currentUser, els, options = {}) {
renderRow: function(user) { renderRow: function(user) {
var avatar, img, listClosingTags, listWithName, listWithUserName, username; var avatar, img, listClosingTags, listWithName, listWithUserName, username;
username = user.username ? "@" + user.username : ""; username = user.username ? "@" + user.username : "";
avatar = user.avatar_url ? user.avatar_url : false; avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url;
let selected = false; let selected = false;
...@@ -513,10 +513,8 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -513,10 +513,8 @@ function UsersSelect(currentUser, els, options = {}) {
if (user.beforeDivider != null) { if (user.beforeDivider != null) {
`<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${_.escape(user.name)}</a></li>`; `<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${_.escape(user.name)}</a></li>`;
} else { } else {
if (avatar) {
img = "<img src='" + avatar + "' class='avatar avatar-inline' width='32' />"; img = "<img src='" + avatar + "' class='avatar avatar-inline' width='32' />";
} }
}
return ` return `
<li data-user-id=${user.id}> <li data-user-id=${user.id}>
......
import Flash from '../../../flash';
import mrWidgetAuthorTime from '../../components/mr_widget_author_time';
import tooltip from '../../../vue_shared/directives/tooltip';
import loadingIcon from '../../../vue_shared/components/loading_icon.vue';
import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub';
export default {
name: 'MRWidgetMerged',
props: {
mr: { type: Object, required: true },
service: { type: Object, required: true },
},
data() {
return {
isMakingRequest: false,
};
},
directives: {
tooltip,
},
components: {
'mr-widget-author-and-time': mrWidgetAuthorTime,
loadingIcon,
statusIcon,
},
computed: {
shouldShowRemoveSourceBranch() {
const { sourceBranchRemoved, isRemovingSourceBranch, canRemoveSourceBranch } = this.mr;
return !sourceBranchRemoved && canRemoveSourceBranch &&
!this.isMakingRequest && !isRemovingSourceBranch;
},
shouldShowSourceBranchRemoving() {
const { sourceBranchRemoved, isRemovingSourceBranch } = this.mr;
return !sourceBranchRemoved && (isRemovingSourceBranch || this.isMakingRequest);
},
shouldShowMergedButtons() {
const { canRevertInCurrentMR, canCherryPickInCurrentMR, revertInForkPath,
cherryPickInForkPath } = this.mr;
return canRevertInCurrentMR || canCherryPickInCurrentMR ||
revertInForkPath || cherryPickInForkPath;
},
},
methods: {
removeSourceBranch() {
this.isMakingRequest = true;
this.service.removeSourceBranch()
.then(res => res.data)
.then((data) => {
if (data.message === 'Branch was removed') {
eventHub.$emit('MRWidgetUpdateRequested', () => {
this.isMakingRequest = false;
});
}
})
.catch(() => {
this.isMakingRequest = false;
new Flash('Something went wrong. Please try again.'); // eslint-disable-line
});
},
},
template: `
<div class="mr-widget-body media">
<status-icon status="success" />
<div class="media-body">
<div class="space-children">
<mr-widget-author-and-time
actionText="Merged by"
:author="mr.metrics.mergedBy"
:date-title="mr.metrics.mergedAt"
:date-readable="mr.metrics.readableMergedAt" />
<a
v-if="mr.canRevertInCurrentMR"
v-tooltip
class="btn btn-close btn-xs"
href="#modal-revert-commit"
data-toggle="modal"
data-container="body"
title="Revert this merge request in a new merge request">
Revert
</a>
<a
v-else-if="mr.revertInForkPath"
v-tooltip
class="btn btn-close btn-xs"
data-method="post"
:href="mr.revertInForkPath"
title="Revert this merge request in a new merge request">
Revert
</a>
<a
v-if="mr.canCherryPickInCurrentMR"
v-tooltip
class="btn btn-default btn-xs"
href="#modal-cherry-pick-commit"
data-toggle="modal"
data-container="body"
title="Cherry-pick this merge request in a new merge request">
Cherry-pick
</a>
<a
v-else-if="mr.cherryPickInForkPath"
v-tooltip
class="btn btn-default btn-xs"
data-method="post"
:href="mr.cherryPickInForkPath"
title="Cherry-pick this merge request in a new merge request">
Cherry-pick
</a>
</div>
<section class="mr-info-list">
<p>
The changes were merged into
<span class="label-branch">
<a :href="mr.targetBranchPath">{{mr.targetBranch}}</a>
</span>
</p>
<p v-if="mr.sourceBranchRemoved">The source branch has been removed</p>
<p v-if="shouldShowRemoveSourceBranch" class="space-children">
<span>You can remove source branch now</span>
<button
@click="removeSourceBranch"
:disabled="isMakingRequest"
type="button"
class="btn btn-xs btn-default js-remove-branch-button">
Remove Source Branch
</button>
</p>
<p v-if="shouldShowSourceBranchRemoving">
<loading-icon inline />
<span>The source branch is being removed</span>
</p>
</section>
</div>
</div>
`,
};
<script>
import Flash from '~/flash';
import tooltip from '~/vue_shared/directives/tooltip';
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import { s__, __ } from '~/locale';
import mrWidgetAuthorTime from '../../components/mr_widget_author_time';
import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub';
export default {
name: 'MRWidgetMerged',
directives: {
tooltip,
},
components: {
mrWidgetAuthorTime,
loadingIcon,
statusIcon,
},
props: {
mr: {
type: Object,
required: true,
default: () => ({}),
},
service: {
type: Object,
required: true,
default: () => ({}),
},
},
data() {
return {
isMakingRequest: false,
};
},
computed: {
shouldShowRemoveSourceBranch() {
const {
sourceBranchRemoved,
isRemovingSourceBranch,
canRemoveSourceBranch,
} = this.mr;
return !sourceBranchRemoved &&
canRemoveSourceBranch &&
!this.isMakingRequest &&
!isRemovingSourceBranch;
},
shouldShowSourceBranchRemoving() {
const {
sourceBranchRemoved,
isRemovingSourceBranch,
} = this.mr;
return !sourceBranchRemoved &&
(isRemovingSourceBranch || this.isMakingRequest);
},
shouldShowMergedButtons() {
const {
canRevertInCurrentMR,
canCherryPickInCurrentMR,
revertInForkPath,
cherryPickInForkPath,
} = this.mr;
return canRevertInCurrentMR ||
canCherryPickInCurrentMR ||
revertInForkPath ||
cherryPickInForkPath;
},
revertTitle() {
return s__('mrWidget|Revert this merge request in a new merge request');
},
cherryPickTitle() {
return s__('mrWidget|Cherry-pick this merge request in a new merge request');
},
revertLabel() {
return s__('mrWidget|Revert');
},
cherryPickLabel() {
return s__('mrWidget|Cherry-pick');
},
},
methods: {
removeSourceBranch() {
this.isMakingRequest = true;
this.service.removeSourceBranch()
.then(res => res.data)
.then((data) => {
if (data.message === 'Branch was removed') {
eventHub.$emit('MRWidgetUpdateRequested', () => {
this.isMakingRequest = false;
});
}
})
.catch(() => {
this.isMakingRequest = false;
Flash(__('Something went wrong. Please try again.'));
});
},
},
};
</script>
<template>
<div class="mr-widget-body media">
<status-icon status="success" />
<div class="media-body">
<div class="space-children">
<mr-widget-author-time
:action-text="s__('mrWidget|Merged by')"
:author="mr.metrics.mergedBy"
:date-title="mr.metrics.mergedAt"
:date-readable="mr.metrics.readableMergedAt"
/>
<a
v-if="mr.canRevertInCurrentMR"
v-tooltip
class="btn btn-close btn-xs"
href="#modal-revert-commit"
data-toggle="modal"
data-container="body"
:title="revertTitle"
>
{{ revertLabel }}
</a>
<a
v-else-if="mr.revertInForkPath"
v-tooltip
class="btn btn-close btn-xs"
data-method="post"
:href="mr.revertInForkPath"
:title="revertTitle"
>
{{ revertLabel }}
</a>
<a
v-if="mr.canCherryPickInCurrentMR"
v-tooltip
class="btn btn-default btn-xs"
href="#modal-cherry-pick-commit"
data-toggle="modal"
data-container="body"
:title="cherryPickTitle"
>
{{ cherryPickLabel }}
</a>
<a
v-else-if="mr.cherryPickInForkPath"
v-tooltip
class="btn btn-default btn-xs"
data-method="post"
:href="mr.cherryPickInForkPath"
:title="cherryPickTitle"
>
{{ cherryPickLabel }}
</a>
</div>
<section class="mr-info-list">
<p>
{{ s__("mrWidget|The changes were merged into") }}
<span class="label-branch">
<a :href="mr.targetBranchPath">{{ mr.targetBranch }}</a>
</span>
</p>
<p v-if="mr.sourceBranchRemoved">
{{ s__("mrWidget|The source branch has been removed") }}
</p>
<p
v-if="shouldShowRemoveSourceBranch"
class="space-children"
>
<span>{{ s__("mrWidget|You can remove source branch now") }}</span>
<button
@click="removeSourceBranch"
:disabled="isMakingRequest"
type="button"
class="btn btn-xs btn-default js-remove-branch-button"
>
{{ s__("mrWidget|Remove Source Branch") }}
</button>
</p>
<p v-if="shouldShowSourceBranchRemoving">
<loading-icon :inline="true" />
<span>
{{ s__("mrWidget|The source branch is being removed") }}
</span>
</p>
</section>
</div>
</div>
</template>
...@@ -16,7 +16,7 @@ export { default as WidgetMergeHelp } from './components/mr_widget_merge_help'; ...@@ -16,7 +16,7 @@ export { default as WidgetMergeHelp } from './components/mr_widget_merge_help';
export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue'; export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue';
export { default as WidgetDeployment } from './components/mr_widget_deployment'; export { default as WidgetDeployment } from './components/mr_widget_deployment';
export { default as WidgetRelatedLinks } from './components/mr_widget_related_links'; export { default as WidgetRelatedLinks } from './components/mr_widget_related_links';
export { default as MergedState } from './components/states/mr_widget_merged'; export { default as MergedState } from './components/states/mr_widget_merged.vue';
export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge.vue'; export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge.vue';
export { default as ClosedState } from './components/states/mr_widget_closed.vue'; export { default as ClosedState } from './components/states/mr_widget_closed.vue';
export { default as MergingState } from './components/states/mr_widget_merging.vue'; export { default as MergingState } from './components/states/mr_widget_merging.vue';
......
...@@ -89,7 +89,7 @@ module ApplicationHelper ...@@ -89,7 +89,7 @@ module ApplicationHelper
end end
def default_avatar def default_avatar
'no_avatar.png' asset_path('no_avatar.png')
end end
def last_commit(project) def last_commit(project)
......
...@@ -9,7 +9,8 @@ module MergeRequests ...@@ -9,7 +9,8 @@ module MergeRequests
Gitlab::GitalyClient.allow_n_plus_1_calls(&method(:find_new_commits)) Gitlab::GitalyClient.allow_n_plus_1_calls(&method(:find_new_commits))
# Be sure to close outstanding MRs before reloading them to avoid generating an # Be sure to close outstanding MRs before reloading them to avoid generating an
# empty diff during a manual merge # empty diff during a manual merge
close_merge_requests close_upon_missing_source_branch_ref
post_merge_manually_merged
reload_merge_requests reload_merge_requests
reset_merge_when_pipeline_succeeds reset_merge_when_pipeline_succeeds
mark_pending_todos_done mark_pending_todos_done
...@@ -30,11 +31,22 @@ module MergeRequests ...@@ -30,11 +31,22 @@ module MergeRequests
private private
def close_upon_missing_source_branch_ref
# MergeRequest#reload_diff ignores not opened MRs. This means it won't
# create an `empty` diff for `closed` MRs without a source branch, keeping
# the latest diff state as the last _valid_ one.
merge_requests_for_source_branch.reject(&:source_branch_exists?).each do |mr|
MergeRequests::CloseService
.new(mr.target_project, @current_user)
.execute(mr)
end
end
# Collect open merge requests that target same branch we push into # Collect open merge requests that target same branch we push into
# and close if push to master include last commit from merge request # and close if push to master include last commit from merge request
# We need this to close(as merged) merge requests that were merged into # We need this to close(as merged) merge requests that were merged into
# target branch manually # target branch manually
def close_merge_requests def post_merge_manually_merged
commit_ids = @commits.map(&:id) commit_ids = @commits.map(&:id)
merge_requests = @project.merge_requests.preload(:latest_merge_request_diff).opened.where(target_branch: @branch_name).to_a merge_requests = @project.merge_requests.preload(:latest_merge_request_diff).opened.where(target_branch: @branch_name).to_a
merge_requests = merge_requests.select(&:diff_head_commit) merge_requests = merge_requests.select(&:diff_head_commit)
......
...@@ -14,5 +14,5 @@ ...@@ -14,5 +14,5 @@
#{time_ago_with_tooltip(event.created_at)} #{time_ago_with_tooltip(event.created_at)}
.pull-right .pull-right
= link_to new_mr_path_from_push_event(event), title: _("New merge request"), class: "btn btn-info btn-sm" do = link_to new_mr_path_from_push_event(event), title: _("New merge request"), class: "btn btn-info btn-sm qa-create-merge-request" do
#{ _('Create merge request') } #{ _('Create merge request') }
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
= render layout: 'projects/md_preview', locals: { url: preview_url, referenced_users: true } do = render layout: 'projects/md_preview', locals: { url: preview_url, referenced_users: true } do
= render 'projects/zen', f: form, attr: :description, = render 'projects/zen', f: form, attr: :description,
classes: 'note-textarea', classes: 'note-textarea qa-issuable-form-description',
placeholder: "Write a comment or drag your files here...", placeholder: "Write a comment or drag your files here...",
supports_quick_actions: supports_quick_actions supports_quick_actions: supports_quick_actions
= render 'shared/notes/hints', supports_quick_actions: supports_quick_actions = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
%span.append-right-10 %span.append-right-10
- if issuable.new_record? - if issuable.new_record?
= form.submit "Submit #{issuable.class.model_name.human.downcase}", class: 'btn btn-create' = form.submit "Submit #{issuable.class.model_name.human.downcase}", class: 'btn btn-create qa-issuable-create-button'
- else - else
= form.submit 'Save changes', class: 'btn btn-save' = form.submit 'Save changes', class: 'btn btn-save'
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
%div{ class: div_class } %div{ class: div_class }
= form.text_field :title, required: true, maxlength: 255, autofocus: true, = form.text_field :title, required: true, maxlength: 255, autofocus: true,
autocomplete: 'off', class: 'form-control pad' autocomplete: 'off', class: 'form-control pad qa-issuable-form-title'
- if issuable.respond_to?(:work_in_progress?) - if issuable.respond_to?(:work_in_progress?)
%p.help-block %p.help-block
......
---
title: Fix default avatar icon missing when Gravatar is disabled
merge_request: 16681
author: Felix Geyer
type: fixed
---
title: Close and do not reload MR diffs when source branch is deleted
merge_request:
author:
type: fixed
...@@ -496,7 +496,7 @@ more of the following options: ...@@ -496,7 +496,7 @@ more of the following options:
- `BACKUP=timestamp_of_backup` - Required if more than one backup exists. - `BACKUP=timestamp_of_backup` - Required if more than one backup exists.
Read what the [backup timestamp is about](#backup-timestamp). Read what the [backup timestamp is about](#backup-timestamp).
- `force=yes` - Do not ask if the authorized_keys file should get regenerated. - `force=yes` - Does not ask if the authorized_keys file should get regenerated and assumes 'yes' for warning that database tables will be removed.
### Restore for installation from source ### Restore for installation from source
......
...@@ -468,9 +468,13 @@ module Gitlab ...@@ -468,9 +468,13 @@ module Gitlab
} }
options = default_options.merge(options) options = default_options.merge(options)
options[:limit] ||= 0
options[:offset] ||= 0 options[:offset] ||= 0
limit = options[:limit]
if limit == 0 || !limit.is_a?(Integer)
raise ArgumentError.new("invalid Repository#log limit: #{limit.inspect}")
end
gitaly_migrate(:find_commits) do |is_enabled| gitaly_migrate(:find_commits) do |is_enabled|
if is_enabled if is_enabled
gitaly_commit_client.find_commits(options) gitaly_commit_client.find_commits(options)
......
...@@ -28,6 +28,7 @@ module QA ...@@ -28,6 +28,7 @@ module QA
autoload :Sandbox, 'qa/factory/resource/sandbox' autoload :Sandbox, 'qa/factory/resource/sandbox'
autoload :Group, 'qa/factory/resource/group' autoload :Group, 'qa/factory/resource/group'
autoload :Project, 'qa/factory/resource/project' autoload :Project, 'qa/factory/resource/project'
autoload :MergeRequest, 'qa/factory/resource/merge_request'
autoload :DeployKey, 'qa/factory/resource/deploy_key' autoload :DeployKey, 'qa/factory/resource/deploy_key'
autoload :SecretVariable, 'qa/factory/resource/secret_variable' autoload :SecretVariable, 'qa/factory/resource/secret_variable'
autoload :Runner, 'qa/factory/resource/runner' autoload :Runner, 'qa/factory/resource/runner'
...@@ -135,6 +136,10 @@ module QA ...@@ -135,6 +136,10 @@ module QA
autoload :PersonalAccessTokens, 'qa/page/profile/personal_access_tokens' autoload :PersonalAccessTokens, 'qa/page/profile/personal_access_tokens'
end end
module MergeRequest
autoload :New, 'qa/page/merge_request/new'
end
module Admin module Admin
autoload :Settings, 'qa/page/admin/settings' autoload :Settings, 'qa/page/admin/settings'
end end
......
...@@ -16,20 +16,21 @@ module QA ...@@ -16,20 +16,21 @@ module QA
def build! def build!
return if overridden? return if overridden?
Builder.new(@signature).fabricate!.tap do |product| Builder.new(@signature, @factory).fabricate!.tap do |product|
@factory.public_send("#{@name}=", product) @factory.public_send("#{@name}=", product)
end end
end end
class Builder class Builder
def initialize(signature) def initialize(signature, caller_factory)
@factory = signature.factory @factory = signature.factory
@block = signature.block @block = signature.block
@caller_factory = caller_factory
end end
def fabricate! def fabricate!
@factory.fabricate! do |factory| @factory.fabricate! do |factory|
@block&.call(factory) @block&.call(factory, @caller_factory)
end end
end end
end end
......
require 'securerandom'
module QA
module Factory
module Resource
class MergeRequest < Factory::Base
attr_accessor :title,
:description,
:source_branch,
:target_branch
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-with-merge-request'
end
dependency Factory::Repository::Push, as: :target do |push, factory|
push.project = factory.project
push.branch_name = "master:#{factory.target_branch}"
end
dependency Factory::Repository::Push, as: :source do |push, factory|
push.project = factory.project
push.branch_name = "#{factory.target_branch}:#{factory.source_branch}"
push.file_name = "added_file.txt"
push.file_content = "File Added"
end
def initialize
@title = 'QA test - merge request'
@description = 'This is a test merge request'
@source_branch = "qa-test-feature-#{SecureRandom.hex(8)}"
@target_branch = "master"
end
def fabricate!
project.visit!
Page::Project::Show.act { new_merge_request }
Page::MergeRequest::New.perform do |page|
page.fill_title(@title)
page.fill_description(@description)
page.create_merge_request
end
end
end
end
end
end
...@@ -42,12 +42,16 @@ module QA ...@@ -42,12 +42,16 @@ module QA
page.within(selector) { yield } if block_given? page.within(selector) { yield } if block_given?
end end
def find_element(name)
find(element_selector_css(name))
end
def click_element(name) def click_element(name)
find_element(name).click find_element(name).click
end end
def find_element(name) def fill_element(name, content)
find(element_selector_css(name)) find_element(name).set(content)
end end
def within_element(name) def within_element(name)
......
module QA
module Page
module MergeRequest
class New < Page::Base
view 'app/views/shared/issuable/_form.html.haml' do
element :issuable_create_button
end
view 'app/views/shared/issuable/form/_title.html.haml' do
element :issuable_form_title
end
view 'app/views/shared/form_elements/_description.html.haml' do
element :issuable_form_description
end
def create_merge_request
click_element :issuable_create_button
end
def fill_title(title)
fill_element :issuable_form_title, title
end
def fill_description(description)
fill_element :issuable_form_description, description
end
end
end
end
end
...@@ -7,6 +7,13 @@ module QA ...@@ -7,6 +7,13 @@ module QA
element :clone_dropdown element :clone_dropdown
element :clone_options_dropdown, '.clone-options-dropdown' element :clone_options_dropdown, '.clone-options-dropdown'
element :project_repository_location, 'text_field_tag :project_clone' element :project_repository_location, 'text_field_tag :project_clone'
<<<<<<< HEAD
=======
end
view 'app/views/projects/_last_push.html.haml' do
element :create_merge_request
>>>>>>> upstream/master
end end
view 'app/views/projects/_home_panel.html.haml' do view 'app/views/projects/_home_panel.html.haml' do
...@@ -16,11 +23,19 @@ module QA ...@@ -16,11 +23,19 @@ module QA
def choose_repository_clone_http def choose_repository_clone_http
wait(reload: false) do wait(reload: false) do
click_element :clone_dropdown click_element :clone_dropdown
<<<<<<< HEAD
page.within('.clone-options-dropdown') do page.within('.clone-options-dropdown') do
click_link('HTTP') click_link('HTTP')
end end
=======
page.within('.clone-options-dropdown') do
click_link('HTTP')
end
>>>>>>> upstream/master
# Ensure git clone textbox was updated to http URI # Ensure git clone textbox was updated to http URI
page.has_css?('.git-clone-holder input#project_clone[value*="http"]') page.has_css?('.git-clone-holder input#project_clone[value*="http"]')
end end
...@@ -34,6 +49,10 @@ module QA ...@@ -34,6 +49,10 @@ module QA
find('.qa-project-name').text find('.qa-project-name').text
end end
def new_merge_request
click_element :create_merge_request
end
def wait_for_push def wait_for_push
sleep 5 sleep 5
refresh refresh
......
module QA
feature 'creates a merge request', :core do
scenario 'user creates a new merge request' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
Factory::Resource::MergeRequest.fabricate! do |merge_request|
merge_request.title = 'This is a merge request'
merge_request.description = 'Great feature'
end
expect(page).to have_content('This is a merge request')
expect(page).to have_content('Great feature')
expect(page).to have_content('Opened less than a minute ago')
end
end
end
...@@ -54,6 +54,19 @@ describe QA::Factory::Dependency do ...@@ -54,6 +54,19 @@ describe QA::Factory::Dependency do
expect(factory).to have_received(:mydep=).with(dependency) expect(factory).to have_received(:mydep=).with(dependency)
end end
context 'when receives a caller factory as block argument' do
let(:dependency) { QA::Factory::Base }
it 'calls given block with dependency factory and caller factory' do
allow_any_instance_of(QA::Factory::Base).to receive(:fabricate!).and_return(factory)
allow(QA::Factory::Product).to receive(:populate!).and_return(spy('any'))
subject.build!
expect(block).to have_received(:call).with(an_instance_of(QA::Factory::Base), factory)
end
end
end end
end end
end end
...@@ -194,7 +194,7 @@ describe 'Commits' do ...@@ -194,7 +194,7 @@ describe 'Commits' do
end end
it 'includes the committed_date for each commit' do it 'includes the committed_date for each commit' do
commits = project.repository.commits(branch_name) commits = project.repository.commits(branch_name, limit: 40)
commits.each do |commit| commits.each do |commit|
expect(page).to have_content("authored #{commit.authored_date.strftime("%b %d, %Y")}") expect(page).to have_content("authored #{commit.authored_date.strftime("%b %d, %Y")}")
......
...@@ -100,7 +100,7 @@ describe ApplicationHelper do ...@@ -100,7 +100,7 @@ describe ApplicationHelper do
end end
it 'returns a generic avatar' do it 'returns a generic avatar' do
expect(helper.gravatar_icon(user_email)).to match('no_avatar.png') expect(helper.gravatar_icon(user_email)).to match_asset_path('no_avatar.png')
end end
end end
...@@ -110,7 +110,7 @@ describe ApplicationHelper do ...@@ -110,7 +110,7 @@ describe ApplicationHelper do
end end
it 'returns a generic avatar when email is blank' do it 'returns a generic avatar when email is blank' do
expect(helper.gravatar_icon('')).to match('no_avatar.png') expect(helper.gravatar_icon('')).to match_asset_path('no_avatar.png')
end end
it 'returns a valid Gravatar URL' do it 'returns a valid Gravatar URL' do
......
import Vue from 'vue'; import Vue from 'vue';
import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged'; import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged.vue';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
import mountComponent from '../../../helpers/vue_mount_component_helper';
const targetBranch = 'foo'; describe('MRWidgetMerged', () => {
let vm;
const targetBranch = 'foo';
const createComponent = () => { beforeEach(() => {
const Component = Vue.extend(mergedComponent); const Component = Vue.extend(mergedComponent);
const mr = { const mr = {
isRemovingSourceBranch: false, isRemovingSourceBranch: false,
...@@ -15,14 +18,19 @@ const createComponent = () => { ...@@ -15,14 +18,19 @@ const createComponent = () => {
canRemoveSourceBranch: true, canRemoveSourceBranch: true,
sourceBranchRemoved: true, sourceBranchRemoved: true,
metrics: { metrics: {
mergedBy: {}, mergedBy: {
mergedAt: 'mergedUpdatedAt', name: 'Administrator',
username: 'root',
webUrl: 'http://localhost:3000/root',
avatarUrl: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
},
mergedAt: 'Jan 24, 2018 1:02pm GMT+0000',
readableMergedAt: '', readableMergedAt: '',
closedBy: {}, closedBy: {},
closedAt: 'mergedUpdatedAt', closedAt: 'Jan 24, 2018 1:02pm GMT+0000',
readableClosedAt: '', readableClosedAt: '',
}, },
updatedAt: 'mrUpdatedAt', updatedAt: 'mergedUpdatedAt',
targetBranch, targetBranch,
}; };
...@@ -30,79 +38,62 @@ const createComponent = () => { ...@@ -30,79 +38,62 @@ const createComponent = () => {
removeSourceBranch() {}, removeSourceBranch() {},
}; };
return new Component({ spyOn(eventHub, '$emit');
el: document.createElement('div'),
propsData: { mr, service },
});
};
describe('MRWidgetMerged', () => {
describe('props', () => {
it('should have props', () => {
const { mr, service } = mergedComponent.props;
expect(mr.type instanceof Object).toBeTruthy();
expect(mr.required).toBeTruthy();
expect(service.type instanceof Object).toBeTruthy();
expect(service.required).toBeTruthy();
});
});
describe('components', () => { vm = mountComponent(Component, { mr, service });
it('should have components added', () => {
expect(mergedComponent.components['mr-widget-author-and-time']).toBeDefined();
});
}); });
describe('data', () => { afterEach(() => {
it('should have default data', () => { vm.$destroy();
const data = mergedComponent.data();
expect(data.isMakingRequest).toBeFalsy();
});
}); });
describe('computed', () => { describe('computed', () => {
describe('shouldShowRemoveSourceBranch', () => { describe('shouldShowRemoveSourceBranch', () => {
it('should correct value when fields changed', () => { it('returns true when sourceBranchRemoved is false', () => {
const vm = createComponent();
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
expect(vm.shouldShowRemoveSourceBranch).toBeTruthy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(true);
});
it('returns false wehn sourceBranchRemoved is true', () => {
vm.mr.sourceBranchRemoved = true; vm.mr.sourceBranchRemoved = true;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
});
it('returns false when canRemoveSourceBranch is false', () => {
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
vm.mr.canRemoveSourceBranch = false; vm.mr.canRemoveSourceBranch = false;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
});
it('returns false when is making request', () => {
vm.mr.canRemoveSourceBranch = true; vm.mr.canRemoveSourceBranch = true;
vm.isMakingRequest = true; vm.isMakingRequest = true;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
});
it('returns true when all are true', () => {
vm.mr.isRemovingSourceBranch = true; vm.mr.isRemovingSourceBranch = true;
vm.mr.canRemoveSourceBranch = true; vm.mr.canRemoveSourceBranch = true;
vm.isMakingRequest = true; vm.isMakingRequest = true;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
}); });
}); });
describe('shouldShowSourceBranchRemoving', () => { describe('shouldShowSourceBranchRemoving', () => {
it('should correct value when fields changed', () => { it('should correct value when fields changed', () => {
const vm = createComponent();
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
expect(vm.shouldShowSourceBranchRemoving).toBeFalsy(); expect(vm.shouldShowSourceBranchRemoving).toEqual(false);
vm.mr.sourceBranchRemoved = true; vm.mr.sourceBranchRemoved = true;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
vm.isMakingRequest = true; vm.isMakingRequest = true;
expect(vm.shouldShowSourceBranchRemoving).toBeTruthy(); expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
vm.isMakingRequest = false; vm.isMakingRequest = false;
vm.mr.isRemovingSourceBranch = true; vm.mr.isRemovingSourceBranch = true;
expect(vm.shouldShowSourceBranchRemoving).toBeTruthy(); expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
}); });
}); });
}); });
...@@ -110,8 +101,6 @@ describe('MRWidgetMerged', () => { ...@@ -110,8 +101,6 @@ describe('MRWidgetMerged', () => {
describe('methods', () => { describe('methods', () => {
describe('removeSourceBranch', () => { describe('removeSourceBranch', () => {
it('should set flag and call service then request main component to update the widget', (done) => { it('should set flag and call service then request main component to update the widget', (done) => {
const vm = createComponent();
spyOn(eventHub, '$emit');
spyOn(vm.service, 'removeSourceBranch').and.returnValue(new Promise((resolve) => { spyOn(vm.service, 'removeSourceBranch').and.returnValue(new Promise((resolve) => {
resolve({ resolve({
data: { data: {
...@@ -123,7 +112,7 @@ describe('MRWidgetMerged', () => { ...@@ -123,7 +112,7 @@ describe('MRWidgetMerged', () => {
vm.removeSourceBranch(); vm.removeSourceBranch();
setTimeout(() => { setTimeout(() => {
const args = eventHub.$emit.calls.argsFor(0); const args = eventHub.$emit.calls.argsFor(0);
expect(vm.isMakingRequest).toBeTruthy(); expect(vm.isMakingRequest).toEqual(true);
expect(args[0]).toEqual('MRWidgetUpdateRequested'); expect(args[0]).toEqual('MRWidgetUpdateRequested');
expect(args[1]).not.toThrow(); expect(args[1]).not.toThrow();
done(); done();
...@@ -132,33 +121,31 @@ describe('MRWidgetMerged', () => { ...@@ -132,33 +121,31 @@ describe('MRWidgetMerged', () => {
}); });
}); });
describe('template', () => { it('has merged by information', () => {
let vm; expect(vm.$el.textContent).toContain('Merged by');
let el; expect(vm.$el.textContent).toContain('Administrator');
});
beforeEach(() => { it('renders branch information', () => {
vm = createComponent(); expect(vm.$el.textContent).toContain('The changes were merged into');
el = vm.$el; expect(vm.$el.textContent).toContain(targetBranch);
}); });
it('should have correct elements', () => { it('renders information about branch being removed', () => {
expect(el.classList.contains('mr-widget-body')).toBeTruthy(); expect(vm.$el.textContent).toContain('The source branch has been removed');
expect(el.querySelector('.js-mr-widget-author')).toBeDefined(); });
expect(el.innerText).toContain('The changes were merged into');
expect(el.innerText).toContain(targetBranch); it('shows revert and cherry-pick buttons', () => {
expect(el.innerText).toContain('The source branch has been removed'); expect(vm.$el.textContent).toContain('Revert');
expect(el.innerText).toContain('Revert'); expect(vm.$el.textContent).toContain('Cherry-pick');
expect(el.innerText).toContain('Cherry-pick');
expect(el.innerText).not.toContain('You can remove source branch now');
expect(el.innerText).not.toContain('The source branch is being removed');
}); });
it('should not show source branch removed text', (done) => { it('should not show source branch removed text', (done) => {
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
Vue.nextTick(() => { Vue.nextTick(() => {
expect(el.innerText).toContain('You can remove source branch now'); expect(vm.$el.innerText).toContain('You can remove source branch now');
expect(el.innerText).not.toContain('The source branch has been removed'); expect(vm.$el.innerText).not.toContain('The source branch has been removed');
done(); done();
}); });
}); });
...@@ -168,17 +155,16 @@ describe('MRWidgetMerged', () => { ...@@ -168,17 +155,16 @@ describe('MRWidgetMerged', () => {
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
Vue.nextTick(() => { Vue.nextTick(() => {
expect(el.innerText).toContain('The source branch is being removed'); expect(vm.$el.innerText).toContain('The source branch is being removed');
expect(el.innerText).not.toContain('You can remove source branch now'); expect(vm.$el.innerText).not.toContain('You can remove source branch now');
expect(el.innerText).not.toContain('The source branch has been removed'); expect(vm.$el.innerText).not.toContain('The source branch has been removed');
done(); done();
}); });
}); });
it('should use mergedEvent updatedAt as tooltip title', () => { it('should use mergedEvent mergedAt as tooltip title', () => {
expect( expect(
el.querySelector('time').getAttribute('title'), vm.$el.querySelector('time').getAttribute('title'),
).toBe('mergedUpdatedAt'); ).toBe('Jan 24, 2018 1:02pm GMT+0000');
});
}); });
}); });
...@@ -981,6 +981,16 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -981,6 +981,16 @@ describe Gitlab::Git::Repository, seed_helper: true do
end end
end end
end end
context 'limit validation' do
where(:limit) do
[0, nil, '', 'foo']
end
with_them do
it { expect { repository.log(limit: limit) }.to raise_error(ArgumentError) }
end
end
end end
describe "#rugged_commits_between" do describe "#rugged_commits_between" do
......
...@@ -1768,7 +1768,7 @@ describe MergeRequest do ...@@ -1768,7 +1768,7 @@ describe MergeRequest do
expect { subject.reload_diff }.to change { subject.merge_request_diffs.count }.by(1) expect { subject.reload_diff }.to change { subject.merge_request_diffs.count }.by(1)
end end
it "executs diff cache service" do it "executes diff cache service" do
expect_any_instance_of(MergeRequests::MergeRequestDiffCacheService).to receive(:execute).with(subject) expect_any_instance_of(MergeRequests::MergeRequestDiffCacheService).to receive(:execute).with(subject)
subject.reload_diff subject.reload_diff
......
...@@ -222,20 +222,20 @@ describe Repository do ...@@ -222,20 +222,20 @@ describe Repository do
it 'sets follow when path is a single path' do it 'sets follow when path is a single path' do
expect(Gitlab::Git::Commit).to receive(:where).with(a_hash_including(follow: true)).and_call_original.twice expect(Gitlab::Git::Commit).to receive(:where).with(a_hash_including(follow: true)).and_call_original.twice
repository.commits('master', path: 'README.md') repository.commits('master', limit: 1, path: 'README.md')
repository.commits('master', path: ['README.md']) repository.commits('master', limit: 1, path: ['README.md'])
end end
it 'does not set follow when path is multiple paths' do it 'does not set follow when path is multiple paths' do
expect(Gitlab::Git::Commit).to receive(:where).with(a_hash_including(follow: false)).and_call_original expect(Gitlab::Git::Commit).to receive(:where).with(a_hash_including(follow: false)).and_call_original
repository.commits('master', path: ['README.md', 'CHANGELOG']) repository.commits('master', limit: 1, path: ['README.md', 'CHANGELOG'])
end end
it 'does not set follow when there are no paths' do it 'does not set follow when there are no paths' do
expect(Gitlab::Git::Commit).to receive(:where).with(a_hash_including(follow: false)).and_call_original expect(Gitlab::Git::Commit).to receive(:where).with(a_hash_including(follow: false)).and_call_original
repository.commits('master') repository.commits('master', limit: 1)
end end
end end
...@@ -455,7 +455,7 @@ describe Repository do ...@@ -455,7 +455,7 @@ describe Repository do
expect do expect do
repository.create_dir(user, 'newdir', repository.create_dir(user, 'newdir',
message: 'Create newdir', branch_name: 'master') message: 'Create newdir', branch_name: 'master')
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
newdir = repository.tree('master', 'newdir') newdir = repository.tree('master', 'newdir')
expect(newdir.path).to eq('newdir') expect(newdir.path).to eq('newdir')
...@@ -469,7 +469,7 @@ describe Repository do ...@@ -469,7 +469,7 @@ describe Repository do
repository.create_dir(user, 'newdir', repository.create_dir(user, 'newdir',
message: 'Create newdir', branch_name: 'patch', message: 'Create newdir', branch_name: 'patch',
start_branch_name: 'master', start_project: forked_project) start_branch_name: 'master', start_project: forked_project)
end.to change { repository.commits('master').count }.by(0) end.to change { repository.count_commits(ref: 'master') }.by(0)
expect(repository.branch_exists?('patch')).to be_truthy expect(repository.branch_exists?('patch')).to be_truthy
expect(forked_project.repository.branch_exists?('patch')).to be_falsy expect(forked_project.repository.branch_exists?('patch')).to be_falsy
...@@ -486,7 +486,7 @@ describe Repository do ...@@ -486,7 +486,7 @@ describe Repository do
message: 'Add newdir', message: 'Add newdir',
branch_name: 'master', branch_name: 'master',
author_email: author_email, author_name: author_name) author_email: author_email, author_name: author_name)
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
last_commit = repository.commit last_commit = repository.commit
...@@ -502,7 +502,7 @@ describe Repository do ...@@ -502,7 +502,7 @@ describe Repository do
repository.create_file(user, 'NEWCHANGELOG', 'Changelog!', repository.create_file(user, 'NEWCHANGELOG', 'Changelog!',
message: 'Create changelog', message: 'Create changelog',
branch_name: 'master') branch_name: 'master')
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
blob = repository.blob_at('master', 'NEWCHANGELOG') blob = repository.blob_at('master', 'NEWCHANGELOG')
...@@ -514,7 +514,7 @@ describe Repository do ...@@ -514,7 +514,7 @@ describe Repository do
repository.create_file(user, 'new_dir/new_file.txt', 'File!', repository.create_file(user, 'new_dir/new_file.txt', 'File!',
message: 'Create new_file with new_dir', message: 'Create new_file with new_dir',
branch_name: 'master') branch_name: 'master')
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
expect(repository.tree('master', 'new_dir').path).to eq('new_dir') expect(repository.tree('master', 'new_dir').path).to eq('new_dir')
expect(repository.blob_at('master', 'new_dir/new_file.txt').data).to eq('File!') expect(repository.blob_at('master', 'new_dir/new_file.txt').data).to eq('File!')
...@@ -538,7 +538,7 @@ describe Repository do ...@@ -538,7 +538,7 @@ describe Repository do
branch_name: 'master', branch_name: 'master',
author_email: author_email, author_email: author_email,
author_name: author_name) author_name: author_name)
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
last_commit = repository.commit last_commit = repository.commit
...@@ -554,7 +554,7 @@ describe Repository do ...@@ -554,7 +554,7 @@ describe Repository do
repository.update_file(user, 'CHANGELOG', 'Changelog!', repository.update_file(user, 'CHANGELOG', 'Changelog!',
message: 'Update changelog', message: 'Update changelog',
branch_name: 'master') branch_name: 'master')
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
blob = repository.blob_at('master', 'CHANGELOG') blob = repository.blob_at('master', 'CHANGELOG')
...@@ -567,7 +567,7 @@ describe Repository do ...@@ -567,7 +567,7 @@ describe Repository do
branch_name: 'master', branch_name: 'master',
previous_path: 'LICENSE', previous_path: 'LICENSE',
message: 'Changes filename') message: 'Changes filename')
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
files = repository.ls_files('master') files = repository.ls_files('master')
...@@ -584,7 +584,7 @@ describe Repository do ...@@ -584,7 +584,7 @@ describe Repository do
message: 'Update README', message: 'Update README',
author_email: author_email, author_email: author_email,
author_name: author_name) author_name: author_name)
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
last_commit = repository.commit last_commit = repository.commit
...@@ -599,7 +599,7 @@ describe Repository do ...@@ -599,7 +599,7 @@ describe Repository do
expect do expect do
repository.delete_file(user, 'README', repository.delete_file(user, 'README',
message: 'Remove README', branch_name: 'master') message: 'Remove README', branch_name: 'master')
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
expect(repository.blob_at('master', 'README')).to be_nil expect(repository.blob_at('master', 'README')).to be_nil
end end
...@@ -610,7 +610,7 @@ describe Repository do ...@@ -610,7 +610,7 @@ describe Repository do
repository.delete_file(user, 'README', repository.delete_file(user, 'README',
message: 'Remove README', branch_name: 'master', message: 'Remove README', branch_name: 'master',
author_email: author_email, author_name: author_name) author_email: author_email, author_name: author_name)
end.to change { repository.commits('master').count }.by(1) end.to change { repository.count_commits(ref: 'master') }.by(1)
last_commit = repository.commit last_commit = repository.commit
......
...@@ -62,7 +62,7 @@ describe API::Commits do ...@@ -62,7 +62,7 @@ describe API::Commits do
context "since optional parameter" do context "since optional parameter" do
it "returns project commits since provided parameter" do it "returns project commits since provided parameter" do
commits = project.repository.commits("master") commits = project.repository.commits("master", limit: 2)
after = commits.second.created_at after = commits.second.created_at
get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user) get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user)
...@@ -73,7 +73,7 @@ describe API::Commits do ...@@ -73,7 +73,7 @@ describe API::Commits do
end end
it 'include correct pagination headers' do it 'include correct pagination headers' do
commits = project.repository.commits("master") commits = project.repository.commits("master", limit: 2)
after = commits.second.created_at after = commits.second.created_at
commit_count = project.repository.count_commits(ref: 'master', after: after).to_s commit_count = project.repository.count_commits(ref: 'master', after: after).to_s
...@@ -87,12 +87,12 @@ describe API::Commits do ...@@ -87,12 +87,12 @@ describe API::Commits do
context "until optional parameter" do context "until optional parameter" do
it "returns project commits until provided parameter" do it "returns project commits until provided parameter" do
commits = project.repository.commits("master") commits = project.repository.commits("master", limit: 20)
before = commits.second.created_at before = commits.second.created_at
get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user) get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user)
if commits.size >= 20 if commits.size == 20
expect(json_response.size).to eq(20) expect(json_response.size).to eq(20)
else else
expect(json_response.size).to eq(commits.size - 1) expect(json_response.size).to eq(commits.size - 1)
...@@ -103,7 +103,7 @@ describe API::Commits do ...@@ -103,7 +103,7 @@ describe API::Commits do
end end
it 'include correct pagination headers' do it 'include correct pagination headers' do
commits = project.repository.commits("master") commits = project.repository.commits("master", limit: 2)
before = commits.second.created_at before = commits.second.created_at
commit_count = project.repository.count_commits(ref: 'master', before: before).to_s commit_count = project.repository.count_commits(ref: 'master', before: before).to_s
...@@ -181,7 +181,7 @@ describe API::Commits do ...@@ -181,7 +181,7 @@ describe API::Commits do
let(:page) { 3 } let(:page) { 3 }
it 'returns the third 5 commits' do it 'returns the third 5 commits' do
commit = project.repository.commits('HEAD', offset: (page - 1) * per_page).first commit = project.repository.commits('HEAD', limit: per_page, offset: (page - 1) * per_page).first
expect(json_response.size).to eq(per_page) expect(json_response.size).to eq(per_page)
expect(json_response.first['id']).to eq(commit.id) expect(json_response.first['id']).to eq(commit.id)
......
...@@ -36,7 +36,7 @@ describe API::V3::Commits do ...@@ -36,7 +36,7 @@ describe API::V3::Commits do
context "since optional parameter" do context "since optional parameter" do
it "returns project commits since provided parameter" do it "returns project commits since provided parameter" do
commits = project.repository.commits("master") commits = project.repository.commits("master", limit: 2)
since = commits.second.created_at since = commits.second.created_at
get v3_api("/projects/#{project.id}/repository/commits?since=#{since.utc.iso8601}", user) get v3_api("/projects/#{project.id}/repository/commits?since=#{since.utc.iso8601}", user)
...@@ -49,12 +49,12 @@ describe API::V3::Commits do ...@@ -49,12 +49,12 @@ describe API::V3::Commits do
context "until optional parameter" do context "until optional parameter" do
it "returns project commits until provided parameter" do it "returns project commits until provided parameter" do
commits = project.repository.commits("master") commits = project.repository.commits("master", limit: 20)
before = commits.second.created_at before = commits.second.created_at
get v3_api("/projects/#{project.id}/repository/commits?until=#{before.utc.iso8601}", user) get v3_api("/projects/#{project.id}/repository/commits?until=#{before.utc.iso8601}", user)
if commits.size >= 20 if commits.size == 20
expect(json_response.size).to eq(20) expect(json_response.size).to eq(20)
else else
expect(json_response.size).to eq(commits.size - 1) expect(json_response.size).to eq(commits.size - 1)
......
...@@ -58,11 +58,12 @@ describe MergeRequests::RefreshService do ...@@ -58,11 +58,12 @@ describe MergeRequests::RefreshService do
before do before do
allow(refresh_service).to receive(:execute_hooks) allow(refresh_service).to receive(:execute_hooks)
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
end end
it 'executes hooks with update action' do it 'executes hooks with update action' do
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
expect(refresh_service).to have_received(:execute_hooks) expect(refresh_service).to have_received(:execute_hooks)
.with(@merge_request, 'update', old_rev: @oldrev) .with(@merge_request, 'update', old_rev: @oldrev)
...@@ -78,6 +79,26 @@ describe MergeRequests::RefreshService do ...@@ -78,6 +79,26 @@ describe MergeRequests::RefreshService do
expect(@merge_request.approvals).to be_empty expect(@merge_request.approvals).to be_empty
expect(@fork_merge_request.approvals).not_to be_empty expect(@fork_merge_request.approvals).not_to be_empty
end end
context 'when source branch ref does not exists' do
before do
DeleteBranchService.new(@project, @user).execute(@merge_request.source_branch)
end
it 'closes MRs without source branch ref' do
expect { refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') }
.to change { @merge_request.reload.state }
.from('opened')
.to('closed')
expect(@fork_merge_request.reload).to be_open
end
it 'does not change the merge request diff' do
expect { refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') }
.not_to change { @merge_request.reload.merge_request_diff }
end
end
end end
context 'when pipeline exists for the source branch' do context 'when pipeline exists for the source branch' do
......
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