Commit 15bb2f91 authored by Matija Čupić's avatar Matija Čupić

Merge branch 'master' into 44059-specify-variables-when-executing-a-manual-pipeline-from-the-ui

parents d03cd7b4 c7c9f38d
<script>
import Store from '../../stores/sidebar_store';
import eventHub from '../../event_hub';
import Flash from '../../../flash';
import { __ } from '../../../locale';
import subscriptions from './subscriptions.vue';
......@@ -19,6 +20,12 @@ export default {
store: new Store(),
};
},
created() {
eventHub.$on('toggleSubscription', this.onToggleSubscription);
},
beforeDestroy() {
eventHub.$off('toggleSubscription', this.onToggleSubscription);
},
methods: {
onToggleSubscription() {
this.mediator.toggleSubscription()
......@@ -35,7 +42,6 @@ export default {
<subscriptions
:loading="store.isFetching.subscriptions"
:subscribed="store.subscribed"
@toggleSubscription="onToggleSubscription"
/>
</div>
</template>
......@@ -3,6 +3,7 @@
import icon from '~/vue_shared/components/icon.vue';
import toggleButton from '~/vue_shared/components/toggle_button.vue';
import tooltip from '~/vue_shared/directives/tooltip';
import eventHub from '../../event_hub';
const ICON_ON = 'notifications';
const ICON_OFF = 'notifications-off';
......@@ -47,7 +48,7 @@
},
methods: {
toggleSubscription() {
this.$emit('toggleSubscription', this.id);
eventHub.$emit('toggleSubscription', this.id);
},
},
};
......
export default {
name: 'time-tracking-no-tracking-pane',
template: `
<div class="time-tracking-no-tracking-pane">
<span class="no-value">
{{ __('No estimate or time spent') }}
</span>
</div>
`,
};
<script>
export default {
name: 'TimeTrackingNoTrackingPane',
};
</script>
<template>
<div class="time-tracking-no-tracking-pane">
<span class="no-value">
{{ __('No estimate or time spent') }}
</span>
</div>
</template>
<script>
import $ from 'jquery';
import _ from 'underscore';
......@@ -10,14 +11,17 @@ import Mediator from '../../sidebar_mediator';
import eventHub from '../../event_hub';
export default {
components: {
IssuableTimeTracker,
},
data() {
return {
mediator: new Mediator(),
store: new Store(),
};
},
components: {
IssuableTimeTracker,
mounted() {
this.listenForQuickActions();
},
methods: {
listenForQuickActions() {
......@@ -41,18 +45,17 @@ export default {
}
},
},
mounted() {
this.listenForQuickActions();
},
template: `
<div class="block">
<issuable-time-tracker
:time_estimate="store.timeEstimate"
:time_spent="store.totalTimeSpent"
:human_time_estimate="store.humanTimeEstimate"
:human_time_spent="store.humanTotalTimeSpent"
:rootPath="store.rootPath"
/>
</div>
`,
};
</script>
<template>
<div class="block">
<issuable-time-tracker
:time_estimate="store.timeEstimate"
:time_spent="store.totalTimeSpent"
:human_time_estimate="store.humanTimeEstimate"
:human_time_spent="store.humanTotalTimeSpent"
:root-path="store.rootPath"
/>
</div>
</template>
......@@ -2,7 +2,7 @@
import TimeTrackingHelpState from './help_state.vue';
import TimeTrackingCollapsedState from './collapsed_state.vue';
import timeTrackingSpentOnlyPane from './spent_only_pane';
import timeTrackingNoTrackingPane from './no_tracking_pane';
import TimeTrackingNoTrackingPane from './no_tracking_pane.vue';
import TimeTrackingEstimateOnlyPane from './estimate_only_pane.vue';
import TimeTrackingComparisonPane from './comparison_pane.vue';
......@@ -14,7 +14,7 @@ export default {
TimeTrackingCollapsedState,
TimeTrackingEstimateOnlyPane,
'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane,
'time-tracking-no-tracking-pane': timeTrackingNoTrackingPane,
TimeTrackingNoTrackingPane,
TimeTrackingComparisonPane,
TimeTrackingHelpState,
},
......
import $ from 'jquery';
import Vue from 'vue';
import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking';
import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking.vue';
import SidebarAssignees from './components/assignees/sidebar_assignees.vue';
import ConfidentialIssueSidebar from './components/confidential/confidential_issue_sidebar.vue';
import SidebarMoveIssue from './lib/sidebar_move_issue';
......
<script>
import $ from 'jquery';
import statusIcon from '../mr_widget_status_icon.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
import eventHub from '../../event_hub';
export default {
name: 'MRWidgetWIP',
props: {
mr: { type: Object, required: true },
service: { type: Object, required: true },
name: 'WorkInProgress',
components: {
statusIcon,
},
directives: {
tooltip,
},
props: {
mr: { type: Object, required: true },
service: { type: Object, required: true },
},
data() {
return {
isMakingRequest: false,
};
},
components: {
statusIcon,
},
methods: {
removeWIP() {
this.isMakingRequest = true;
......@@ -36,32 +37,40 @@ export default {
});
},
},
template: `
<div class="mr-widget-body media">
<status-icon status="warning" :show-disabled-button="Boolean(mr.removeWIPPath)" />
<div class="media-body space-children">
<span class="bold">
This is a Work in Progress
<i
v-tooltip
class="fa fa-question-circle"
title="When this merge request is ready, remove the WIP: prefix from the title to allow it to be merged"
aria-label="When this merge request is ready, remove the WIP: prefix from the title to allow it to be merged">
</i>
</span>
<button
v-if="mr.removeWIPPath"
@click="removeWIP"
:disabled="isMakingRequest"
type="button"
class="btn btn-default btn-xs js-remove-wip">
<i
v-if="isMakingRequest"
class="fa fa-spinner fa-spin"
aria-hidden="true" />
Resolve WIP status
</button>
</div>
</div>
`,
};
</script>
<template>
<div class="mr-widget-body media">
<status-icon
status="warning"
:show-disabled-button="Boolean(mr.removeWIPPath)"
/>
<div class="media-body space-children">
<span class="bold">
This is a Work in Progress
<i
v-tooltip
class="fa fa-question-circle"
title="When this merge request is ready,
remove the WIP: prefix from the title to allow it to be merged"
aria-label="When this merge request is ready,
remove the WIP: prefix from the title to allow it to be merged">
</i>
</span>
<button
v-if="mr.removeWIPPath"
@click="removeWIP"
:disabled="isMakingRequest"
type="button"
class="btn btn-default btn-xs js-remove-wip">
<i
v-if="isMakingRequest"
class="fa fa-spinner fa-spin"
aria-hidden="true">
</i>
Resolve WIP status
</button>
</div>
</div>
</template>
......@@ -21,7 +21,7 @@ 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 ClosedState } from './components/states/mr_widget_closed.vue';
export { default as MergingState } from './components/states/mr_widget_merging.vue';
export { default as WipState } from './components/states/mr_widget_wip';
export { default as WorkInProgressState } from './components/states/work_in_progress.vue';
export { default as ArchivedState } from './components/states/mr_widget_archived.vue';
export { default as ConflictsState } from './components/states/mr_widget_conflicts.vue';
export { default as NothingToMergeState } from './components/states/nothing_to_merge.vue';
......
......@@ -12,7 +12,7 @@ import {
ClosedState,
MergingState,
RebaseState,
WipState,
WorkInProgressState,
ArchivedState,
ConflictsState,
NothingToMergeState,
......@@ -220,7 +220,7 @@ export default {
'mr-widget-closed': ClosedState,
'mr-widget-merging': MergingState,
'mr-widget-failed-to-merge': FailedToMerge,
'mr-widget-wip': WipState,
'mr-widget-wip': WorkInProgressState,
'mr-widget-archived': ArchivedState,
'mr-widget-conflicts': ConflictsState,
'mr-widget-nothing-to-merge': NothingToMergeState,
......
......@@ -46,7 +46,7 @@
}
&.middle-block {
margin-top: 0;
margin-top: $gl-padding-24;
margin-bottom: 0;
}
......@@ -61,7 +61,7 @@
}
&.footer-block {
margin-top: 0;
margin-top: $gl-padding-24;
border-bottom: 0;
margin-bottom: -$gl-padding;
}
......
......@@ -212,6 +212,7 @@ $tooltip-font-size: 12px;
/*
* Padding
*/
$gl-padding-24: 24px;
$gl-padding: 16px;
$gl-padding-8: 8px;
$gl-padding-4: 4px;
......
......@@ -50,21 +50,30 @@ module MergeRequests
end
def commit
message = params[:commit_message] || merge_request.merge_commit_message
log_info("Git merge started on JID #{merge_jid}")
commit_id = repository.merge(current_user, source, merge_request, message)
log_info("Git merge finished on JID #{merge_jid} commit #{commit_id}")
commit_id = try_merge
if commit_id
log_info("Git merge finished on JID #{merge_jid} commit #{commit_id}")
else
raise MergeError, 'Conflicts detected during merge'
end
raise MergeError, 'Conflicts detected during merge' unless commit_id
merge_request.update!(merge_commit_sha: commit_id)
end
def try_merge
message = params[:commit_message] || merge_request.merge_commit_message
merge_request.update(merge_commit_sha: commit_id)
repository.merge(current_user, source, merge_request, message)
rescue Gitlab::Git::HooksService::PreReceiveError => e
raise MergeError, e.message
rescue StandardError => e
raise MergeError, "Something went wrong during merge: #{e.message}"
handle_merge_error(log_message: e.message)
raise MergeError, 'Something went wrong during merge pre-receive hook'
rescue => e
handle_merge_error(log_message: e.message)
raise MergeError, 'Something went wrong during merge'
ensure
merge_request.update(in_progress_merge_commit_sha: nil)
merge_request.update!(in_progress_merge_commit_sha: nil)
end
def after_merge
......
......@@ -13,7 +13,7 @@
.panel
.panel-heading.alert.alert-danger
Last repository check
= "(#{time_ago_in_words(@project.last_repository_check_at)} ago)"
= "(#{time_ago_with_tooltip(@project.last_repository_check_at)})"
failed. See
= link_to 'repocheck.log', admin_logs_path
for error messages.
......
......@@ -31,7 +31,7 @@
= tag
%td
- if runner.contacted_at
#{time_ago_in_words(runner.contacted_at)} ago
= time_ago_with_tooltip runner.contacted_at
- else
Never
%td.admin-runner-btn-group-cell
......
......@@ -108,4 +108,4 @@
%td.timestamp
- if build.finished_at
%span #{time_ago_in_words build.finished_at} ago
%span= time_ago_with_tooltip build.finished_at
......@@ -20,5 +20,4 @@
%td
= service.description
%td.light
= time_ago_in_words service.updated_at
ago
= time_ago_with_tooltip service.updated_at
......@@ -2,7 +2,7 @@
= email_default_heading("Hello, #{@resource.name}!")
%p
Your GitLab account has been locked due to an excessive amount of unsuccessful
sign in attempts. Your account will automatically unlock in #{time_ago_in_words(Devise.unlock_in.from_now)}
sign in attempts. Your account will automatically unlock in #{distance_of_time_in_words(Devise.unlock_in)}
or you may click the link below to unlock now.
#cta
= link_to('Unlock account', unlock_url(@resource, unlock_token: @token))
Hello, <%= @resource.name %>!
Your GitLab account has been locked due to an excessive amount of unsuccessful
sign in attempts. Your account will automatically unlock in <%= time_ago_in_words(Devise.unlock_in.from_now) %>
sign in attempts. Your account will automatically unlock in <%= distance_of_time_in_words(Devise.unlock_in) %>
or you may click the link below to unlock now.
<%= unlock_url(@resource, unlock_token: @token) %>
......@@ -15,7 +15,7 @@
- elsif @build.has_expiring_artifacts?
%p.build-detail-row
The artifacts will be removed in
%span= time_ago_in_words @build.artifacts_expire_at
%span= time_ago_with_tooltip @build.artifacts_expire_at
- if @build.artifacts?
.btn-group.btn-group-justified{ role: :group }
......
......@@ -18,7 +18,7 @@
\-
%td
- if tag.created_at
= time_ago_in_words(tag.created_at)
= time_ago_with_tooltip tag.created_at
- else
.light
\-
......
......@@ -62,6 +62,6 @@
%td Last contact
%td
- if @runner.contacted_at
#{time_ago_in_words(@runner.contacted_at)} ago
= time_ago_with_tooltip @runner.contacted_at
- else
Never
......@@ -27,5 +27,4 @@
= service.description
%td.light
- if service.updated_at.present?
= time_ago_in_words service.updated_at
ago
= time_ago_with_tooltip service.updated_at
......@@ -25,7 +25,7 @@
%td
- if trigger.last_used
#{time_ago_in_words(trigger.last_used)} ago
= time_ago_with_tooltip trigger.last_used
- else
Never
......
......@@ -35,5 +35,4 @@
%span.light
#{t('sherlock.finished_at')}:
%strong
= time_ago_in_words(@transaction.finished_at)
= t('sherlock.ago')
= time_ago_with_tooltip @transaction.finished_at
......@@ -35,8 +35,7 @@
= t('sherlock.seconds')
%td= trans.queries.length
%td
= time_ago_in_words(trans.finished_at)
= t('sherlock.ago')
= time_ago_with_tooltip trans.finished_at
%td
= link_to(sherlock_transaction_path(trans), class: 'btn btn-xs') do
= t('sherlock.view')
---
title: Replace time_ago_in_words with JS-based one
merge_request: 18607
author: Takuya Noguchi
type: performance
---
title: Increase new issue metadata form margin
merge_request: 18630
author: George Tsiolis
type: fixed
---
title: Display only generic message on merge error to avoid exposing any potentially
sensitive or user unfriendly backend messages.
merge_request:
author:
type: fixed
---
title: Move WorkInProgress vue component
merge_request: 17536
author: George Tsiolis
type: performance
---
title: Move TimeTrackingNoTrackingPane vue component
merge_request: 18676
author: George Tsiolis
type: performance
---
title: Move SidebarTimeTracking vue component
merge_request: 18677
author: George Tsiolis
type: performance
---
title: Finish NamespaceService migration to Gitaly
merge_request:
author:
type: performance
......@@ -294,17 +294,7 @@ module Gitlab
# add_namespace("default", "gitlab")
#
def add_namespace(storage, name)
Gitlab::GitalyClient.migrate(:add_namespace,
status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled
Gitlab::GitalyClient::NamespaceService.new(storage).add(name)
else
path = full_path(storage, name)
FileUtils.mkdir_p(path, mode: 0770) unless exists?(storage, name)
end
end
rescue Errno::EEXIST => e
Rails.logger.warn("Directory exists as a file: #{e} at: #{path}")
Gitlab::GitalyClient::NamespaceService.new(storage).add(name)
rescue GRPC::InvalidArgument => e
raise ArgumentError, e.message
end
......@@ -316,14 +306,7 @@ module Gitlab
# rm_namespace("default", "gitlab")
#
def rm_namespace(storage, name)
Gitlab::GitalyClient.migrate(:remove_namespace,
status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled
Gitlab::GitalyClient::NamespaceService.new(storage).remove(name)
else
FileUtils.rm_r(full_path(storage, name), force: true)
end
end
Gitlab::GitalyClient::NamespaceService.new(storage).remove(name)
rescue GRPC::InvalidArgument => e
raise ArgumentError, e.message
end
......@@ -335,17 +318,7 @@ module Gitlab
# mv_namespace("/path/to/storage", "gitlab", "gitlabhq")
#
def mv_namespace(storage, old_name, new_name)
Gitlab::GitalyClient.migrate(:rename_namespace,
status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled
Gitlab::GitalyClient::NamespaceService.new(storage)
.rename(old_name, new_name)
else
break false if exists?(storage, new_name) || !exists?(storage, old_name)
FileUtils.mv(full_path(storage, old_name), full_path(storage, new_name))
end
end
Gitlab::GitalyClient::NamespaceService.new(storage).rename(old_name, new_name)
rescue GRPC::InvalidArgument
false
end
......@@ -370,17 +343,8 @@ module Gitlab
# exists?(storage, 'gitlab')
# exists?(storage, 'gitlab/cookies.git')
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def exists?(storage, dir_name)
Gitlab::GitalyClient.migrate(:namespace_exists,
status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled
Gitlab::GitalyClient::NamespaceService.new(storage)
.exists?(dir_name)
else
File.exist?(full_path(storage, dir_name))
end
end
Gitlab::GitalyClient::NamespaceService.new(storage).exists?(dir_name)
end
protected
......
......@@ -19,7 +19,7 @@ feature 'Admin uses repository checks' do
expect(page).to have_content('Repository check was triggered')
end
scenario 'to see a single failed repository check' do
scenario 'to see a single failed repository check', :js do
project = create(:project)
project.update_columns(
last_repository_check_failed: true,
......
......@@ -178,9 +178,10 @@ feature 'Issues > User uses quick actions', :js do
end
context 'when the project is valid but the user not authorized' do
let(:project_unauthorized) {create(:project, :public)}
let(:project_unauthorized) { create(:project, :public) }
before do
gitlab_sign_out
sign_in(user)
visit project_issue_path(project, issue)
end
......@@ -195,6 +196,7 @@ feature 'Issues > User uses quick actions', :js do
context 'when the project is invalid' do
before do
gitlab_sign_out
sign_in(user)
visit project_issue_path(project, issue)
end
......
......@@ -3,6 +3,7 @@ import sidebarSubscriptions from '~/sidebar/components/subscriptions/sidebar_sub
import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarService from '~/sidebar/services/sidebar_service';
import SidebarStore from '~/sidebar/stores/sidebar_store';
import eventHub from '~/sidebar/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import Mock from './mock_data';
......@@ -31,7 +32,7 @@ describe('Sidebar Subscriptions', function () {
mediator,
});
vm.onToggleSubscription();
eventHub.$emit('toggleSubscription');
expect(mediator.toggleSubscription).toHaveBeenCalled();
});
......
......@@ -39,12 +39,4 @@ describe('Subscriptions', function () {
expect(vm.$refs.toggleButton.$el.querySelector('.project-feature-toggle')).toHaveClass('is-checked');
});
it('toggleSubscription method emits `toggleSubscription` event on component', () => {
vm = mountComponent(Subscriptions, { subscribed: true });
spyOn(vm, '$emit');
vm.toggleSubscription();
expect(vm.$emit).toHaveBeenCalledWith('toggleSubscription', jasmine.any(Object));
});
});
import Vue from 'vue';
import wipComponent from '~/vue_merge_request_widget/components/states/mr_widget_wip';
import WorkInProgress from '~/vue_merge_request_widget/components/states/work_in_progress.vue';
import eventHub from '~/vue_merge_request_widget/event_hub';
const createComponent = () => {
const Component = Vue.extend(wipComponent);
const Component = Vue.extend(WorkInProgress);
const mr = {
title: 'The best MR ever',
removeWIPPath: '/path/to/remove/wip',
......@@ -17,10 +17,10 @@ const createComponent = () => {
});
};
describe('MRWidgetWIP', () => {
describe('Wip', () => {
describe('props', () => {
it('should have props', () => {
const { mr, service } = wipComponent.props;
const { mr, service } = WorkInProgress.props;
expect(mr.type instanceof Object).toBeTruthy();
expect(mr.required).toBeTruthy();
......
......@@ -219,7 +219,7 @@ describe MergeRequests::MergeService do
service.execute(merge_request)
expect(merge_request.merge_error).to include(error_message)
expect(merge_request.merge_error).to include('Something went wrong during merge')
expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message))
end
......@@ -231,7 +231,7 @@ describe MergeRequests::MergeService do
service.execute(merge_request)
expect(merge_request.merge_error).to include(error_message)
expect(merge_request.merge_error).to include('Something went wrong during merge pre-receive hook')
expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message))
end
......
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