Commit 837715f6 authored by GitLab Bot's avatar GitLab Bot

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

# Conflicts:
#	Gemfile.lock
#	app/assets/javascripts/dispatcher.js
#	changelogs/unreleased-ee/4378-fix-cluster-js-not-running-on-update-page.yml
#	spec/requests/api/jobs_spec.rb
#	spec/requests/api/v3/builds_spec.rb

[ci skip]
parents 6004bf60 3b13159d
...@@ -992,6 +992,11 @@ entry. ...@@ -992,6 +992,11 @@ entry.
- Added type to CHANGELOG entries. (Jacopo Beschi @jacopo-beschi) - Added type to CHANGELOG entries. (Jacopo Beschi @jacopo-beschi)
- [BUGIFX] Improves subgroup creation permissions. !13418 - [BUGIFX] Improves subgroup creation permissions. !13418
## 9.5.10 (2017-11-08)
- [SECURITY] Add SSRF protections for hostnames that will never resolve but will still connect to localhost
- [SECURITY] Include X-Content-Type-Options (XCTO) header into API responses
## 9.5.9 (2017-10-16) ## 9.5.9 (2017-10-16)
- [SECURITY] Move project repositories between namespaces when renaming users. - [SECURITY] Move project repositories between namespaces when renaming users.
......
...@@ -118,7 +118,7 @@ gem 'google-api-client', '~> 0.13.6' ...@@ -118,7 +118,7 @@ gem 'google-api-client', '~> 0.13.6'
gem 'unf', '~> 0.1.4' gem 'unf', '~> 0.1.4'
# Seed data # Seed data
gem 'seed-fu', '2.3.6' # Upgrade to > 2.3.7 once https://github.com/mbleigh/seed-fu/issues/123 is solved gem 'seed-fu', '~> 2.3.7'
# Search # Search
gem 'elasticsearch-model', '~> 0.1.9' gem 'elasticsearch-model', '~> 0.1.9'
......
...@@ -861,7 +861,7 @@ GEM ...@@ -861,7 +861,7 @@ GEM
rake (>= 0.9, < 13) rake (>= 0.9, < 13)
sass (~> 3.5.3) sass (~> 3.5.3)
securecompare (1.0.0) securecompare (1.0.0)
seed-fu (2.3.6) seed-fu (2.3.7)
activerecord (>= 3.1) activerecord (>= 3.1)
activesupport (>= 3.1) activesupport (>= 3.1)
select2-rails (3.5.9.3) select2-rails (3.5.9.3)
...@@ -1069,7 +1069,10 @@ DEPENDENCIES ...@@ -1069,7 +1069,10 @@ DEPENDENCIES
email_spec (~> 1.6.0) email_spec (~> 1.6.0)
factory_bot_rails (~> 4.8.2) factory_bot_rails (~> 4.8.2)
faraday (~> 0.12) faraday (~> 0.12)
<<<<<<< HEAD
faraday_middleware-aws-signers-v4 faraday_middleware-aws-signers-v4
=======
>>>>>>> upstream/master
fast_blank fast_blank
ffaker (~> 2.4) ffaker (~> 2.4)
flay (~> 2.8.0) flay (~> 2.8.0)
...@@ -1210,7 +1213,7 @@ DEPENDENCIES ...@@ -1210,7 +1213,7 @@ DEPENDENCIES
sanitize (~> 2.0) sanitize (~> 2.0)
sass-rails (~> 5.0.6) sass-rails (~> 5.0.6)
scss_lint (~> 0.56.0) scss_lint (~> 0.56.0)
seed-fu (= 2.3.6) seed-fu (~> 2.3.7)
select2-rails (~> 3.5.9) select2-rails (~> 3.5.9)
selenium-webdriver (~> 3.5) selenium-webdriver (~> 3.5)
sentry-raven (~> 2.5.3) sentry-raven (~> 2.5.3)
......
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
import { s__ } from './locale';
import projectSelect from './project_select'; import projectSelect from './project_select';
import Milestone from './milestone'; import Milestone from './milestone';
import IssuableForm from './issuable_form'; import IssuableForm from './issuable_form';
...@@ -14,7 +13,6 @@ import Project from './project'; ...@@ -14,7 +13,6 @@ import Project from './project';
import projectAvatar from './project_avatar'; import projectAvatar from './project_avatar';
import MergeRequest from './merge_request'; import MergeRequest from './merge_request';
import Compare from './compare'; import Compare from './compare';
import initCompareAutocomplete from './compare_autocomplete';
import ProjectNew from './project_new'; import ProjectNew from './project_new';
import Labels from './labels'; import Labels from './labels';
import LabelManager from './label_manager'; import LabelManager from './label_manager';
...@@ -22,12 +20,10 @@ import Sidebar from './right_sidebar'; ...@@ -22,12 +20,10 @@ import Sidebar from './right_sidebar';
import IssuableTemplateSelectors from './templates/issuable_template_selectors'; import IssuableTemplateSelectors from './templates/issuable_template_selectors';
import Flash from './flash'; import Flash from './flash';
import CommitsList from './commits';
import BindInOut from './behaviors/bind_in_out'; import BindInOut from './behaviors/bind_in_out';
import SecretValues from './behaviors/secret_values'; import SecretValues from './behaviors/secret_values';
import Group from './group'; import Group from './group';
import ProjectsList from './projects_list'; import ProjectsList from './projects_list';
import MiniPipelineGraph from './mini_pipeline_graph_dropdown';
import UserCallout from './user_callout'; import UserCallout from './user_callout';
import ShortcutsWiki from './shortcuts_wiki'; import ShortcutsWiki from './shortcuts_wiki';
import BlobViewer from './blob/viewer/index'; import BlobViewer from './blob/viewer/index';
...@@ -42,8 +38,6 @@ import PerformanceBar from './performance_bar'; ...@@ -42,8 +38,6 @@ import PerformanceBar from './performance_bar';
import initNotes from './init_notes'; import initNotes from './init_notes';
import initIssuableSidebar from './init_issuable_sidebar'; import initIssuableSidebar from './init_issuable_sidebar';
import initProjectVisibilitySelector from './project_visibility'; import initProjectVisibilitySelector from './project_visibility';
import GpgBadges from './gpg_badges';
import initChangesDropdown from './init_changes_dropdown';
import NewGroupChild from './groups/new_group_child'; import NewGroupChild from './groups/new_group_child';
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils'; import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
import GlFieldErrors from './gl_field_errors'; import GlFieldErrors from './gl_field_errors';
...@@ -58,7 +52,6 @@ import Diff from './diff'; ...@@ -58,7 +52,6 @@ import Diff from './diff';
import ProjectLabelSubscription from './project_label_subscription'; import ProjectLabelSubscription from './project_label_subscription';
import SearchAutocomplete from './search_autocomplete'; import SearchAutocomplete from './search_autocomplete';
import Activities from './activities'; import Activities from './activities';
import { fetchCommitMergeRequests } from './commit_merge_requests';
// EE-only // EE-only
import ApproversSelect from 'ee/approvers_select'; // eslint-disable-line import/first import ApproversSelect from 'ee/approvers_select'; // eslint-disable-line import/first
...@@ -233,9 +226,9 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -233,9 +226,9 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
new ZenMode(); new ZenMode();
break; break;
case 'projects:compare:show': case 'projects:compare:show':
new Diff(); import('./pages/projects/compare/show')
const paddingTop = 16; .then(callDefault)
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - paddingTop); .catch(fail);
break; break;
case 'projects:branches:new': case 'projects:branches:new':
import('./pages/projects/branches/new') import('./pages/projects/branches/new')
...@@ -288,8 +281,11 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -288,8 +281,11 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
new LabelsSelect(); new LabelsSelect();
new MilestoneSelect(); new MilestoneSelect();
new IssuableTemplateSelectors(); new IssuableTemplateSelectors();
<<<<<<< HEAD
initApprovals(); initApprovals();
=======
>>>>>>> upstream/master
break; break;
case 'projects:tags:new': case 'projects:tags:new':
import('./pages/projects/tags/new') import('./pages/projects/tags/new')
...@@ -351,23 +347,15 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -351,23 +347,15 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
.catch(fail); .catch(fail);
break; break;
case 'projects:commit:show': case 'projects:commit:show':
new Diff(); import('./pages/projects/commit/show')
new ZenMode(); .then(callDefault)
shortcut_handler = new ShortcutsNavigation(); .catch(fail);
new MiniPipelineGraph({ shortcut_handler = true;
container: '.js-commit-pipeline-graph',
}).bindEvents();
initNotes();
const stickyBarPaddingTop = 16;
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - stickyBarPaddingTop);
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
fetchCommitMergeRequests();
break; break;
case 'projects:commit:pipelines': case 'projects:commit:pipelines':
new MiniPipelineGraph({ import('./pages/projects/commit/pipelines')
container: '.js-commit-pipeline-graph', .then(callDefault)
}).bindEvents(); .catch(fail);
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
break; break;
case 'projects:activity': case 'projects:activity':
import('./pages/projects/activity') import('./pages/projects/activity')
...@@ -376,9 +364,10 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -376,9 +364,10 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
shortcut_handler = true; shortcut_handler = true;
break; break;
case 'projects:commits:show': case 'projects:commits:show':
CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit); import('./pages/projects/commits/show')
shortcut_handler = new ShortcutsNavigation(); .then(callDefault)
GpgBadges.fetch(); .catch(fail);
shortcut_handler = true;
break; break;
case 'projects:show': case 'projects:show':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
...@@ -624,20 +613,23 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -624,20 +613,23 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
case 'projects:clusters:show': case 'projects:clusters:show':
case 'projects:clusters:update': case 'projects:clusters:update':
case 'projects:clusters:destroy': case 'projects:clusters:destroy':
<<<<<<< HEAD
import(/* webpackChunkName: "clusters" */ './clusters/clusters_bundle') import(/* webpackChunkName: "clusters" */ './clusters/clusters_bundle')
.then(cluster => new cluster.default()) // eslint-disable-line new-cap .then(cluster => new cluster.default()) // eslint-disable-line new-cap
.catch((err) => { .catch((err) => {
Flash(s__('ClusterIntegration|Problem setting up the cluster')); Flash(s__('ClusterIntegration|Problem setting up the cluster'));
throw err; throw err;
}); });
=======
import('./pages/projects/clusters/show')
.then(callDefault)
.catch(fail);
>>>>>>> upstream/master
break; break;
case 'projects:clusters:index': case 'projects:clusters:index':
import(/* webpackChunkName: "clusters_index" */ './clusters/clusters_index') import('./pages/projects/clusters/index')
.then(clusterIndex => clusterIndex.default()) .then(callDefault)
.catch((err) => { .catch(fail);
Flash(s__('ClusterIntegration|Problem setting up the clusters list'));
throw err;
});
break; break;
case 'admin:licenses:new': case 'admin:licenses:new':
import(/* webpackChunkName: "admin_licenses" */ 'ee/pages/admin/licenses/new').then(m => m.default()).catch(fail); import(/* webpackChunkName: "admin_licenses" */ 'ee/pages/admin/licenses/new').then(m => m.default()).catch(fail);
...@@ -735,7 +727,9 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line ...@@ -735,7 +727,9 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
projectAvatar(); projectAvatar();
switch (path[1]) { switch (path[1]) {
case 'compare': case 'compare':
initCompareAutocomplete(); import('./pages/projects/compare')
.then(callDefault)
.catch(fail);
break; break;
case 'edit': case 'edit':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
......
...@@ -3,7 +3,6 @@ import { visitUrl } from './lib/utils/url_utility'; ...@@ -3,7 +3,6 @@ import { visitUrl } from './lib/utils/url_utility';
import bp from './breakpoints'; import bp from './breakpoints';
import { numberToHumanSize } from './lib/utils/number_utils'; import { numberToHumanSize } from './lib/utils/number_utils';
import { setCiStatusFavicon } from './lib/utils/common_utils'; import { setCiStatusFavicon } from './lib/utils/common_utils';
import { timeFor } from './lib/utils/datetime_utility';
export default class Job { export default class Job {
constructor(options) { constructor(options) {
...@@ -71,7 +70,6 @@ export default class Job { ...@@ -71,7 +70,6 @@ export default class Job {
.off('resize.build') .off('resize.build')
.on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100)); .on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100));
this.updateArtifactRemoveDate();
this.initAffixTopArea(); this.initAffixTopArea();
this.getBuildTrace(); this.getBuildTrace();
...@@ -261,16 +259,7 @@ export default class Job { ...@@ -261,16 +259,7 @@ export default class Job {
sidebarOnClick() { sidebarOnClick() {
if (this.shouldHideSidebarForViewport()) this.toggleSidebar(); if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
} }
// eslint-disable-next-line class-methods-use-this, consistent-return
updateArtifactRemoveDate() {
const $date = $('.js-artifacts-remove');
if ($date.length) {
const date = $date.text();
return $date.text(
timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3'))),
);
}
}
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
populateJobs(stage) { populateJobs(stage) {
$('.build-job').hide(); $('.build-job').hide();
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
<loading-icon <loading-icon
v-if="isLoading" v-if="isLoading"
size="2" size="2"
class="prepend-top-default append-bottom-default"
/> />
</div> </div>
</template> </template>
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, no-underscore-dangle, one-var, one-var-declaration-per-line, consistent-return, dot-notation, quote-props, comma-dangle, object-shorthand, max-len, prefer-arrow-callback */ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, no-underscore-dangle, one-var, one-var-declaration-per-line, consistent-return, dot-notation, quote-props, comma-dangle, object-shorthand, max-len, prefer-arrow-callback */
import 'vendor/jquery.waitforimages'; import 'vendor/jquery.waitforimages';
import { __ } from '~/locale';
import TaskList from './task_list'; import TaskList from './task_list';
import MergeRequestTabs from './merge_request_tabs'; import MergeRequestTabs from './merge_request_tabs';
import IssuablesHelper from './helpers/issuables_helper'; import IssuablesHelper from './helpers/issuables_helper';
...@@ -110,12 +111,12 @@ MergeRequest.prototype.initCommitMessageListeners = function() { ...@@ -110,12 +111,12 @@ MergeRequest.prototype.initCommitMessageListeners = function() {
}); });
}; };
MergeRequest.updateStatusText = function(classToRemove, classToAdd, newStatusText) { MergeRequest.setStatusBoxToMerged = function() {
$('.detail-page-header .status-box') $('.detail-page-header .status-box')
.removeClass(classToRemove) .removeClass('status-box-open')
.addClass(classToAdd) .addClass('status-box-mr-merged')
.find('span') .find('span')
.text(newStatusText); .text(__('Merged'));
}; };
MergeRequest.decreaseCounter = function(by = 1) { MergeRequest.decreaseCounter = function(by = 1) {
......
import ClustersIndex from '~/clusters/clusters_index';
export default () => {
new ClustersIndex(); // eslint-disable-line no-new
};
import ClustersBundle from '~/clusters/clusters_bundle';
export default () => {
new ClustersBundle(); // eslint-disable-line no-new
};
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
export default () => {
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
};
/* eslint-disable no-new */
import Diff from '~/diff';
import ZenMode from '~/zen_mode';
import ShortcutsNavigation from '~/shortcuts_navigation';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
import initNotes from '~/init_notes';
import initChangesDropdown from '~/init_changes_dropdown';
import { fetchCommitMergeRequests } from '~/commit_merge_requests';
export default () => {
new Diff();
new ZenMode();
new ShortcutsNavigation();
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
initNotes();
const stickyBarPaddingTop = 16;
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - stickyBarPaddingTop);
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
fetchCommitMergeRequests();
};
import CommitsList from '~/commits';
import GpgBadges from '~/gpg_badges';
import ShortcutsNavigation from '~/shortcuts_navigation';
export default () => {
CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
new ShortcutsNavigation(); // eslint-disable-line no-new
GpgBadges.fetch();
};
import initCompareAutocomplete from '~/compare_autocomplete';
export default () => {
initCompareAutocomplete();
};
import Diff from '~/diff';
import initChangesDropdown from '~/init_changes_dropdown';
export default () => {
new Diff(); // eslint-disable-line no-new
const paddingTop = 16;
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - paddingTop);
};
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import icon from '../../vue_shared/components/icon.vue';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default { export default {
...@@ -12,6 +13,7 @@ ...@@ -12,6 +13,7 @@
components: { components: {
loadingIcon, loadingIcon,
icon,
}, },
props: { props: {
endpoint: { endpoint: {
...@@ -42,9 +44,6 @@ ...@@ -42,9 +44,6 @@
}; };
}, },
computed: { computed: {
iconClass() {
return `fa fa-${this.icon}`;
},
buttonClass() { buttonClass() {
return `btn ${this.cssClass}`; return `btn ${this.cssClass}`;
}, },
...@@ -77,10 +76,9 @@ ...@@ -77,10 +76,9 @@
data-container="body" data-container="body"
data-placement="top" data-placement="top"
:disabled="isLoading"> :disabled="isLoading">
<i <icon
:class="iconClass" :name="icon"
aria-hidden="true"> />
</i>
<loading-icon v-if="isLoading" /> <loading-icon v-if="isLoading" />
</button> </button>
</template> </template>
...@@ -93,6 +93,7 @@ ...@@ -93,6 +93,7 @@
<loading-icon <loading-icon
v-if="isLoading" v-if="isLoading"
size="2" size="2"
class="prepend-top-default append-bottom-default"
/> />
</div> </div>
</template> </template>
<script> <script>
import playIconSvg from 'icons/_icon_play.svg';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import icon from '../../vue_shared/components/icon.vue';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default { export default {
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
}, },
components: { components: {
loadingIcon, loadingIcon,
icon,
}, },
props: { props: {
actions: { actions: {
...@@ -19,7 +20,6 @@ ...@@ -19,7 +20,6 @@
}, },
data() { data() {
return { return {
playIconSvg,
isLoading: false, isLoading: false,
}; };
}, },
...@@ -52,7 +52,10 @@ ...@@ -52,7 +52,10 @@
aria-label="Manual job" aria-label="Manual job"
:disabled="isLoading" :disabled="isLoading"
> >
<span v-html="playIconSvg"></span> <icon
name="play"
class="icon-play"
/>
<i <i
class="fa fa-caret-down" class="fa fa-caret-down"
aria-hidden="true"> aria-hidden="true">
......
...@@ -313,7 +313,7 @@ ...@@ -313,7 +313,7 @@
:endpoint="pipeline.cancel_path" :endpoint="pipeline.cancel_path"
css-class="js-pipelines-cancel-button btn-remove" css-class="js-pipelines-cancel-button btn-remove"
title="Cancel" title="Cancel"
icon="remove" icon="close"
confirm-action-message="Are you sure you want to cancel this pipeline?" confirm-action-message="Are you sure you want to cancel this pipeline?"
/> />
</div> </div>
......
...@@ -62,7 +62,7 @@ export default class Shortcuts { ...@@ -62,7 +62,7 @@ export default class Shortcuts {
e.preventDefault(); e.preventDefault();
const performanceBarCookieName = 'perf_bar_enabled'; const performanceBarCookieName = 'perf_bar_enabled';
if (Cookies.get(performanceBarCookieName) === 'true') { if (Cookies.get(performanceBarCookieName) === 'true') {
Cookies.remove(performanceBarCookieName, { path: '/' }); Cookies.set(performanceBarCookieName, 'false', { path: '/' });
} else { } else {
Cookies.set(performanceBarCookieName, 'true', { path: '/' }); Cookies.set(performanceBarCookieName, 'true', { path: '/' });
} }
......
...@@ -170,7 +170,7 @@ export default { ...@@ -170,7 +170,7 @@ export default {
// If state is merged we should update the widget and stop the polling // If state is merged we should update the widget and stop the polling
eventHub.$emit('MRWidgetUpdateRequested'); eventHub.$emit('MRWidgetUpdateRequested');
eventHub.$emit('FetchActionsContent'); eventHub.$emit('FetchActionsContent');
MergeRequest.updateStatusText('status-box-open', 'status-box-merged', 'Merged'); MergeRequest.setStatusBoxToMerged();
MergeRequest.hideCloseButton(); MergeRequest.hideCloseButton();
MergeRequest.decreaseCounter(); MergeRequest.decreaseCounter();
stopPolling(); stopPolling();
......
...@@ -122,7 +122,7 @@ ...@@ -122,7 +122,7 @@
> >
<button <button
type="button" type="button"
class="btn pull-left" class="btn"
:class="btnCancelKindClass" :class="btnCancelKindClass"
@click="emitCancel($event)" @click="emitCancel($event)"
data-dismiss="modal" data-dismiss="modal"
...@@ -132,7 +132,7 @@ ...@@ -132,7 +132,7 @@
<button <button
v-if="primaryButtonLabel" v-if="primaryButtonLabel"
type="button" type="button"
class="btn pull-right js-primary-button" class="btn js-primary-button"
:disabled="submitDisabled" :disabled="submitDisabled"
:class="btnKindClass" :class="btnKindClass"
@click="emitSubmit($event)" @click="emitSubmit($event)"
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
@include set-visible; @include set-visible;
min-height: $dropdown-min-height; min-height: $dropdown-min-height;
max-height: $dropdown-max-height; max-height: $dropdown-max-height;
overflow: auto; overflow-y: auto;
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
width: 100%; width: 100%;
......
...@@ -303,6 +303,8 @@ ...@@ -303,6 +303,8 @@
.projects-dropdown-menu { .projects-dropdown-menu {
padding: 0; padding: 0;
overflow-y: initial;
max-height: initial;
} }
.dropdown-chevron { .dropdown-chevron {
......
...@@ -24,15 +24,13 @@ ...@@ -24,15 +24,13 @@
font-size: $gl-font-size; font-size: $gl-font-size;
line-height: 25px; line-height: 25px;
&.status-box-closed,
&.status-box-mr-closed { &.status-box-mr-closed {
background-color: $gl-danger; background-color: $gl-danger;
} }
&.status-box-issue-closed { &.status-box-issue-closed,
background-color: $gl-primary; &.status-box-mr-merged {
}
&.status-box-merged {
background-color: $gl-primary; background-color: $gl-primary;
} }
......
.modal-header { .modal-header {
background-color: $modal-body-bg;
padding: #{3 * $grid-size} #{2 * $grid-size}; padding: #{3 * $grid-size} #{2 * $grid-size};
.page-title { .page-title {
...@@ -8,6 +9,7 @@ ...@@ -8,6 +9,7 @@
.modal-body { .modal-body {
background-color: $modal-body-bg; background-color: $modal-body-bg;
min-height: $modal-body-height;
position: relative; position: relative;
padding: #{3 * $grid-size} #{2 * $grid-size}; padding: #{3 * $grid-size} #{2 * $grid-size};
...@@ -20,6 +22,30 @@ ...@@ -20,6 +22,30 @@
} }
} }
.modal-footer {
display: flex;
flex-direction: row;
.btn + .btn {
margin-left: $grid-size;
}
@media (max-width: $screen-xs-max) {
flex-direction: column;
.btn + .btn {
margin-left: 0;
margin-top: $grid-size;
}
}
@media (min-width: $screen-sm-min) {
.btn:first-of-type {
margin-left: auto;
}
}
}
body.modal-open { body.modal-open {
overflow: hidden; overflow: hidden;
} }
...@@ -32,12 +58,6 @@ body.modal-open { ...@@ -32,12 +58,6 @@ body.modal-open {
} }
} }
@media (min-width: $screen-md-min) {
.modal-dialog {
width: 860px;
}
}
@media (min-width: $screen-lg-min) { @media (min-width: $screen-lg-min) {
.modal-full { .modal-full {
width: 98%; width: 98%;
......
...@@ -194,6 +194,6 @@ $modal-body-bg: $white-light; ...@@ -194,6 +194,6 @@ $modal-body-bg: $white-light;
//** Modal footer border color //** Modal footer border color
// $modal-footer-border-color: $modal-header-border-color // $modal-footer-border-color: $modal-header-border-color
// $modal-lg: 900px $modal-lg: 860px;
// $modal-md: 600px $modal-md: 540px;
// $modal-sm: 300px // $modal-sm: 300px
...@@ -766,3 +766,8 @@ $popup-box-shadow-color: rgba(90, 90, 90, 0.05); ...@@ -766,3 +766,8 @@ $popup-box-shadow-color: rgba(90, 90, 90, 0.05);
Multi file editor Multi file editor
*/ */
$border-color-settings: #e1e1e1; $border-color-settings: #e1e1e1;
/*
Modals
*/
$modal-body-height: 134px;
...@@ -96,13 +96,6 @@ ...@@ -96,13 +96,6 @@
border-color: $border-white-normal; border-color: $border-white-normal;
} }
} }
.btn {
.icon-play {
height: 13px;
width: 12px;
}
}
} }
.btn .text-center { .btn .text-center {
......
...@@ -3,22 +3,21 @@ ...@@ -3,22 +3,21 @@
// see also: https://gist.github.com/jasonm23/2868981 // see also: https://gist.github.com/jasonm23/2868981
$black: #000; $black: #000;
$red: #cd0000; $red: #ea1010;
$green: #00cd00; $green: #009900;
$yellow: #cdcd00; $yellow: #999900;
$blue: #00e; // according to wikipedia, this is the xterm standard $blue: #0073e6;
//$blue: #1e90ff; // this is used by all the terminals I tried (when configured with the xterm color profile) $magenta: #d411d4;
$magenta: #cd00cd; $cyan: #009999;
$cyan: #00cdcd; $white: #ccc;
$white: #e5e5e5;
$l-black: #373b41; $l-black: #373b41;
$l-red: #c66; $l-red: #ff6161;
$l-green: #b5bd68; $l-green: #00d600;
$l-yellow: #f0c674; $l-yellow: #bdbd00;
$l-blue: #81a2be; $l-blue: #5797ff;
$l-magenta: #b294bb; $l-magenta: #d96dd9;
$l-cyan: #8abeb7; $l-cyan: #00bdbd;
$l-white: $gray-darkest; $l-white: #fff;
/* /*
* xterm colors * xterm colors
......
...@@ -6,13 +6,22 @@ module WithPerformanceBar ...@@ -6,13 +6,22 @@ module WithPerformanceBar
end end
def peek_enabled? def peek_enabled?
return true if Rails.env.development?
return false unless Gitlab::PerformanceBar.enabled?(current_user) return false unless Gitlab::PerformanceBar.enabled?(current_user)
if RequestStore.active? if RequestStore.active?
RequestStore.fetch(:peek_enabled) { cookies[:perf_bar_enabled].present? } RequestStore.fetch(:peek_enabled) { cookie_or_default_value }
else else
cookies[:perf_bar_enabled].present? cookie_or_default_value
end
end
private
def cookie_or_default_value
if cookies[:perf_bar_enabled].present?
cookies[:perf_bar_enabled] == 'true'
else
cookies[:perf_bar_enabled] = 'true' if Rails.env.development?
end end
end end
end end
...@@ -74,7 +74,7 @@ module IssuesHelper ...@@ -74,7 +74,7 @@ module IssuesHelper
if item.try(:expired?) if item.try(:expired?)
'status-box-expired' 'status-box-expired'
elsif item.try(:merged?) elsif item.try(:merged?)
'status-box-merged' 'status-box-mr-merged'
elsif item.closed? elsif item.closed?
'status-box-mr-closed' 'status-box-mr-closed'
elsif item.try(:upcoming?) elsif item.try(:upcoming?)
......
...@@ -54,8 +54,16 @@ module TodosHelper ...@@ -54,8 +54,16 @@ module TodosHelper
def todo_target_state_pill(todo) def todo_target_state_pill(todo)
return unless show_todo_state?(todo) return unless show_todo_state?(todo)
type =
case todo.target
when MergeRequest
'mr'
when Issue
'issue'
end
content_tag(:span, nil, class: 'target-status') do content_tag(:span, nil, class: 'target-status') do
content_tag(:span, nil, class: "status-box status-box-#{todo.target.state.dasherize}") do content_tag(:span, nil, class: "status-box status-box-#{type}-#{todo.target.state.dasherize}") do
todo.target.state.capitalize todo.target.state.capitalize
end end
end end
......
...@@ -46,10 +46,11 @@ class PushEvent < Event ...@@ -46,10 +46,11 @@ class PushEvent < Event
# Returns PushEvent instances for which no merge requests have been created. # Returns PushEvent instances for which no merge requests have been created.
def self.without_existing_merge_requests def self.without_existing_merge_requests
existing_mrs = MergeRequest.except(:order) existing_mrs = MergeRequest.except(:order, :where)
.select(1) .select(1)
.where('merge_requests.source_project_id = events.project_id') .where('merge_requests.source_project_id = events.project_id')
.where('merge_requests.source_branch = push_event_payloads.ref') .where('merge_requests.source_branch = push_event_payloads.ref')
.where(state: :opened)
# For reasons unknown the use of #eager_load will result in the # For reasons unknown the use of #eager_load will result in the
# "push_event_payload" association not being set. Because of this we're # "push_event_payload" association not being set. Because of this we're
......
...@@ -13,6 +13,7 @@ module Labels ...@@ -13,6 +13,7 @@ module Labels
update_issuables(new_label, batched_ids) update_issuables(new_label, batched_ids)
update_issue_board_lists(new_label, batched_ids) update_issue_board_lists(new_label, batched_ids)
update_priorities(new_label, batched_ids) update_priorities(new_label, batched_ids)
subscribe_users(new_label, batched_ids)
# Order is important, project labels need to be last # Order is important, project labels need to be last
update_project_labels(batched_ids) update_project_labels(batched_ids)
end end
...@@ -26,6 +27,15 @@ module Labels ...@@ -26,6 +27,15 @@ module Labels
private private
def subscribe_users(new_label, label_ids)
# users can be subscribed to multiple labels that will be merged into the group one
# we want to keep only one subscription / user
ids_to_update = Subscription.where(subscribable_id: label_ids, subscribable_type: 'Label')
.group(:user_id)
.pluck('MAX(id)')
Subscription.where(id: ids_to_update).update_all(subscribable_id: new_label.id)
end
def label_ids_for_merge(new_label) def label_ids_for_merge(new_label)
LabelsFinder LabelsFinder
.new(current_user, title: new_label.title, group_id: project.group.id) .new(current_user, title: new_label.title, group_id: project.group.id)
...@@ -53,7 +63,7 @@ module Labels ...@@ -53,7 +63,7 @@ module Labels
end end
def update_project_labels(label_ids) def update_project_labels(label_ids)
Label.where(id: label_ids).delete_all Label.where(id: label_ids).destroy_all
end end
def clone_label_to_group_label(label) def clone_label_to_group_label(label)
......
...@@ -54,6 +54,7 @@ module MergeRequests ...@@ -54,6 +54,7 @@ module MergeRequests
source_project_id: project.id, source_project_id: project.id,
source_branch: branch_name, source_branch: branch_name,
target_project_id: project.id, target_project_id: project.id,
target_branch: ref,
milestone_id: issue.milestone_id milestone_id: issue.milestone_id
} }
end end
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
.form-group.visibility-level-setting .form-group.visibility-level-setting
= f.label :visibility_level, class: 'label-light' do = f.label :visibility_level, class: 'label-light' do
Visibility Level Visibility Level
= link_to icon('question-circle'), help_page_path("public_access/public_access"), aria: { label: 'Documentation for Visibility Level' } = link_to icon('question-circle'), help_page_path("public_access/public_access"), aria: { label: 'Documentation for Visibility Level' }, target: '_blank', rel: 'noopener noreferrer'
= render 'shared/visibility_level', f: f, visibility_level: visibility_level.to_i, can_change_visibility_level: true, form_model: @project, with_label: false = render 'shared/visibility_level', f: f, visibility_level: visibility_level.to_i, can_change_visibility_level: true, form_model: @project, with_label: false
= f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4 = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
......
#modal-create-new-dir.modal #modal-create-new-dir.modal
.modal-dialog .modal-dialog.modal-lg
.modal-content .modal-content
.modal-header .modal-header
%a.close{ href: "#", "data-dismiss" => "modal" } × %a.close{ href: "#", "data-dismiss" => "modal" } ×
......
#modal-upload-blob.modal #modal-upload-blob.modal
.modal-dialog .modal-dialog.modal-lg
.modal-content .modal-content
.modal-header .modal-header
%a.close{ href: "#", "data-dismiss" => "modal" } × %a.close{ href: "#", "data-dismiss" => "modal" } ×
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
- elsif @build.has_expiring_artifacts? - elsif @build.has_expiring_artifacts?
%p.build-detail-row %p.build-detail-row
The artifacts will be removed in The artifacts will be removed in
%span.js-artifacts-remove= @build.artifacts_expire_at %span= time_ago_in_words @build.artifacts_expire_at
- if @build.artifacts? - if @build.artifacts?
.btn-group.btn-group-justified{ role: :group } .btn-group.btn-group-justified{ role: :group }
......
--- ---
title: Fix JavaScript bundle running on Cluster update/destroy pages title: Fix JavaScript bundle running on Cluster update/destroy pages
<<<<<<< HEAD
merge_request: 4112 merge_request: 4112
=======
merge_request:
>>>>>>> upstream/master
author: author:
type: fixed type: fixed
---
title: Keep subscribers when promoting labels to group labels
merge_request:
author:
type: fixed
---
title: increase-readability-of-colored-text-in-job-output-log
merge_request:
author:
type: other
---
title: Last push widget will show banner for new pushes to previously merged branch
merge_request:
author:
type: changed
---
title: Adds sorting to deployments API
merge_request: !16396
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Set target_branch to the ref branch when creating MR from issue
merge_request:
author:
type: fixed
---
title: Fix closed text for issues on Todos page
merge_request:
author:
type: fixed
---
title: Fix links to uploaded files on wiki pages
merge_request: 16499
author:
type: fixed
---
title: Support PostgreSQL 10
merge_request: 16471
author:
type: added
---
title: Open visibility level help in a new tab
merge_request:
author: Jussi Räsänen
type: fixed
---
title: Fix tooltip displayed for running manual actions
merge_request: 16489
author:
type: fixed
---
title: Prevent RevList failing on non utf8 paths
merge_request: 16440
author:
type: fixed
---
title: Adjust modal style to new design
merge_request: 16310
author:
type: other
raise "Vendored ActiveRecord 5 code! Delete #{__FILE__}!" if ActiveRecord::VERSION::MAJOR >= 5
require 'active_record/connection_adapters/postgresql_adapter'
require 'active_record/connection_adapters/postgresql/schema_statements'
#
# Monkey-patch the refused Rails 4.2 patch at https://github.com/rails/rails/pull/31330
#
# Updates sequence logic to support PostgreSQL 10.
#
# rubocop:disable all
module ActiveRecord
module ConnectionAdapters
# We need #postgresql_version to be public as in ActiveRecord 5 for seed_fu
# to work. In ActiveRecord 4, it is protected.
# https://github.com/mbleigh/seed-fu/issues/123
class PostgreSQLAdapter
public :postgresql_version
end
module PostgreSQL
module SchemaStatements
# Resets the sequence of a table's primary key to the maximum value.
def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
unless pk and sequence
default_pk, default_sequence = pk_and_sequence_for(table)
pk ||= default_pk
sequence ||= default_sequence
end
if @logger && pk && !sequence
@logger.warn "#{table} has primary key #{pk} with no default sequence"
end
if pk && sequence
quoted_sequence = quote_table_name(sequence)
max_pk = select_value("SELECT MAX(#{quote_column_name pk}) FROM #{quote_table_name(table)}")
if max_pk.nil?
if postgresql_version >= 100000
minvalue = select_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass")
else
minvalue = select_value("SELECT min_value FROM #{quoted_sequence}")
end
end
select_value <<-end_sql, 'SCHEMA'
SELECT setval(#{quote(quoted_sequence)}, #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})
end_sql
end
end
end
end
end
end
# rubocop:enable all
class AddMergeRequestStateIndex < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :merge_requests, [:source_project_id, :source_branch],
where: "state = 'opened'",
name: 'index_merge_requests_on_source_project_and_branch_state_opened'
end
def down
remove_concurrent_index_by_name :merge_requests,
'index_merge_requests_on_source_project_and_branch_state_opened'
end
end
...@@ -1468,6 +1468,7 @@ ActiveRecord::Schema.define(version: 20180105233807) do ...@@ -1468,6 +1468,7 @@ ActiveRecord::Schema.define(version: 20180105233807) do
add_index "merge_requests", ["merge_user_id"], name: "index_merge_requests_on_merge_user_id", where: "(merge_user_id IS NOT NULL)", using: :btree add_index "merge_requests", ["merge_user_id"], name: "index_merge_requests_on_merge_user_id", where: "(merge_user_id IS NOT NULL)", using: :btree
add_index "merge_requests", ["milestone_id"], name: "index_merge_requests_on_milestone_id", using: :btree add_index "merge_requests", ["milestone_id"], name: "index_merge_requests_on_milestone_id", using: :btree
add_index "merge_requests", ["source_branch"], name: "index_merge_requests_on_source_branch", using: :btree add_index "merge_requests", ["source_branch"], name: "index_merge_requests_on_source_branch", using: :btree
add_index "merge_requests", ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_and_branch_state_opened", where: "((state)::text = 'opened'::text)", using: :btree
add_index "merge_requests", ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_id_and_source_branch", using: :btree add_index "merge_requests", ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_id_and_source_branch", using: :btree
add_index "merge_requests", ["target_branch"], name: "index_merge_requests_on_target_branch", using: :btree add_index "merge_requests", ["target_branch"], name: "index_merge_requests_on_target_branch", using: :btree
add_index "merge_requests", ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid", unique: true, using: :btree add_index "merge_requests", ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid", unique: true, using: :btree
......
...@@ -11,6 +11,8 @@ GET /projects/:id/deployments ...@@ -11,6 +11,8 @@ GET /projects/:id/deployments
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
|-----------|---------|----------|---------------------| |-----------|---------|----------|---------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `order_by`| string | no | Return deployments ordered by `id` or `iid` or `created_at` or `ref` fields. Default is `id` |
| `sort` | string | no | Return deployments sorted in `asc` or `desc` order. Default is `asc` |
```bash ```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/deployments" curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/deployments"
......
...@@ -10,6 +10,7 @@ This is what the `.gitlab-ci.yml` file looks like for this project: ...@@ -10,6 +10,7 @@ This is what the `.gitlab-ci.yml` file looks like for this project:
```yaml ```yaml
test: test:
stage: test
script: script:
- apt-get update -qy - apt-get update -qy
- apt-get install -y nodejs - apt-get install -y nodejs
...@@ -18,7 +19,7 @@ test: ...@@ -18,7 +19,7 @@ test:
- bundle exec rake test - bundle exec rake test
staging: staging:
type: deploy stage: deploy
script: script:
- gem install dpl - gem install dpl
- dpl --provider=heroku --app=gitlab-ci-ruby-test-staging --api-key=$HEROKU_STAGING_API_KEY - dpl --provider=heroku --app=gitlab-ci-ruby-test-staging --api-key=$HEROKU_STAGING_API_KEY
...@@ -26,7 +27,7 @@ staging: ...@@ -26,7 +27,7 @@ staging:
- master - master
production: production:
type: deploy stage: deploy
script: script:
- gem install dpl - gem install dpl
- dpl --provider=heroku --app=gitlab-ci-ruby-test-prod --api-key=$HEROKU_PRODUCTION_API_KEY - dpl --provider=heroku --app=gitlab-ci-ruby-test-prod --api-key=$HEROKU_PRODUCTION_API_KEY
......
...@@ -123,7 +123,7 @@ Existing users using GitLab with MySQL/MariaDB are advised to ...@@ -123,7 +123,7 @@ Existing users using GitLab with MySQL/MariaDB are advised to
### PostgreSQL Requirements ### PostgreSQL Requirements
As of GitLab 10.0, PostgreSQL 9.6 or newer (but less than 10) is required, and earlier versions are As of GitLab 10.0, PostgreSQL 9.6 or newer is required, and earlier versions are
not supported. We highly recommend users to use PostgreSQL 9.6 as this not supported. We highly recommend users to use PostgreSQL 9.6 as this
is the PostgreSQL version used for development and testing. is the PostgreSQL version used for development and testing.
......
...@@ -15,11 +15,13 @@ module API ...@@ -15,11 +15,13 @@ module API
end end
params do params do
use :pagination use :pagination
optional :order_by, type: String, values: %w[id iid created_at ref], default: 'id', desc: 'Return deployments ordered by `id` or `iid` or `created_at` or `ref`'
optional :sort, type: String, values: %w[asc desc], default: 'asc', desc: 'Sort by asc (ascending) or desc (descending)'
end end
get ':id/deployments' do get ':id/deployments' do
authorize! :read_deployment, user_project authorize! :read_deployment, user_project
present paginate(user_project.deployments), with: Entities::Deployment present paginate(user_project.deployments.order(params[:order_by] => params[:sort])), with: Entities::Deployment
end end
desc 'Gets a specific deployment' do desc 'Gets a specific deployment' do
......
...@@ -108,7 +108,10 @@ module Backup ...@@ -108,7 +108,10 @@ module Backup
$progress.puts "Please make sure that file name ends with #{FILE_NAME_SUFFIX}" $progress.puts "Please make sure that file name ends with #{FILE_NAME_SUFFIX}"
exit 1 exit 1
elsif backup_file_list.many? && ENV["BACKUP"].nil? elsif backup_file_list.many? && ENV["BACKUP"].nil?
$progress.puts 'Found more than one backup, please specify which one you want to restore:' $progress.puts 'Found more than one backup:'
# print list of available backups
$progress.puts " " + available_timestamps.join("\n ")
$progress.puts 'Please specify which one you want to restore:'
$progress.puts 'rake gitlab:backup:restore BACKUP=timestamp_of_backup' $progress.puts 'rake gitlab:backup:restore BACKUP=timestamp_of_backup'
exit 1 exit 1
end end
...@@ -169,6 +172,10 @@ module Backup ...@@ -169,6 +172,10 @@ module Backup
@backup_file_list ||= Dir.glob("*#{FILE_NAME_SUFFIX}") @backup_file_list ||= Dir.glob("*#{FILE_NAME_SUFFIX}")
end end
def available_timestamps
@backup_file_list.map {|item| item.gsub("#{FILE_NAME_SUFFIX}", "")}
end
def connect_to_remote_directory(connection_settings) def connect_to_remote_directory(connection_settings)
# our settings use string keys, but Fog expects symbols # our settings use string keys, but Fog expects symbols
connection = ::Fog::Storage.new(connection_settings.symbolize_keys) connection = ::Fog::Storage.new(connection_settings.symbolize_keys)
......
...@@ -9,6 +9,10 @@ module Banzai ...@@ -9,6 +9,10 @@ module Banzai
end end
def apply_rules def apply_rules
# Special case: relative URLs beginning with `/uploads/` refer to
# user-uploaded files and will be handled elsewhere.
return @uri.to_s if @uri.relative? && @uri.path.starts_with?('/uploads/')
apply_file_link_rules! apply_file_link_rules!
apply_hierarchical_link_rules! apply_hierarchical_link_rules!
apply_relative_link_rules! apply_relative_link_rules!
......
...@@ -2,6 +2,9 @@ module Gitlab ...@@ -2,6 +2,9 @@ module Gitlab
module Ci module Ci
module Status module Status
module Build module Build
##
# Extended status for playable manual actions.
#
class Action < Status::Extended class Action < Status::Extended
def label def label
if has_action? if has_action?
...@@ -12,7 +15,7 @@ module Gitlab ...@@ -12,7 +15,7 @@ module Gitlab
end end
def self.matches?(build, user) def self.matches?(build, user)
build.action? build.playable?
end end
end end
end end
......
...@@ -621,37 +621,6 @@ module Gitlab ...@@ -621,37 +621,6 @@ module Gitlab
end end
end end
# Returns branch names collection that contains the special commit(SHA1
# or name)
#
# Ex.
# repo.branch_names_contains('master')
#
def branch_names_contains(commit)
branches_contains(commit).map { |c| c.name }
end
# Returns branch collection that contains the special commit(SHA1 or name)
#
# Ex.
# repo.branch_names_contains('master')
#
def branches_contains(commit)
commit_obj = rugged.rev_parse(commit)
parent = commit_obj.parents.first unless commit_obj.parents.empty?
walker = Rugged::Walker.new(rugged)
rugged.branches.select do |branch|
walker.push(branch.target_id)
walker.hide(parent) if parent
result = walker.any? { |c| c.oid == commit_obj.oid }
walker.reset
result
end
end
# Get refs hash which key is SHA1 # Get refs hash which key is SHA1
# and value is a Rugged::Reference # and value is a Rugged::Reference
def refs_hash def refs_hash
......
...@@ -95,7 +95,7 @@ module Gitlab ...@@ -95,7 +95,7 @@ module Gitlab
object_output.map do |output_line| object_output.map do |output_line|
sha, path = output_line.split(' ', 2) sha, path = output_line.split(' ', 2)
next if require_path && path.blank? next if require_path && path.to_s.empty?
sha sha
end.reject(&:nil?) end.reject(&:nil?)
......
...@@ -6,6 +6,7 @@ module Gitlab ...@@ -6,6 +6,7 @@ module Gitlab
EXPIRY_TIME = 5.minutes EXPIRY_TIME = 5.minutes
def self.enabled?(user = nil) def self.enabled?(user = nil)
return true if Rails.env.development?
return false unless user && allowed_group_id return false unless user && allowed_group_id
allowed_user_ids.include?(user.id) allowed_user_ids.include?(user.id)
......
...@@ -3,9 +3,9 @@ module QA ...@@ -3,9 +3,9 @@ module QA
module Project module Project
module Settings module Settings
module Common module Common
def expand(selector) def expand(element_name)
page.within('#content-body') do page.within('#content-body') do
find(selector).click click_element(element_name)
yield yield
end end
......
...@@ -3,12 +3,19 @@ module QA ...@@ -3,12 +3,19 @@ module QA
module Project module Project
module Settings module Settings
class DeployKeys < Page::Base class DeployKeys < Page::Base
## view 'app/views/projects/deploy_keys/_form.html.haml' do
# TODO, define all selectors required by this page object element :deploy_key_title, 'text_field :title'
# element :deploy_key_key, 'text_area :key'
# See gitlab-org/gitlab-qa#154 end
#
view 'app/views/projects/deploy_keys/edit.html.haml' view 'app/assets/javascripts/deploy_keys/components/app.vue' do
element :deploy_keys_section, /class=".*deploy\-keys.*"/
end
view 'app/assets/javascripts/deploy_keys/components/key.vue' do
element :key_title, /class=".*title.*"/
element :key_title_field, '{{ deployKey.title }}'
end
def fill_key_title(title) def fill_key_title(title)
fill_in 'deploy_key_title', with: title fill_in 'deploy_key_title', with: title
......
...@@ -5,15 +5,12 @@ module QA ...@@ -5,15 +5,12 @@ module QA
class Repository < Page::Base class Repository < Page::Base
include Common include Common
## view 'app/views/projects/deploy_keys/_index.html.haml' do
# TODO, define all selectors required by this page object element :expand_deploy_keys
# end
# See gitlab-org/gitlab-qa#154
#
view 'app/views/projects/settings/repository/show.html.haml'
def expand_deploy_keys(&block) def expand_deploy_keys(&block)
expand('.qa-expand-deploy-keys') do expand(:expand_deploy_keys) do
DeployKeys.perform(&block) DeployKeys.perform(&block)
end end
end end
......
require 'rails_helper' require 'rails_helper'
describe 'User can display performance bar', :js do describe 'User can display performance bar', :js do
shared_examples 'performance bar is disabled' do shared_examples 'performance bar cannot be displayed' do
it 'does not show the performance bar by default' do it 'does not show the performance bar by default' do
expect(page).not_to have_css('#peek') expect(page).not_to have_css('#peek')
end end
...@@ -17,7 +17,7 @@ describe 'User can display performance bar', :js do ...@@ -17,7 +17,7 @@ describe 'User can display performance bar', :js do
end end
end end
shared_examples 'performance bar is enabled' do shared_examples 'performance bar can be displayed' do
it 'does not show the performance bar by default' do it 'does not show the performance bar by default' do
expect(page).not_to have_css('#peek') expect(page).not_to have_css('#peek')
end end
...@@ -33,6 +33,18 @@ describe 'User can display performance bar', :js do ...@@ -33,6 +33,18 @@ describe 'User can display performance bar', :js do
end end
end end
shared_examples 'performance bar is enabled by default in development' do
before do
allow(Rails.env).to receive(:development?).and_return(true)
end
it 'shows the performance bar by default' do
refresh # Because we're stubbing Rails.env after the 1st visit to root_path
expect(page).to have_css('#peek')
end
end
let(:group) { create(:group) } let(:group) { create(:group) }
context 'when user is logged-out' do context 'when user is logged-out' do
...@@ -45,7 +57,7 @@ describe 'User can display performance bar', :js do ...@@ -45,7 +57,7 @@ describe 'User can display performance bar', :js do
stub_application_setting(performance_bar_allowed_group_id: nil) stub_application_setting(performance_bar_allowed_group_id: nil)
end end
it_behaves_like 'performance bar is disabled' it_behaves_like 'performance bar cannot be displayed'
end end
context 'when the performance_bar feature is enabled' do context 'when the performance_bar feature is enabled' do
...@@ -53,7 +65,7 @@ describe 'User can display performance bar', :js do ...@@ -53,7 +65,7 @@ describe 'User can display performance bar', :js do
stub_application_setting(performance_bar_allowed_group_id: group.id) stub_application_setting(performance_bar_allowed_group_id: group.id)
end end
it_behaves_like 'performance bar is disabled' it_behaves_like 'performance bar cannot be displayed'
end end
end end
...@@ -72,7 +84,8 @@ describe 'User can display performance bar', :js do ...@@ -72,7 +84,8 @@ describe 'User can display performance bar', :js do
stub_application_setting(performance_bar_allowed_group_id: nil) stub_application_setting(performance_bar_allowed_group_id: nil)
end end
it_behaves_like 'performance bar is disabled' it_behaves_like 'performance bar cannot be displayed'
it_behaves_like 'performance bar is enabled by default in development'
end end
context 'when the performance_bar feature is enabled' do context 'when the performance_bar feature is enabled' do
...@@ -80,7 +93,8 @@ describe 'User can display performance bar', :js do ...@@ -80,7 +93,8 @@ describe 'User can display performance bar', :js do
stub_application_setting(performance_bar_allowed_group_id: group.id) stub_application_setting(performance_bar_allowed_group_id: group.id)
end end
it_behaves_like 'performance bar is enabled' it_behaves_like 'performance bar is enabled by default in development'
it_behaves_like 'performance bar can be displayed'
end end
end end
end end
...@@ -52,11 +52,6 @@ describe('Job', () => { ...@@ -52,11 +52,6 @@ describe('Job', () => {
expect($('.build-job[data-stage="test"]').is(':visible')).toBe(false); expect($('.build-job[data-stage="test"]').is(':visible')).toBe(false);
expect($('.build-job[data-stage="deploy"]').is(':visible')).toBe(false); expect($('.build-job[data-stage="deploy"]').is(':visible')).toBe(false);
}); });
it('displays the remove date correctly', () => {
const removeDateElement = document.querySelector('.js-artifacts-remove');
expect(removeDateElement.innerText.trim()).toBe('1 year remaining');
});
}); });
describe('running build', () => { describe('running build', () => {
......
...@@ -13,7 +13,7 @@ describe('Pipelines Async Button', () => { ...@@ -13,7 +13,7 @@ describe('Pipelines Async Button', () => {
propsData: { propsData: {
endpoint: '/foo', endpoint: '/foo',
title: 'Foo', title: 'Foo',
icon: 'fa fa-foo', icon: 'repeat',
cssClass: 'bar', cssClass: 'bar',
}, },
}).$mount(); }).$mount();
...@@ -23,8 +23,8 @@ describe('Pipelines Async Button', () => { ...@@ -23,8 +23,8 @@ describe('Pipelines Async Button', () => {
expect(component.$el.tagName).toEqual('BUTTON'); expect(component.$el.tagName).toEqual('BUTTON');
}); });
it('should render the provided icon', () => { it('should render svg icon', () => {
expect(component.$el.querySelector('i').getAttribute('class')).toContain('fa fa-foo'); expect(component.$el.querySelector('svg')).not.toBeNull();
}); });
it('should render the provided title', () => { it('should render the provided title', () => {
......
...@@ -404,7 +404,7 @@ describe('MRWidgetReadyToMerge', () => { ...@@ -404,7 +404,7 @@ describe('MRWidgetReadyToMerge', () => {
setTimeout(() => { setTimeout(() => {
const statusBox = document.querySelector('.status-box'); const statusBox = document.querySelector('.status-box');
expect(statusBox.classList.contains('status-box-merged')).toBeTruthy(); expect(statusBox.classList.contains('status-box-mr-merged')).toBeTruthy();
expect(statusBox.textContent).toContain('Merged'); expect(statusBox.textContent).toContain('Merged');
done(); done();
......
...@@ -194,6 +194,12 @@ describe Backup::Manager do ...@@ -194,6 +194,12 @@ describe Backup::Manager do
) )
end end
it 'prints the list of available backups' do
expect { subject.unpack }.to raise_error SystemExit
expect(progress).to have_received(:puts)
.with(a_string_matching('1451606400_2016_01_01_1.2.3\n 1451520000_2015_12_31'))
end
it 'fails the operation and prints an error' do it 'fails the operation and prints an error' do
expect { subject.unpack }.to raise_error SystemExit expect { subject.unpack }.to raise_error SystemExit
expect(progress).to have_received(:puts) expect(progress).to have_received(:puts)
......
...@@ -10,15 +10,23 @@ describe Banzai::Filter::WikiLinkFilter do ...@@ -10,15 +10,23 @@ describe Banzai::Filter::WikiLinkFilter do
it "doesn't rewrite absolute links" do it "doesn't rewrite absolute links" do
filtered_link = filter("<a href='http://example.com:8000/'>Link</a>", project_wiki: wiki).children[0] filtered_link = filter("<a href='http://example.com:8000/'>Link</a>", project_wiki: wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('http://example.com:8000/') expect(filtered_link.attribute('href').value).to eq('http://example.com:8000/')
end end
it "doesn't rewrite links to project uploads" do
filtered_link = filter("<a href='/uploads/a.test'>Link</a>", project_wiki: wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('/uploads/a.test')
end
describe "invalid links" do describe "invalid links" do
invalid_links = ["http://:8080", "http://", "http://:8080/path"] invalid_links = ["http://:8080", "http://", "http://:8080/path"]
invalid_links.each do |invalid_link| invalid_links.each do |invalid_link|
it "doesn't rewrite invalid invalid_links like #{invalid_link}" do it "doesn't rewrite invalid invalid_links like #{invalid_link}" do
filtered_link = filter("<a href='#{invalid_link}'>Link</a>", project_wiki: wiki).children[0] filtered_link = filter("<a href='#{invalid_link}'>Link</a>", project_wiki: wiki).children[0]
expect(filtered_link.attribute('href').value).to eq(invalid_link) expect(filtered_link.attribute('href').value).to eq(invalid_link)
end end
end end
......
...@@ -37,16 +37,16 @@ describe Gitlab::Ci::Status::Build::Action do ...@@ -37,16 +37,16 @@ describe Gitlab::Ci::Status::Build::Action do
describe '.matches?' do describe '.matches?' do
subject { described_class.matches?(build, user) } subject { described_class.matches?(build, user) }
context 'when build is an action' do context 'when build is playable action' do
let(:build) { create(:ci_build, :manual) } let(:build) { create(:ci_build, :playable) }
it 'is a correct match' do it 'is a correct match' do
expect(subject).to be true expect(subject).to be true
end end
end end
context 'when build is not manual' do context 'when build is not playable action' do
let(:build) { create(:ci_build) } let(:build) { create(:ci_build, :non_playable) }
it 'does not match' do it 'does not match' do
expect(subject).to be false expect(subject).to be false
......
...@@ -1104,14 +1104,6 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -1104,14 +1104,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
end end
end end
describe "branch_names_contains" do
subject { repository.branch_names_contains(SeedRepo::LastCommit::ID) }
it { is_expected.to include('master') }
it { is_expected.not_to include('feature') }
it { is_expected.not_to include('fix') }
end
describe '#autocrlf' do describe '#autocrlf' do
before(:all) do before(:all) do
@repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
......
...@@ -39,7 +39,7 @@ describe Gitlab::Git::RevList do ...@@ -39,7 +39,7 @@ describe Gitlab::Git::RevList do
] ]
expect(rev_list).to receive(:popen).with(*params) do |*_, lazy_block:| expect(rev_list).to receive(:popen).with(*params) do |*_, lazy_block:|
lazy_block.call(output.split("\n").lazy) lazy_block.call(output.lines.lazy.map(&:chomp))
end end
end end
...@@ -64,6 +64,15 @@ describe Gitlab::Git::RevList do ...@@ -64,6 +64,15 @@ describe Gitlab::Git::RevList do
expect(rev_list.new_objects(require_path: true)).to eq(%w[sha2]) expect(rev_list.new_objects(require_path: true)).to eq(%w[sha2])
end end
it 'can handle non utf-8 paths' do
non_utf_char = [0x89].pack("c*").force_encoding("UTF-8")
stub_lazy_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha2 πå†h/†ø/ƒîlé#{non_utf_char}\nsha1")
rev_list.new_objects(require_path: true) do |object_ids|
expect(object_ids.force).to eq(%w[sha2])
end
end
it 'can yield a lazy enumerator' do it 'can yield a lazy enumerator' do
stub_lazy_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2") stub_lazy_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2")
......
...@@ -63,12 +63,14 @@ describe PushEvent do ...@@ -63,12 +63,14 @@ describe PushEvent do
let(:event2) { create(:push_event, project: project) } let(:event2) { create(:push_event, project: project) }
let(:event3) { create(:push_event, project: project) } let(:event3) { create(:push_event, project: project) }
let(:event4) { create(:push_event, project: project) } let(:event4) { create(:push_event, project: project) }
let(:event5) { create(:push_event, project: project) }
before do before do
create(:push_event_payload, event: event1, ref: 'foo', action: :created) create(:push_event_payload, event: event1, ref: 'foo', action: :created)
create(:push_event_payload, event: event2, ref: 'bar', action: :created) create(:push_event_payload, event: event2, ref: 'bar', action: :created)
create(:push_event_payload, event: event3, ref: 'baz', action: :removed) create(:push_event_payload, event: event3, ref: 'qux', action: :created)
create(:push_event_payload, event: event4, ref: 'baz', ref_type: :tag) create(:push_event_payload, event: event4, ref: 'baz', action: :removed)
create(:push_event_payload, event: event5, ref: 'baz', ref_type: :tag)
project.repository.create_branch('bar', 'master') project.repository.create_branch('bar', 'master')
...@@ -78,6 +80,16 @@ describe PushEvent do ...@@ -78,6 +80,16 @@ describe PushEvent do
target_project: project, target_project: project,
source_branch: 'bar' source_branch: 'bar'
) )
project.repository.create_branch('qux', 'master')
create(
:merge_request,
:closed,
source_project: project,
target_project: project,
source_branch: 'qux'
)
end end
let(:relation) { described_class.without_existing_merge_requests } let(:relation) { described_class.without_existing_merge_requests }
...@@ -86,16 +98,20 @@ describe PushEvent do ...@@ -86,16 +98,20 @@ describe PushEvent do
expect(relation).to include(event1) expect(relation).to include(event1)
end end
it 'does not include events that have a corresponding merge request' do it 'does not include events that have a corresponding open merge request' do
expect(relation).not_to include(event2) expect(relation).not_to include(event2)
end end
it 'includes events that has corresponding closed/merged merge requests' do
expect(relation).to include(event3)
end
it 'does not include events for removed refs' do it 'does not include events for removed refs' do
expect(relation).not_to include(event3) expect(relation).not_to include(event4)
end end
it 'does not include events for pushing to tags' do it 'does not include events for pushing to tags' do
expect(relation).not_to include(event4) expect(relation).not_to include(event5)
end end
end end
......
...@@ -3,24 +3,65 @@ require 'spec_helper' ...@@ -3,24 +3,65 @@ require 'spec_helper'
describe API::Deployments do describe API::Deployments do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:non_member) { create(:user) } let(:non_member) { create(:user) }
let(:project) { deployment.environment.project }
let!(:deployment) { create(:deployment) }
before do before do
project.add_master(user) project.add_master(user)
end end
describe 'GET /projects/:id/deployments' do describe 'GET /projects/:id/deployments' do
let(:project) { create(:project) }
let!(:deployment_1) { create(:deployment, project: project, iid: 11, ref: 'master', created_at: Time.now) }
let!(:deployment_2) { create(:deployment, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago) }
let!(:deployment_3) { create(:deployment, project: project, iid: 8, ref: 'feature', created_at: 2.days.ago) }
context 'as member of the project' do context 'as member of the project' do
it 'returns projects deployments' do it 'returns projects deployments sorted by id asc' do
get api("/projects/#{project.id}/deployments", user) get api("/projects/#{project.id}/deployments", user)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.size).to eq(1) expect(json_response.size).to eq(3)
expect(json_response.first['iid']).to eq(deployment.iid) expect(json_response.first['iid']).to eq(deployment_1.iid)
expect(json_response.first['sha']).to match /\A\h{40}\z/ expect(json_response.first['sha']).to match /\A\h{40}\z/
expect(json_response.second['iid']).to eq(deployment_2.iid)
expect(json_response.last['iid']).to eq(deployment_3.iid)
end
describe 'ordering' do
using RSpec::Parameterized::TableSyntax
let(:order_by) { nil }
let(:sort) { nil }
subject { get api("/projects/#{project.id}/deployments?order_by=#{order_by}&sort=#{sort}", user) }
def expect_deployments(ordered_deployments)
json_response.each_with_index do |deployment_json, index|
expect(deployment_json['id']).to eq(public_send(ordered_deployments[index]).id)
end
end
before do
subject
end
where(:order_by, :sort, :ordered_deployments) do
'created_at' | 'asc' | [:deployment_3, :deployment_2, :deployment_1]
'created_at' | 'desc' | [:deployment_1, :deployment_2, :deployment_3]
'id' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
'id' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
'iid' | 'asc' | [:deployment_3, :deployment_1, :deployment_2]
'iid' | 'desc' | [:deployment_2, :deployment_1, :deployment_3]
'ref' | 'asc' | [:deployment_2, :deployment_3, :deployment_1]
'ref' | 'desc' | [:deployment_1, :deployment_2, :deployment_3]
end
with_them do
it 'returns the deployments ordered' do
expect_deployments(ordered_deployments)
end
end
end end
end end
...@@ -34,6 +75,9 @@ describe API::Deployments do ...@@ -34,6 +75,9 @@ describe API::Deployments do
end end
describe 'GET /projects/:id/deployments/:deployment_id' do describe 'GET /projects/:id/deployments/:deployment_id' do
let(:project) { deployment.environment.project }
let!(:deployment) { create(:deployment) }
context 'as a member of the project' do context 'as a member of the project' do
it 'returns the projects deployment' do it 'returns the projects deployment' do
get api("/projects/#{project.id}/deployments/#{deployment.id}", user) get api("/projects/#{project.id}/deployments/#{deployment.id}", user)
......
...@@ -30,8 +30,11 @@ describe API::Jobs do ...@@ -30,8 +30,11 @@ describe API::Jobs do
let(:query) { Hash.new } let(:query) { Hash.new }
before do |example| before do |example|
<<<<<<< HEAD
job job
=======
>>>>>>> upstream/master
unless example.metadata[:skip_before_request] unless example.metadata[:skip_before_request]
get api("/projects/#{project.id}/jobs", api_user), query get api("/projects/#{project.id}/jobs", api_user), query
end end
......
...@@ -14,7 +14,10 @@ describe API::V3::Builds do ...@@ -14,7 +14,10 @@ describe API::V3::Builds do
let(:query) { '' } let(:query) { '' }
before do |example| before do |example|
<<<<<<< HEAD
build build
=======
>>>>>>> upstream/master
create(:ci_build, :skipped, pipeline: pipeline) create(:ci_build, :skipped, pipeline: pipeline)
unless example.metadata[:skip_before_request] unless example.metadata[:skip_before_request]
......
...@@ -85,6 +85,19 @@ describe Labels::PromoteService do ...@@ -85,6 +85,19 @@ describe Labels::PromoteService do
change(project_3.labels, :count).by(-1) change(project_3.labels, :count).by(-1)
end end
it 'keeps users\' subscriptions' do
user2 = create(:user)
project_label_1_1.subscriptions.create(user: user, subscribed: true)
project_label_2_1.subscriptions.create(user: user, subscribed: true)
project_label_3_2.subscriptions.create(user: user, subscribed: true)
project_label_2_1.subscriptions.create(user: user2, subscribed: true)
expect { service.execute(project_label_1_1) }.to change { Subscription.count }.from(4).to(3)
expect(new_label.subscribed?(user)).to be_truthy
expect(new_label.subscribed?(user2)).to be_truthy
end
it 'recreates priorities' do it 'recreates priorities' do
service.execute(project_label_1_1) service.execute(project_label_1_1)
......
...@@ -112,5 +112,24 @@ describe MergeRequests::CreateFromIssueService do ...@@ -112,5 +112,24 @@ describe MergeRequests::CreateFromIssueService do
expect(result[:merge_request].assignee).to eq(user) expect(result[:merge_request].assignee).to eq(user)
end end
context 'when ref branch is set' do
subject { described_class.new(project, user, issue_iid: issue.iid, ref: 'feature').execute }
it 'sets the merge request source branch to the new issue branch' do
expect(subject[:merge_request].source_branch).to eq(issue.to_branch_name)
end
it 'sets the merge request target branch to the ref branch' do
expect(subject[:merge_request].target_branch).to eq('feature')
end
context 'when ref branch does not exist' do
it 'does not create a merge request' do
expect { described_class.new(project, user, issue_iid: issue.iid, ref: 'nobr').execute }
.not_to change { project.merge_requests.count }
end
end
end
end end
end 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