summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock7
-rw-r--r--app/assets/javascripts/application.js9
-rw-r--r--app/assets/javascripts/commits.js8
-rw-r--r--app/assets/javascripts/diff.js.es66
-rw-r--r--app/assets/javascripts/droplab/droplab_ajax.js41
-rw-r--r--app/assets/javascripts/droplab/droplab_ajax_filter.js61
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_utils.js.es610
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js.es63
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es615
-rw-r--r--app/assets/javascripts/issuable_context.js9
-rw-r--r--app/assets/javascripts/lib/ace.js3
-rw-r--r--app/assets/javascripts/lib/ace/ace_config_paths.js.erb25
-rw-r--r--app/assets/javascripts/line_highlighter.js5
-rw-r--r--app/assets/javascripts/profile/profile.js.es61
-rw-r--r--app/assets/javascripts/users/calendar.js2
-rw-r--r--app/assets/stylesheets/framework/avatar.scss2
-rw-r--r--app/assets/stylesheets/framework/calendar.scss1
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss3
-rw-r--r--app/assets/stylesheets/framework/filters.scss9
-rw-r--r--app/assets/stylesheets/framework/header.scss2
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/pages/issuable.scss4
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss26
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss4
-rw-r--r--app/assets/stylesheets/pages/projects.scss4
-rw-r--r--app/controllers/autocomplete_controller.rb5
-rw-r--r--app/controllers/explore/projects_controller.rb1
-rw-r--r--app/controllers/projects/builds_controller.rb2
-rw-r--r--app/controllers/projects/refs_controller.rb6
-rw-r--r--app/models/application_setting.rb95
-rw-r--r--app/models/repository.rb13
-rw-r--r--app/presenters/README.md6
-rw-r--r--app/views/ci/status/_badge.html.haml3
-rw-r--r--app/views/projects/builds/_header.html.haml4
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/projects/issues/index.html.haml4
-rw-r--r--app/views/projects/merge_requests/_show.html.haml3
-rw-r--r--app/views/projects/services/_form.html.haml2
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml4
-rw-r--r--changelogs/unreleased/26844-new-search-bar-performs-a-new-request-for-each-tag.yml4
-rw-r--r--changelogs/unreleased/26947-build-status-self-link.yml4
-rw-r--r--changelogs/unreleased/27044-fix-explore-sorting-on-trending.yml4
-rw-r--r--changelogs/unreleased/27248-filtered-search-does-not-allow-filtering-labels-with-multiple-words.yml4
-rw-r--r--changelogs/unreleased/27259-label-for-references-the-wrong-associated-text-input.yml4
-rw-r--r--changelogs/unreleased/27277-small-mini-pipeline-graph-glitch-upon-hover.yml4
-rw-r--r--changelogs/unreleased/contribution-calendar-scroll.yml4
-rw-r--r--changelogs/unreleased/fix-cancel-integration-settings.yml4
-rw-r--r--changelogs/unreleased/fix-search-bar-search-param.yml4
-rw-r--r--changelogs/unreleased/get-rid-of-water-from-notification_service_spec-to-make-it-DRY.yml4
-rw-r--r--changelogs/unreleased/hardcode-title-system-note.yml4
-rw-r--r--changelogs/unreleased/improve-ci-example-php-doc.yml4
-rw-r--r--changelogs/unreleased/issuable-sidebar-bug.yml4
-rw-r--r--changelogs/unreleased/issue_27211.yml4
-rw-r--r--changelogs/unreleased/mr-tabs-container-offset.yml4
-rw-r--r--changelogs/unreleased/relative-url-assets.yml4
-rw-r--r--changelogs/unreleased/revert-filter-assigned-to-me.yml4
-rw-r--r--changelogs/unreleased/sh-fix-annotated-tags-pointing-to-blob.yml4
-rw-r--r--config/initializers/1_settings.rb8
-rw-r--r--config/initializers/5_backend.rb6
-rw-r--r--config/initializers/rspec_profiling.rb14
-rw-r--r--doc/README.md3
-rw-r--r--doc/administration/raketasks/maintenance.md4
-rw-r--r--doc/administration/repository_checks.md10
-rw-r--r--doc/administration/repository_storage_paths.md102
-rw-r--r--doc/administration/repository_storages.md101
-rw-r--r--doc/api/commits.md2
-rw-r--r--doc/ci/examples/README.md6
-rw-r--r--doc/ci/examples/deployment/composer-npm-deploy.md156
-rw-r--r--doc/ci/examples/php.md6
-rw-r--r--doc/ci/yaml/README.md2
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/gemfile.md14
-rw-r--r--doc/development/performance.md35
-rw-r--r--doc/development/ux_guide/components.md2
-rw-r--r--doc/development/ux_guide/copy.md10
-rw-r--r--doc/gitlab-basics/add-image.md50
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/install/relative_url.md8
-rw-r--r--doc/update/patch_versions.md2
-rw-r--r--doc/user/profile/account/two_factor_authentication.md110
-rw-r--r--lib/gitlab/ci/trace_reader.rb1
-rw-r--r--lib/gitlab/current_settings.rb4
-rw-r--r--lib/gitlab/shell.rb (renamed from lib/gitlab/backend/shell.rb)0
-rw-r--r--lib/gitlab/shell_adapter.rb (renamed from lib/gitlab/backend/shell_adapter.rb)0
-rw-r--r--lib/gitlab/upgrader.rb2
-rw-r--r--lib/gitlab/view/presenter/base.rb2
-rw-r--r--lib/gitlab/view/presenter/delegated.rb4
-rwxr-xr-xlib/support/deploy/deploy.sh4
-rw-r--r--lib/tasks/gitlab/assets.rake47
-rw-r--r--spec/controllers/explore/projects_controller_spec.rb27
-rw-r--r--spec/factories/trending_project.rb6
-rw-r--r--spec/features/issues/filtered_search/dropdown_assignee_spec.rb34
-rw-r--r--spec/features/issues/filtered_search/dropdown_author_spec.rb18
-rw-r--r--spec/features/issues/filtered_search/dropdown_label_spec.rb17
-rw-r--r--spec/features/issues/filtered_search/dropdown_milestone_spec.rb17
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb2
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb25
-rw-r--r--spec/features/projects/project_settings_spec.rb4
-rw-r--r--spec/javascripts/commits_spec.js.es650
-rw-r--r--spec/javascripts/filtered_search/dropdown_utils_spec.js.es6156
-rw-r--r--spec/javascripts/filtered_search/filtered_search_manager_spec.js.es668
-rw-r--r--spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es66
-rw-r--r--spec/lib/gitlab/ci/trace_reader_spec.rb16
-rw-r--r--spec/lib/gitlab/view/presenter/delegated_spec.rb14
-rw-r--r--spec/lib/gitlab/view/presenter/factory_spec.rb7
-rw-r--r--spec/lib/gitlab/view/presenter/simple_spec.rb15
-rw-r--r--spec/models/ability_spec.rb10
-rw-r--r--spec/models/ci/build_spec.rb2
-rw-r--r--spec/models/ci/pipeline_spec.rb8
-rw-r--r--spec/models/ci/runner_spec.rb7
-rw-r--r--spec/models/commit_range_spec.rb2
-rw-r--r--spec/models/commit_spec.rb14
-rw-r--r--spec/models/commit_status_spec.rb2
-rw-r--r--spec/models/compare_spec.rb2
-rw-r--r--spec/models/concerns/issuable_spec.rb6
-rw-r--r--spec/models/concerns/mentionable_spec.rb8
-rw-r--r--spec/models/concerns/milestoneish_spec.rb2
-rw-r--r--spec/models/concerns/project_features_compatibility_spec.rb2
-rw-r--r--spec/models/cycle_analytics/code_spec.rb2
-rw-r--r--spec/models/cycle_analytics/issue_spec.rb2
-rw-r--r--spec/models/cycle_analytics/plan_spec.rb2
-rw-r--r--spec/models/cycle_analytics/production_spec.rb2
-rw-r--r--spec/models/cycle_analytics/review_spec.rb2
-rw-r--r--spec/models/cycle_analytics/staging_spec.rb3
-rw-r--r--spec/models/cycle_analytics/test_spec.rb2
-rw-r--r--spec/models/deploy_keys_project_spec.rb4
-rw-r--r--spec/models/deployment_spec.rb2
-rw-r--r--spec/models/diff_note_spec.rb4
-rw-r--r--spec/models/environment_spec.rb4
-rw-r--r--spec/models/event_spec.rb6
-rw-r--r--spec/models/forked_project_link_spec.rb4
-rw-r--r--spec/models/global_milestone_spec.rb6
-rw-r--r--spec/models/group_milestone_spec.rb2
-rw-r--r--spec/models/guest_spec.rb6
-rw-r--r--spec/models/hooks/system_hook_spec.rb2
-rw-r--r--spec/models/hooks/web_hook_spec.rb2
-rw-r--r--spec/models/issue/metrics_spec.rb2
-rw-r--r--spec/models/issue_collection_spec.rb2
-rw-r--r--spec/models/issue_spec.rb18
-rw-r--r--spec/models/member_spec.rb2
-rw-r--r--spec/models/members/project_member_spec.rb8
-rw-r--r--spec/models/merge_request/metrics_spec.rb4
-rw-r--r--spec/models/milestone_spec.rb6
-rw-r--r--spec/models/namespace_spec.rb4
-rw-r--r--spec/models/network/graph_spec.rb2
-rw-r--r--spec/models/note_spec.rb12
-rw-r--r--spec/models/project_feature_spec.rb4
-rw-r--r--spec/models/project_group_link_spec.rb2
-rw-r--r--spec/models/project_label_spec.rb2
-rw-r--r--spec/models/project_services/asana_service_spec.rb2
-rw-r--r--spec/models/project_services/assembla_service_spec.rb2
-rw-r--r--spec/models/project_services/campfire_service_spec.rb2
-rw-r--r--spec/models/project_services/drone_ci_service_spec.rb2
-rw-r--r--spec/models/project_services/external_wiki_service_spec.rb2
-rw-r--r--spec/models/project_services/flowdock_service_spec.rb2
-rw-r--r--spec/models/project_services/gemnasium_service_spec.rb2
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb6
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb6
-rw-r--r--spec/models/project_services/irker_service_spec.rb2
-rw-r--r--spec/models/project_services/jira_service_spec.rb12
-rw-r--r--spec/models/project_services/pipeline_email_service_spec.rb2
-rw-r--r--spec/models/project_services/pushover_service_spec.rb2
-rw-r--r--spec/models/project_team_spec.rb10
-rw-r--r--spec/models/repository_spec.rb26
-rw-r--r--spec/models/service_spec.rb16
-rw-r--r--spec/models/snippet_spec.rb6
-rw-r--r--spec/models/todo_spec.rb8
-rw-r--r--spec/models/tree_spec.rb2
-rw-r--r--spec/models/user_spec.rb6
-rw-r--r--spec/requests/api/branches_spec.rb2
-rw-r--r--spec/requests/api/builds_spec.rb2
-rw-r--r--spec/requests/api/commit_statuses_spec.rb2
-rw-r--r--spec/requests/api/commits_spec.rb2
-rw-r--r--spec/requests/api/files_spec.rb4
-rw-r--r--spec/requests/api/fork_spec.rb21
-rw-r--r--spec/requests/api/internal_spec.rb2
-rw-r--r--spec/requests/api/merge_requests_spec.rb16
-rw-r--r--spec/requests/api/pipelines_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb1
-rw-r--r--spec/requests/api/repositories_spec.rb14
-rw-r--r--spec/requests/api/tags_spec.rb6
-rw-r--r--spec/requests/api/triggers_spec.rb2
-rw-r--r--spec/requests/ci/api/triggers_spec.rb6
-rw-r--r--spec/requests/git_http_spec.rb2
-rw-r--r--spec/requests/projects/artifacts_controller_spec.rb2
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb2
-rw-r--r--spec/services/notification_service_spec.rb315
-rw-r--r--spec/services/system_note_service_spec.rb4
-rw-r--r--spec/spec_helper.rb4
-rw-r--r--spec/support/cycle_analytics_helpers/test_generation.rb2
-rw-r--r--spec/support/mentionable_shared_examples.rb2
-rw-r--r--spec/support/mobile_helpers.rb13
-rw-r--r--spec/support/slack_mattermost_notifications_shared_examples.rb6
-rw-r--r--spec/views/ci/lints/show.html.haml_spec.rb2
-rw-r--r--spec/views/projects/builds/show.html.haml_spec.rb30
197 files changed, 1622 insertions, 839 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d30deef0096..782a43cbe74 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -107,7 +107,7 @@ setup-test-env:
<<: *dedicated-runner
stage: prepare
script:
- - bundle exec rake assets:precompile 2>/dev/null
+ - bundle exec rake gitlab:assets:compile 2>/dev/null
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
artifacts:
expire_in: 7d
diff --git a/Gemfile b/Gemfile
index dc8f23d07c6..37a7666602f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -280,6 +280,7 @@ group :development, :test do
gem 'rspec-retry', '~> 0.4.5'
gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2'
+ gem 'rspec_profiling'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.7.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 133e47e1ea4..671d7788a86 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -642,6 +642,11 @@ GEM
rspec-retry (0.4.5)
rspec-core
rspec-support (3.5.0)
+ rspec_profiling (0.0.4)
+ activerecord
+ pg
+ rails
+ sqlite3
rubocop (0.46.0)
parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1)
@@ -743,6 +748,7 @@ GEM
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
+ sqlite3 (1.3.11)
stackprof (0.2.10)
state_machines (0.4.0)
state_machines-activemodel (0.4.0)
@@ -965,6 +971,7 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5)
+ rspec_profiling
rubocop (~> 0.46.0)
rubocop-rspec (~> 1.9.1)
ruby-fogbugz (~> 0.2.1)
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index f0615481ed2..4849aab50f4 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -84,7 +84,6 @@
var $sidebarGutterToggle = $('.js-sidebar-toggle');
var $flash = $('.flash-container');
var bootstrapBreakpoint = bp.getBreakpointSize();
- var checkInitialSidebarSize;
var fitSidebarForSize;
// Set the default path for all cookies to GitLab's root directory
@@ -246,19 +245,11 @@
return $document.trigger('breakpoint:change', [bootstrapBreakpoint]);
}
};
- checkInitialSidebarSize = function () {
- bootstrapBreakpoint = bp.getBreakpointSize();
- if (bootstrapBreakpoint === 'xs' || 'sm') {
- return $document.trigger('breakpoint:change', [bootstrapBreakpoint]);
- }
- };
$window.off('resize.app').on('resize.app', function () {
return fitSidebarForSize();
});
gl.awardsHandler = new AwardsHandler();
- checkInitialSidebarSize();
new Aside();
-
// bind sidebar events
new gl.Sidebar();
});
diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js
index cabeae74ae3..c6fdfbcaa10 100644
--- a/app/assets/javascripts/commits.js
+++ b/app/assets/javascripts/commits.js
@@ -3,7 +3,7 @@
(function() {
this.CommitsList = (function() {
- function CommitsList() {}
+ var CommitsList = {};
CommitsList.timer = null;
@@ -20,6 +20,7 @@
});
this.content = $("#commits-list");
this.searchField = $("#commits-search");
+ this.lastSearch = this.searchField.val();
return this.initSearch();
};
@@ -37,6 +38,7 @@
var commitsUrl, form, search;
form = $(".commits-search-form");
search = CommitsList.searchField.val();
+ if (search === CommitsList.lastSearch) return;
commitsUrl = form.attr("action") + '?' + form.serialize();
CommitsList.content.fadeTo('fast', 0.5);
return $.ajax({
@@ -47,12 +49,16 @@
return CommitsList.content.fadeTo('fast', 1.0);
},
success: function(data) {
+ CommitsList.lastSearch = search;
CommitsList.content.html(data.html);
return history.replaceState({
page: commitsUrl
// Change url so if user reload a page - search results are saved
}, document.title, commitsUrl);
},
+ error: function() {
+ CommitsList.lastSearch = null;
+ },
dataType: "json"
});
};
diff --git a/app/assets/javascripts/diff.js.es6 b/app/assets/javascripts/diff.js.es6
index 5e1a4c948aa..35a029194d0 100644
--- a/app/assets/javascripts/diff.js.es6
+++ b/app/assets/javascripts/diff.js.es6
@@ -1,5 +1,7 @@
/* eslint-disable class-methods-use-this */
+//= require lib/utils/url_utility */
+
(() => {
const UNFOLD_COUNT = 20;
@@ -104,11 +106,11 @@
}
highlighSelectedLine() {
+ const hash = gl.utils.getLocationHash();
const $diffFiles = $('.diff-file');
$diffFiles.find('.hll').removeClass('hll');
- if (window.location.hash !== '') {
- const hash = window.location.hash.replace('#', '');
+ if (hash) {
$diffFiles
.find(`tr#${hash}:not(.match) td, td#${hash}, td[data-line-code="${hash}"]`)
.addClass('hll');
diff --git a/app/assets/javascripts/droplab/droplab_ajax.js b/app/assets/javascripts/droplab/droplab_ajax.js
index f7fed0987a2..c290e1a8355 100644
--- a/app/assets/javascripts/droplab/droplab_ajax.js
+++ b/app/assets/javascripts/droplab/droplab_ajax.js
@@ -9,6 +9,7 @@ require('../window')(function(w){
w.droplabAjax = {
_loadUrlData: function _loadUrlData(url) {
+ var self = this;
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.open('GET', url, true);
@@ -16,6 +17,7 @@ require('../window')(function(w){
if(xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
+ self.cache[url] = data;
return resolve(data);
} else {
return reject([xhr.responseText, xhr.status]);
@@ -26,8 +28,21 @@ require('../window')(function(w){
});
},
+ _loadData: function _loadData(data, config, self) {
+ if (config.loadingTemplate) {
+ var dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
+
+ if (dataLoadingTemplate) {
+ dataLoadingTemplate.outerHTML = self.listTemplate;
+ }
+ }
+
+ self.hook.list[config.method].call(self.hook.list, data);
+ },
+
init: function init(hook) {
var self = this;
+ self.cache = self.cache || {};
var config = hook.config.droplabAjax;
this.hook = hook;
@@ -50,22 +65,16 @@ require('../window')(function(w){
dynamicList.outerHTML = loadingTemplate.outerHTML;
}
- this._loadUrlData(config.endpoint)
- .then(function(d) {
- if (config.loadingTemplate) {
- var dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
-
- if (dataLoadingTemplate) {
- dataLoadingTemplate.outerHTML = self.listTemplate;
- }
- }
-
- if (!self.hook.list.hidden) {
- self.hook.list[config.method].call(self.hook.list, d);
- }
- }).catch(function(e) {
- throw new droplabAjaxException(e.message || e);
- });
+ if (self.cache[config.endpoint]) {
+ self._loadData(self.cache[config.endpoint], config, self);
+ } else {
+ this._loadUrlData(config.endpoint)
+ .then(function(d) {
+ self._loadData(d, config, self);
+ }).catch(function(e) {
+ throw new droplabAjaxException(e.message || e);
+ });
+ }
},
destroy: function() {
diff --git a/app/assets/javascripts/droplab/droplab_ajax_filter.js b/app/assets/javascripts/droplab/droplab_ajax_filter.js
index 86a08d0d01d..b63d73066cb 100644
--- a/app/assets/javascripts/droplab/droplab_ajax_filter.js
+++ b/app/assets/javascripts/droplab/droplab_ajax_filter.js
@@ -72,32 +72,22 @@ require('../window')(function(w){
var params = config.params || {};
params[config.searchKey] = searchValue;
var self = this;
- this._loadUrlData(config.endpoint + this.buildParams(params)).then(function(data) {
- if (config.loadingTemplate && self.hook.list.data === undefined ||
- self.hook.list.data.length === 0) {
- const dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
-
- if (dataLoadingTemplate) {
- dataLoadingTemplate.outerHTML = self.listTemplate;
- }
- }
-
- if (!self.destroyed) {
- var hookListChildren = self.hook.list.list.children;
- var onlyDynamicList = hookListChildren.length === 1 && hookListChildren[0].hasAttribute('data-dynamic');
-
- if (onlyDynamicList && data.length === 0) {
- self.hook.list.hide();
- }
-
- self.hook.list.setData.call(self.hook.list, data);
- }
- self.notLoading();
- self.hook.list.currentIndex = 0;
- });
+ self.cache = self.cache || {};
+ var url = config.endpoint + this.buildParams(params);
+ var urlCachedData = self.cache[url];
+
+ if (urlCachedData) {
+ self._loadData(urlCachedData, config, self);
+ } else {
+ this._loadUrlData(url)
+ .then(function(data) {
+ self._loadData(data, config, self);
+ });
+ }
},
_loadUrlData: function _loadUrlData(url) {
+ var self = this;
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.open('GET', url, true);
@@ -105,6 +95,7 @@ require('../window')(function(w){
if(xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
+ self.cache[url] = data;
return resolve(data);
} else {
return reject([xhr.responseText, xhr.status]);
@@ -115,6 +106,30 @@ require('../window')(function(w){
});
},
+ _loadData: function _loadData(data, config, self) {
+ if (config.loadingTemplate && self.hook.list.data === undefined ||
+ self.hook.list.data.length === 0) {
+ const dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
+
+ if (dataLoadingTemplate) {
+ dataLoadingTemplate.outerHTML = self.listTemplate;
+ }
+ }
+
+ if (!self.destroyed) {
+ var hookListChildren = self.hook.list.list.children;
+ var onlyDynamicList = hookListChildren.length === 1 && hookListChildren[0].hasAttribute('data-dynamic');
+
+ if (onlyDynamicList && data.length === 0) {
+ self.hook.list.hide();
+ }
+
+ self.hook.list.setData.call(self.hook.list, data);
+ }
+ self.notLoading();
+ self.hook.list.currentIndex = 0;
+ },
+
buildParams: function(params) {
if (!params) return '';
var paramsArray = Object.keys(params).map(function(param) {
diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 b/app/assets/javascripts/filtered_search/dropdown_utils.js.es6
index eeab10fba17..de3fa116717 100644
--- a/app/assets/javascripts/filtered_search/dropdown_utils.js.es6
+++ b/app/assets/javascripts/filtered_search/dropdown_utils.js.es6
@@ -28,7 +28,12 @@
if (lastToken !== searchToken) {
const title = updatedItem.title.toLowerCase();
let value = lastToken.value.toLowerCase();
- value = value.replace(/"(.*?)"/g, str => str.slice(1).slice(0, -1));
+
+ // Removes the first character if it is a quotation so that we can search
+ // with multiple words
+ if ((value[0] === '"' || value[0] === '\'') && title.indexOf(' ') !== -1) {
+ value = value.slice(1);
+ }
// Eg. filterSymbol = ~ for labels
const matchWithoutSymbol = lastToken.symbol === filterSymbol && title.indexOf(value) !== -1;
@@ -83,8 +88,9 @@
const selectionStart = input.selectionStart;
let inputValue = input.value;
// Replace all spaces inside quote marks with underscores
+ // (will continue to match entire string until an end quote is found if any)
// This helps with matching the beginning & end of a token:key
- inputValue = inputValue.replace(/("(.*?)"|:\s+)/g, str => str.replace(/\s/g, '_'));
+ inputValue = inputValue.replace(/(('[^']*'{0,1})|("[^"]*"{0,1})|:\s+)/g, str => str.replace(/\s/g, '_'));
// Get the right position for the word selected
// Regex matches first space
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
index 8d62324b79f..029564ffc61 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
@@ -196,7 +196,8 @@
});
if (searchToken) {
- paths.push(`search=${encodeURIComponent(searchToken)}`);
+ const sanitized = searchToken.split(' ').map(t => encodeURIComponent(t)).join('+');
+ paths.push(`search=${sanitized}`);
}
Turbolinks.visit(`?scope=all&utf8=✓&${paths.join('&')}`);
diff --git a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6
index e46373024b6..e6b53cd4b55 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6
+++ b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6
@@ -21,6 +21,15 @@
symbol: '~',
}];
+ const alternativeTokenKeys = [{
+ key: 'label',
+ type: 'string',
+ param: 'name',
+ symbol: '~',
+ }];
+
+ const tokenKeysWithAlternative = tokenKeys.concat(alternativeTokenKeys);
+
const conditions = [{
url: 'assignee_id=0',
tokenKey: 'assignee',
@@ -44,6 +53,10 @@
return tokenKeys;
}
+ static getAlternatives() {
+ return alternativeTokenKeys;
+ }
+
static getConditions() {
return conditions;
}
@@ -57,7 +70,7 @@
}
static searchByKeyParam(keyParam) {
- return tokenKeys.find((tokenKey) => {
+ return tokenKeysWithAlternative.find((tokenKey) => {
let tokenKeyParam = tokenKey.key;
if (tokenKey.param) {
diff --git a/app/assets/javascripts/issuable_context.js b/app/assets/javascripts/issuable_context.js
index 9c53cdee58e..c77fbb6a1c7 100644
--- a/app/assets/javascripts/issuable_context.js
+++ b/app/assets/javascripts/issuable_context.js
@@ -1,5 +1,7 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, max-len */
/* global UsersSelect */
+/* global Cookies */
+/* global bp */
(function() {
this.IssuableContext = (function() {
@@ -37,6 +39,13 @@
}, 0);
}
});
+ window.addEventListener('beforeunload', function() {
+ // collapsed_gutter cookie hides the sidebar
+ var bpBreakpoint = bp.getBreakpointSize();
+ if (bpBreakpoint === 'xs' || bpBreakpoint === 'sm') {
+ Cookies.set('collapsed_gutter', true);
+ }
+ });
$(".right-sidebar").niceScroll();
}
diff --git a/app/assets/javascripts/lib/ace.js b/app/assets/javascripts/lib/ace.js
index 4cdf99cae72..9cdc0309503 100644
--- a/app/assets/javascripts/lib/ace.js
+++ b/app/assets/javascripts/lib/ace.js
@@ -1,2 +1,3 @@
-/*= require ace-rails-ap */
+/*= require ace/ace */
/*= require ace/ext-searchbox */
+/*= require ./ace/ace_config_paths */
diff --git a/app/assets/javascripts/lib/ace/ace_config_paths.js.erb b/app/assets/javascripts/lib/ace/ace_config_paths.js.erb
new file mode 100644
index 00000000000..25e623f0fdc
--- /dev/null
+++ b/app/assets/javascripts/lib/ace/ace_config_paths.js.erb
@@ -0,0 +1,25 @@
+<%
+ace_gem_path = Bundler.rubygems.find_name('ace-rails-ap').first.full_gem_path
+ace_workers = Dir[ace_gem_path + '/vendor/assets/javascripts/ace/worker-*.js'].sort.map do |file|
+ File.basename(file, '.js').sub(/^worker-/, '')
+end
+ace_modes = Dir[ace_gem_path + '/vendor/assets/javascripts/ace/mode-*.js'].sort.map do |file|
+ File.basename(file, '.js').sub(/^mode-/, '')
+end
+%>
+
+(function() {
+ window.gon = window.gon || {};
+ var basePath = (window.gon.relative_url_root || '').replace(/\/$/, '') + '/assets/ace';
+ ace.config.set('basePath', basePath);
+
+ // configure paths for all worker modules
+<% ace_workers.each do |worker| %>
+ ace.config.setModuleUrl('ace/mode/<%= worker %>_worker', basePath + '/worker-<%= worker %>.js');
+<% end %>
+
+ // configure paths for all mode modules
+<% ace_modes.each do |mode| %>
+ ace.config.setModuleUrl('ace/mode/<%= mode %>', basePath + '/mode-<%= mode %>.js');
+<% end %>
+})();
diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js
index 4620715a521..2f147704c22 100644
--- a/app/assets/javascripts/line_highlighter.js
+++ b/app/assets/javascripts/line_highlighter.js
@@ -74,8 +74,9 @@
// If not done this way, the line number anchor will sometimes keep its
// active state even when the event is cancelled, resulting in an ugly border
// around the link and/or a persisted underline text decoration.
- return $('#blob-content-holder').on('click', 'a[data-line-number]', function(event) {
- return event.preventDefault();
+ $('#blob-content-holder').on('click', 'a[data-line-number]', function(event) {
+ event.preventDefault();
+ event.stopPropagation();
});
};
diff --git a/app/assets/javascripts/profile/profile.js.es6 b/app/assets/javascripts/profile/profile.js.es6
index 6dbaae25f2a..5aec9c813fe 100644
--- a/app/assets/javascripts/profile/profile.js.es6
+++ b/app/assets/javascripts/profile/profile.js.es6
@@ -36,6 +36,7 @@
}
onSubmitForm(e) {
+ e.preventDefault();
return this.saveForm();
}
diff --git a/app/assets/javascripts/users/calendar.js b/app/assets/javascripts/users/calendar.js
index 7ffc546ffc1..e7280d643d3 100644
--- a/app/assets/javascripts/users/calendar.js
+++ b/app/assets/javascripts/users/calendar.js
@@ -158,7 +158,7 @@
};
Calendar.prototype.renderMonths = function() {
- return this.svg.append('g').selectAll('text').data(this.months).enter().append('text').attr('x', function(date) {
+ return this.svg.append('g').attr('direction', 'ltr').selectAll('text').data(this.months).enter().append('text').attr('x', function(date) {
return date.x;
}).attr('y', 10).attr('class', 'user-contrib-text').text((function(_this) {
return function(date) {
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index 8392b98f0a7..1d59700543c 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -37,6 +37,8 @@
display: inline-block;
margin-left: 4px;
margin-bottom: 2px;
+ flex-shrink: 0;
+ -webkit-flex-shrink: 0;
&.s16 { margin-right: 4px; }
&.s24 { margin-right: 4px; }
diff --git a/app/assets/stylesheets/framework/calendar.scss b/app/assets/stylesheets/framework/calendar.scss
index ef921a8c6a9..1d2d1bfc0d7 100644
--- a/app/assets/stylesheets/framework/calendar.scss
+++ b/app/assets/stylesheets/framework/calendar.scss
@@ -1,6 +1,7 @@
.calender-block {
padding-left: 0;
padding-right: 0;
+ direction: rtl;
@media (min-width: $screen-sm-min) and (max-width: $screen-md-max) {
overflow-x: scroll;
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 755eddefa42..6bfb9a6d1cb 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -125,7 +125,8 @@
top: 100%;
left: 0;
z-index: 9;
- width: 240px;
+ max-width: 280px;
+ min-width: 240px;
margin-top: 2px;
margin-bottom: 0;
font-size: 14px;
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 4b05ec691a8..e3da467a27c 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -132,6 +132,11 @@
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
+
+ &> span {
+ white-space: normal;
+ word-break: break-all;
+ }
}
}
@@ -141,10 +146,6 @@
}
}
-.hint-dropdown {
- width: 250px;
-}
-
.filter-dropdown-loading {
padding: 8px 16px;
}
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 24a1ce2b84d..2a01bc4d44d 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -71,7 +71,7 @@ header {
&:focus,
&:active {
background-color: $gray-light;
- color: darken($gl-text-color-secondary, 30%);
+ color: $gl-text-color;
.todos-pending-count {
background: darken($todo-alert-blue, 10%);
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 07cb669a46e..7809d4866f1 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -178,7 +178,7 @@ $count-arrow-border: #dce0e5;
$save-project-loader-color: #555;
$divergence-graph-bar-bg: #ccc;
$divergence-graph-separator-bg: #ccc;
-$general-hover-transition-duration: 150ms;
+$general-hover-transition-duration: 100ms;
$general-hover-transition-curve: linear;
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 93cc5a8cf0a..4ef95d27f4f 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -26,10 +26,6 @@
border: 0;
}
}
-
- .container-fluid {
- @extend .fixed-width-container;
- }
}
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 45ff9f7ff5f..ab68b360f93 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -420,10 +420,6 @@
.merge-request-tabs-holder {
background-color: $white-light;
- .container-limited {
- max-width: $limited-layout-width;
- }
-
&.affix {
top: 100px;
left: 0;
@@ -433,10 +429,26 @@
@media (max-width: $screen-xs-max) {
right: 0;
}
+
+ .merge-request-tabs-container {
+ padding-left: $gl-padding;
+ padding-right: $gl-padding;
+ }
}
+}
- &:not(.affix) .container-fluid {
- padding-left: 0;
- padding-right: 0;
+.limit-container-width {
+ .merge-request-tabs-container {
+ max-width: $limited-layout-width;
+ margin-left: auto;
+ margin-right: auto;
+ }
+}
+
+.limit-container-width:not(.container-limited) {
+ .merge-request-tabs-holder:not(.affix) {
+ .merge-request-tabs-container {
+ max-width: $limited-layout-width - ($gl-padding * 2);
+ }
}
}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 5190faad308..47dfc22d533 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -214,9 +214,9 @@
&:not(:last-child) {
&::after {
content: '';
- width: 8px;
+ width: 7px;
position: absolute;
- right: -8px;
+ right: -7px;
top: 10px;
border-bottom: 2px solid $border-color;
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 1b0bf4554e6..8b59c20cb65 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -198,7 +198,7 @@
margin: 15px 5px 0 0;
input {
- height: 27px;
+ height: 28px;
}
}
@@ -523,7 +523,7 @@ a.deploy-project-label {
&:hover,
&:focus {
- color: darken($notes-light-color, 15%);
+ color: $gl-text-color;
}
}
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index 6db4e1dc1bc..d7a45bacd35 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -18,15 +18,14 @@ class AutocompleteController < ApplicationController
if params[:search].blank?
# Include current user if available to filter by "Me"
if params[:current_user].present? && current_user
+ @users = @users.where.not(id: current_user.id)
@users = [current_user, *@users]
end
if params[:author_id].present?
author = User.find_by_id(params[:author_id])
- @users = [author, *@users] if author
+ @users = [author, *@users].uniq if author
end
-
- @users.uniq!
end
render json: @users, only: [:name, :username, :id], methods: [:avatar_url]
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index a62c6211372..26e17a7553e 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -22,6 +22,7 @@ class Explore::ProjectsController < Explore::ApplicationController
def trending
@projects = filter_projects(Project.trending)
+ @projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page])
respond_to do |format|
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 9b45ed6b6af..886934a3f67 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -94,7 +94,7 @@ class Projects::BuildsController < Projects::ApplicationController
private
def build
- @build ||= project.builds.find_by!(id: params[:id]).present(user: current_user)
+ @build ||= project.builds.find_by!(id: params[:id]).present(current_user: current_user)
end
def build_path(build)
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 3602b3d5e58..667f4870c7a 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -32,12 +32,6 @@ class Projects::RefsController < Projects::ApplicationController
redirect_to new_path
end
- format.js do
- @ref = params[:ref]
- define_tree_vars
- tree
- render "tree"
- end
end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index e33a58d3771..2df8b071e13 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -13,49 +13,6 @@ class ApplicationSetting < ActiveRecord::Base
[\r\n] # any number of newline characters
}x
- DEFAULTS_CE = {
- after_sign_up_text: nil,
- akismet_enabled: false,
- container_registry_token_expire_delay: 5,
- default_branch_protection: Settings.gitlab['default_branch_protection'],
- default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
- default_projects_limit: Settings.gitlab['default_projects_limit'],
- default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
- disabled_oauth_sign_in_sources: [],
- domain_whitelist: Settings.gitlab['domain_whitelist'],
- gravatar_enabled: Settings.gravatar['enabled'],
- help_page_text: nil,
- housekeeping_bitmaps_enabled: true,
- housekeeping_enabled: true,
- housekeeping_full_repack_period: 50,
- housekeeping_gc_period: 200,
- housekeeping_incremental_repack_period: 10,
- import_sources: Gitlab::ImportSources.values,
- koding_enabled: false,
- koding_url: nil,
- max_artifacts_size: Settings.artifacts['max_size'],
- max_attachment_size: Settings.gitlab['max_attachment_size'],
- plantuml_enabled: false,
- plantuml_url: nil,
- recaptcha_enabled: false,
- repository_checks_enabled: true,
- repository_storages: ['default'],
- require_two_factor_authentication: false,
- restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
- session_expire_delay: Settings.gitlab['session_expire_delay'],
- send_user_confirmation_email: false,
- shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
- shared_runners_text: nil,
- sidekiq_throttling_enabled: false,
- sign_in_text: nil,
- signin_enabled: Settings.gitlab['signin_enabled'],
- signup_enabled: Settings.gitlab['signup_enabled'],
- two_factor_grace_period: 48,
- user_default_external: false
- }
-
- DEFAULTS = DEFAULTS_CE
-
serialize :restricted_visibility_levels
serialize :import_sources
serialize :disabled_oauth_sign_in_sources, Array
@@ -199,14 +156,64 @@ class ApplicationSetting < ActiveRecord::Base
def self.expire
Rails.cache.delete(CACHE_KEY)
+ rescue
+ # Gracefully handle when Redis is not available. For example,
+ # omnibus may fail here during gitlab:assets:compile.
end
def self.cached
Rails.cache.fetch(CACHE_KEY)
end
+ def self.defaults_ce
+ {
+ after_sign_up_text: nil,
+ akismet_enabled: false,
+ container_registry_token_expire_delay: 5,
+ default_branch_protection: Settings.gitlab['default_branch_protection'],
+ default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
+ default_projects_limit: Settings.gitlab['default_projects_limit'],
+ default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
+ disabled_oauth_sign_in_sources: [],
+ domain_whitelist: Settings.gitlab['domain_whitelist'],
+ gravatar_enabled: Settings.gravatar['enabled'],
+ help_page_text: nil,
+ housekeeping_bitmaps_enabled: true,
+ housekeeping_enabled: true,
+ housekeeping_full_repack_period: 50,
+ housekeeping_gc_period: 200,
+ housekeeping_incremental_repack_period: 10,
+ import_sources: Gitlab::ImportSources.values,
+ koding_enabled: false,
+ koding_url: nil,
+ max_artifacts_size: Settings.artifacts['max_size'],
+ max_attachment_size: Settings.gitlab['max_attachment_size'],
+ plantuml_enabled: false,
+ plantuml_url: nil,
+ recaptcha_enabled: false,
+ repository_checks_enabled: true,
+ repository_storages: ['default'],
+ require_two_factor_authentication: false,
+ restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
+ session_expire_delay: Settings.gitlab['session_expire_delay'],
+ send_user_confirmation_email: false,
+ shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
+ shared_runners_text: nil,
+ sidekiq_throttling_enabled: false,
+ sign_in_text: nil,
+ signin_enabled: Settings.gitlab['signin_enabled'],
+ signup_enabled: Settings.gitlab['signup_enabled'],
+ two_factor_grace_period: 48,
+ user_default_external: false
+ }
+ end
+
+ def self.defaults
+ defaults_ce
+ end
+
def self.create_from_defaults
- create(DEFAULTS)
+ create(defaults)
end
def home_page_url_column_exist
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 43dba86e5ed..d77b7692d75 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1188,7 +1188,18 @@ class Repository
end
def tags_sorted_by_committed_date
- tags.sort_by { |tag| tag.dereferenced_target.committed_date }
+ tags.sort_by do |tag|
+ # Annotated tags can point to any object (e.g. a blob), but generally
+ # tags point to a commit. If we don't have a commit, then just default
+ # to putting the tag at the end of the list.
+ target = tag.dereferenced_target
+
+ if target
+ target.committed_date
+ else
+ Time.now
+ end
+ end
end
def keep_around_ref_name(sha)
diff --git a/app/presenters/README.md b/app/presenters/README.md
index 3edd63451e7..a4d592b54d6 100644
--- a/app/presenters/README.md
+++ b/app/presenters/README.md
@@ -113,7 +113,7 @@ detects the presenter based on the presented subject's class.
class Projects::LabelsController < Projects::ApplicationController
def edit
@label = Gitlab::View::Presenter::Factory
- .new(@label, user: current_user)
+ .new(@label, current_user: current_user)
.fabricate!
end
end
@@ -132,7 +132,7 @@ and then in the controller:
```ruby
class Projects::LabelsController < Projects::ApplicationController
def edit
- @label = @label.present(user: current_user)
+ @label = @label.present(current_user: current_user)
end
end
```
@@ -147,7 +147,7 @@ end
You can also present the model in the view:
```ruby
-- label = @label.present(current_user)
+- label = @label.present(current_user: current_user)
%div{ class: label.text_color }
= render partial: label, label: label
diff --git a/app/views/ci/status/_badge.html.haml b/app/views/ci/status/_badge.html.haml
index 601fb7f0f3f..c00c7f7407e 100644
--- a/app/views/ci/status/_badge.html.haml
+++ b/app/views/ci/status/_badge.html.haml
@@ -1,7 +1,8 @@
- status = local_assigns.fetch(:status)
+- link = local_assigns.fetch(:link, true)
- css_classes = "ci-status ci-#{status.group}"
-- if status.has_details?
+- if link && status.has_details?
= link_to status.details_path, class: css_classes do
= custom_icon(status.icon)
= status.text
diff --git a/app/views/projects/builds/_header.html.haml b/app/views/projects/builds/_header.html.haml
index b15be0d861d..736b485bf06 100644
--- a/app/views/projects/builds/_header.html.haml
+++ b/app/views/projects/builds/_header.html.haml
@@ -1,8 +1,8 @@
.content-block.build-header
.header-content
- = render 'ci/status/badge', status: @build.detailed_status(current_user)
+ = render 'ci/status/badge', status: @build.detailed_status(current_user), link: false
Build
- %strong ##{@build.id}
+ %strong.js-build-id ##{@build.id}
in pipeline
= link_to pipeline_path(@build.pipeline) do
%strong ##{@build.pipeline.id}
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 114865935d6..84787155168 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -9,7 +9,7 @@
%fieldset.append-bottom-0
.row
.form-group.col-md-9
- = f.label :name, class: 'label-light' do
+ = f.label :name, class: 'label-light', for: 'project_name_edit' do
Project name
= f.text_field :name, class: "form-control", id: "project_name_edit"
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 18e8372ecab..5fbed8b9ab8 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -19,10 +19,8 @@
= render 'shared/issuable/nav', type: :issues
.nav-controls
- if current_user
- = link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn append-right-10' do
+ = link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn append-right-10 has-tooltip', title: 'Subscribe' do
= icon('rss')
- %span.icon-label
- Subscribe
- if can? current_user, :create_issue, @project
= link_to new_namespace_project_issue_path(@project.namespace,
@project,
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index eade0c2a668..9585a9a3ad4 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -52,7 +52,7 @@
= render 'award_emoji/awards_block', awardable: @merge_request, inline: true
.merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') }
- %div{ class: container_class }
+ .merge-request-tabs-container
%ul.merge-request-tabs.nav-links.no-top.no-bottom
%li.notes-tab
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do
@@ -115,4 +115,3 @@
});
var mrRefreshWidgetUrl = "#{mr_widget_refresh_url(@merge_request)}";
-
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index fc338dcf887..f1a80f1d5e1 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -17,4 +17,4 @@
- disabled_title = @service.disabled_title
= link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service), class: "btn #{disabled_class}", title: disabled_title
- = link_to "Cancel", namespace_project_services_path(@project.namespace, @project), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_settings_integrations_path(@project.namespace, @project), class: "btn btn-cancel"
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index e9644ca0f12..55360dadbc4 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -47,10 +47,6 @@
%li.filter-dropdown-item{ 'data-value' => 'none' }
%button.btn.btn-link
No Assignee
- - if current_user
- %li.filter-dropdown-item{ 'data-value' => current_user.to_reference }
- %button.btn.btn-link
- Assigned to me
%li.divider
%ul.filter-dropdown{ 'data-dynamic' => true, 'data-dropdown' => true }
%li.filter-dropdown-item
diff --git a/changelogs/unreleased/26844-new-search-bar-performs-a-new-request-for-each-tag.yml b/changelogs/unreleased/26844-new-search-bar-performs-a-new-request-for-each-tag.yml
new file mode 100644
index 00000000000..4678297cfd4
--- /dev/null
+++ b/changelogs/unreleased/26844-new-search-bar-performs-a-new-request-for-each-tag.yml
@@ -0,0 +1,4 @@
+---
+title: Add caching of droplab ajax requests
+merge_request: 8725
+author:
diff --git a/changelogs/unreleased/26947-build-status-self-link.yml b/changelogs/unreleased/26947-build-status-self-link.yml
new file mode 100644
index 00000000000..15c5821874e
--- /dev/null
+++ b/changelogs/unreleased/26947-build-status-self-link.yml
@@ -0,0 +1,4 @@
+---
+title: Add link verification to badge partial in order to render a badge without a link
+merge_request: 8740
+author:
diff --git a/changelogs/unreleased/27044-fix-explore-sorting-on-trending.yml b/changelogs/unreleased/27044-fix-explore-sorting-on-trending.yml
new file mode 100644
index 00000000000..0f0a8940f72
--- /dev/null
+++ b/changelogs/unreleased/27044-fix-explore-sorting-on-trending.yml
@@ -0,0 +1,4 @@
+---
+title: Fix /explore sorting
+merge_request:
+author:
diff --git a/changelogs/unreleased/27248-filtered-search-does-not-allow-filtering-labels-with-multiple-words.yml b/changelogs/unreleased/27248-filtered-search-does-not-allow-filtering-labels-with-multiple-words.yml
new file mode 100644
index 00000000000..6e036923158
--- /dev/null
+++ b/changelogs/unreleased/27248-filtered-search-does-not-allow-filtering-labels-with-multiple-words.yml
@@ -0,0 +1,4 @@
+---
+title: Fix filtering with multiple words
+merge_request: 8830
+author:
diff --git a/changelogs/unreleased/27259-label-for-references-the-wrong-associated-text-input.yml b/changelogs/unreleased/27259-label-for-references-the-wrong-associated-text-input.yml
new file mode 100644
index 00000000000..2591f161bc5
--- /dev/null
+++ b/changelogs/unreleased/27259-label-for-references-the-wrong-associated-text-input.yml
@@ -0,0 +1,4 @@
+---
+title: Fix project name label's for reference in project settings
+merge_request: 8795
+author:
diff --git a/changelogs/unreleased/27277-small-mini-pipeline-graph-glitch-upon-hover.yml b/changelogs/unreleased/27277-small-mini-pipeline-graph-glitch-upon-hover.yml
new file mode 100644
index 00000000000..9456251025b
--- /dev/null
+++ b/changelogs/unreleased/27277-small-mini-pipeline-graph-glitch-upon-hover.yml
@@ -0,0 +1,4 @@
+---
+title: fixed small mini pipeline graph line glitch
+merge_request: 8804
+author:
diff --git a/changelogs/unreleased/contribution-calendar-scroll.yml b/changelogs/unreleased/contribution-calendar-scroll.yml
new file mode 100644
index 00000000000..a504d59e61c
--- /dev/null
+++ b/changelogs/unreleased/contribution-calendar-scroll.yml
@@ -0,0 +1,4 @@
+---
+title: contribution calendar scrolls from right to left
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix-cancel-integration-settings.yml b/changelogs/unreleased/fix-cancel-integration-settings.yml
new file mode 100644
index 00000000000..294b0aa5db9
--- /dev/null
+++ b/changelogs/unreleased/fix-cancel-integration-settings.yml
@@ -0,0 +1,4 @@
+---
+title: Fixed services form cancel not redirecting back the integrations settings view
+merge_request: 8843
+author:
diff --git a/changelogs/unreleased/fix-search-bar-search-param.yml b/changelogs/unreleased/fix-search-bar-search-param.yml
new file mode 100644
index 00000000000..4df14d3bf13
--- /dev/null
+++ b/changelogs/unreleased/fix-search-bar-search-param.yml
@@ -0,0 +1,4 @@
+---
+title: Fix search bar search param encoding
+merge_request: 8753
+author:
diff --git a/changelogs/unreleased/get-rid-of-water-from-notification_service_spec-to-make-it-DRY.yml b/changelogs/unreleased/get-rid-of-water-from-notification_service_spec-to-make-it-DRY.yml
new file mode 100644
index 00000000000..f60417d185e
--- /dev/null
+++ b/changelogs/unreleased/get-rid-of-water-from-notification_service_spec-to-make-it-DRY.yml
@@ -0,0 +1,4 @@
+---
+title: Make notification_service spec DRYer by making test reusable
+merge_request:
+author: YarNayar
diff --git a/changelogs/unreleased/hardcode-title-system-note.yml b/changelogs/unreleased/hardcode-title-system-note.yml
new file mode 100644
index 00000000000..1b0a63efa51
--- /dev/null
+++ b/changelogs/unreleased/hardcode-title-system-note.yml
@@ -0,0 +1,4 @@
+---
+title: Ensure autogenerated title does not cause failing spec
+merge_request: 8963
+author: brian m. carlson
diff --git a/changelogs/unreleased/improve-ci-example-php-doc.yml b/changelogs/unreleased/improve-ci-example-php-doc.yml
new file mode 100644
index 00000000000..39a85e3d261
--- /dev/null
+++ b/changelogs/unreleased/improve-ci-example-php-doc.yml
@@ -0,0 +1,4 @@
+---
+title: Changed composer installer script in the CI PHP example doc
+merge_request: 4342
+author: Jeffrey Cafferata
diff --git a/changelogs/unreleased/issuable-sidebar-bug.yml b/changelogs/unreleased/issuable-sidebar-bug.yml
new file mode 100644
index 00000000000..4086292eb89
--- /dev/null
+++ b/changelogs/unreleased/issuable-sidebar-bug.yml
@@ -0,0 +1,4 @@
+---
+title: Fixed Issuable sidebar not closing on smaller/mobile sized screens
+merge_request:
+author:
diff --git a/changelogs/unreleased/issue_27211.yml b/changelogs/unreleased/issue_27211.yml
new file mode 100644
index 00000000000..ad48fec5d85
--- /dev/null
+++ b/changelogs/unreleased/issue_27211.yml
@@ -0,0 +1,4 @@
+---
+title: Remove unused js response from refs controller
+merge_request:
+author:
diff --git a/changelogs/unreleased/mr-tabs-container-offset.yml b/changelogs/unreleased/mr-tabs-container-offset.yml
new file mode 100644
index 00000000000..c5df8abfcf2
--- /dev/null
+++ b/changelogs/unreleased/mr-tabs-container-offset.yml
@@ -0,0 +1,4 @@
+---
+title: Fixed merge requests tab extra margin when fixed to window
+merge_request:
+author:
diff --git a/changelogs/unreleased/relative-url-assets.yml b/changelogs/unreleased/relative-url-assets.yml
new file mode 100644
index 00000000000..0877664aca4
--- /dev/null
+++ b/changelogs/unreleased/relative-url-assets.yml
@@ -0,0 +1,4 @@
+---
+title: allow relative url change without recompiling frontend assets
+merge_request: 8831
+author:
diff --git a/changelogs/unreleased/revert-filter-assigned-to-me.yml b/changelogs/unreleased/revert-filter-assigned-to-me.yml
new file mode 100644
index 00000000000..37f9d2f5fc4
--- /dev/null
+++ b/changelogs/unreleased/revert-filter-assigned-to-me.yml
@@ -0,0 +1,4 @@
+---
+title: Revert 3f17f29a
+merge_request: 8785
+author:
diff --git a/changelogs/unreleased/sh-fix-annotated-tags-pointing-to-blob.yml b/changelogs/unreleased/sh-fix-annotated-tags-pointing-to-blob.yml
new file mode 100644
index 00000000000..ff2b38f21f2
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-annotated-tags-pointing-to-blob.yml
@@ -0,0 +1,4 @@
+---
+title: Fix Error 500 when repositories contain annotated tags pointing to blobs
+merge_request:
+author:
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 906ec11f012..4f33aad8693 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -419,10 +419,4 @@ if Rails.env.test?
end
# Force a refresh of application settings at startup
-begin
- ApplicationSetting.expire
- Ci::ApplicationSetting.expire
-rescue
- # Gracefully handle when Redis is not available. For example,
- # omnibus may fail here during assets:precompile.
-end
+ApplicationSetting.expire
diff --git a/config/initializers/5_backend.rb b/config/initializers/5_backend.rb
index ed88c8ee1b8..2bd159ca7f1 100644
--- a/config/initializers/5_backend.rb
+++ b/config/initializers/5_backend.rb
@@ -1,9 +1,3 @@
-# GIT over SSH
-require_dependency Rails.root.join('lib/gitlab/backend/shell')
-
-# GitLab shell adapter
-require_dependency Rails.root.join('lib/gitlab/backend/shell_adapter')
-
required_version = Gitlab::VersionInfo.parse(Gitlab::Shell.version_required)
current_version = Gitlab::VersionInfo.parse(Gitlab::Shell.new.version)
diff --git a/config/initializers/rspec_profiling.rb b/config/initializers/rspec_profiling.rb
new file mode 100644
index 00000000000..f462e654b2c
--- /dev/null
+++ b/config/initializers/rspec_profiling.rb
@@ -0,0 +1,14 @@
+module RspecProfilingConnection
+ def establish_connection
+ ::RspecProfiling::Collectors::PSQL::Result.establish_connection(ENV['RSPEC_PROFILING_POSTGRES_URL'])
+ end
+end
+
+if Rails.env.test?
+ RspecProfiling.configure do |config|
+ if ENV['RSPEC_PROFILING_POSTGRES_URL']
+ RspecProfiling::Collectors::PSQL.prepend(RspecProfilingConnection)
+ config.collector = RspecProfiling::Collectors::PSQL
+ end
+ end
+end
diff --git a/doc/README.md b/doc/README.md
index 993b30ccdb5..909740211a6 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -44,7 +44,7 @@
- [Operations](administration/operations.md) Keeping GitLab up and running.
- [Raketasks](raketasks/README.md) Backups, maintenance, automatic webhook setup and the importing of projects.
- [Repository checks](administration/repository_checks.md) Periodic Git repository checks.
-- [Repository storages](administration/repository_storages.md) Manage the paths used to store repositories.
+- [Repository storage paths](administration/repository_storage_paths.md) Manage the paths used to store repositories.
- [Security](security/README.md) Learn what you can do to further secure your GitLab instance.
- [System hooks](system_hooks/system_hooks.md) Notifications when users, projects and keys are changed.
- [Update](update/README.md) Update guides to upgrade your installation.
@@ -61,7 +61,6 @@
- [Sidekiq Troubleshooting](administration/troubleshooting/sidekiq.md) Debug when Sidekiq appears hung and is not processing jobs.
- [High Availability](administration/high_availability/README.md) Configure multiple servers for scaling or high availability.
- [Container Registry](administration/container_registry.md) Configure Docker Registry with GitLab.
-- [Multiple mountpoints for the repositories storage](administration/repository_storages.md) Define multiple repository storage paths to distribute the storage load.
## Contributor documentation
diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md
index 33b9b28433a..5b6ee354887 100644
--- a/doc/administration/raketasks/maintenance.md
+++ b/doc/administration/raketasks/maintenance.md
@@ -172,14 +172,14 @@ Omnibus packages.
```
cd /home/git/gitlab
-sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
+sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production
```
For omnibus versions, the unoptimized assets (JavaScript, CSS) are frozen at
the release of upstream GitLab. The omnibus version includes optimized versions
of those assets. Unless you are modifying the JavaScript / CSS code on your
production machine after installing the package, there should be no reason to redo
-rake assets:precompile on the production machine. If you suspect that assets
+rake gitlab:assets:compile on the production machine. If you suspect that assets
have been corrupted, you should reinstall the omnibus package.
## Tracking Deployments
diff --git a/doc/administration/repository_checks.md b/doc/administration/repository_checks.md
index bc2b1f20ed3..ee37ea49874 100644
--- a/doc/administration/repository_checks.md
+++ b/doc/administration/repository_checks.md
@@ -13,12 +13,12 @@ checks failed you can see their output on the admin log page under
## Periodic checks
-GitLab periodically runs a repository check on all project repositories and
-wiki repositories in order to detect data corruption problems. A
-project will be checked no more than once per week. If any projects
+When enabled, GitLab periodically runs a repository check on all project
+repositories and wiki repositories in order to detect data corruption problems.
+A project will be checked no more than once per month. If any projects
fail their repository checks all GitLab administrators will receive an email
-notification of the situation. This notification is sent out no more
-than once a day.
+notification of the situation. This notification is sent out once a week on
+Sunday, by default.
## Disabling periodic checks
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
new file mode 100644
index 00000000000..d6aa6101026
--- /dev/null
+++ b/doc/administration/repository_storage_paths.md
@@ -0,0 +1,102 @@
+# Repository storage paths
+
+> [Introduced][ce-4578] in GitLab 8.10.
+
+GitLab allows you to define multiple repository storage paths to distribute the
+storage load between several mount points.
+
+>**Notes:**
+>
+- You must have at least one storage path called `default`.
+- The paths are defined in key-value pairs. The key is an arbitrary name you
+ can pick to name the file path.
+- The target directories and any of its subpaths must not be a symlink.
+
+## Configure GitLab
+
+>**Warning:**
+In order for [backups] to work correctly, the storage path must **not** be a
+mount point and the GitLab user should have correct permissions for the parent
+directory of the path. In Omnibus GitLab this is taken care of automatically,
+but for source installations you should be extra careful.
+>
+The thing is that for compatibility reasons `gitlab.yml` has a different
+structure than Omnibus. In `gitlab.yml` you indicate the path for the
+repositories, for example `/home/git/repositories`, while in Omnibus you
+indicate `git_data_dirs`, which for the example above would be `/home/git`.
+Then, Omnibus will create a `repositories` directory under that path to use with
+`gitlab.yml`.
+>
+This little detail matters because while restoring a backup, the current
+contents of `/home/git/repositories` [are moved to][raketask] `/home/git/repositories.old`,
+so if `/home/git/repositories` is the mount point, then `mv` would be moving
+things between mount points, and bad things could happen. Ideally,
+`/home/git` would be the mount point, so then things would be moving within the
+same mount point. This is guaranteed with Omnibus installations (because they
+don't specify the full repository path but the parent path), but not for source
+installations.
+
+---
+
+Now that you've read that big fat warning above, let's edit the configuration
+files and add the full paths of the alternative repository storage paths. In
+the example below, we add two more mountpoints that are named `nfs` and `cephfs`
+respectively.
+
+**For installations from source**
+
+1. Edit `gitlab.yml` and add the storage paths:
+
+ ```yaml
+ repositories:
+ # Paths where repositories can be stored. Give the canonicalized absolute pathname.
+ # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!!
+ storages: # You must have at least a 'default' storage path.
+ default: /home/git/repositories
+ nfs: /mnt/nfs/repositories
+ cephfs: /mnt/cephfs/repositories
+ ```
+
+1. [Restart GitLab] for the changes to take effect.
+
+>**Note:**
+The [`gitlab_shell: repos_path` entry][repospath] in `gitlab.yml` will be
+deprecated and replaced by `repositories: storages` in the future, so if you
+are upgrading from a version prior to 8.10, make sure to add the configuration
+as described in the step above. After you make the changes and confirm they are
+working, you can remove the `repos_path` line.
+
+---
+
+**For Omnibus installations**
+
+1. Edit `/etc/gitlab/gitlab.rb` by appending the rest of the paths to the
+ default one:
+
+ ```ruby
+ git_data_dirs({
+ "default" => "/var/opt/gitlab/git-data",
+ "nfs" => "/mnt/nfs/git-data",
+ "cephfs" => "/mnt/cephfs/git-data"
+ })
+ ```
+
+ Note that Omnibus stores the repositories in a `repositories` subdirectory
+ of the `git-data` directory.
+
+## Choose where new project repositories will be stored
+
+Once you set the multiple storage paths, you can choose where new projects will
+be stored via the **Application Settings** in the Admin area.
+
+![Choose repository storage path in Admin area](img/repository_storages_admin_ui.png)
+
+Beginning with GitLab 8.13.4, multiple paths can be chosen. New projects will be
+randomly placed on one of the selected paths.
+
+[ce-4578]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4578
+[restart gitlab]: restart_gitlab.md#installations-from-source
+[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
+[backups]: ../raketasks/backup_restore.md
+[raketask]: https://gitlab.com/gitlab-org/gitlab-ce/blob/033e5423a2594e08a7ebcd2379bd2331f4c39032/lib/backup/repository.rb#L54-56
+[repospath]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-9-stable/config/gitlab.yml.example#L457
diff --git a/doc/administration/repository_storages.md b/doc/administration/repository_storages.md
index ab70557b69a..9d41ba77f34 100644
--- a/doc/administration/repository_storages.md
+++ b/doc/administration/repository_storages.md
@@ -1,102 +1,3 @@
# Repository storages
-> [Introduced][ce-4578] in GitLab 8.10.
-
-GitLab allows you to define multiple repository storage paths to distribute the
-storage load between several mount points.
-
->**Notes:**
->
-- You must have at least one storage path called `default`.
-- The paths are defined in key-value pairs. The key is an arbitrary name you
- can pick to name the file path.
-- The target directories and any of its subpaths must not be a symlink.
-
-## Configure GitLab
-
->**Warning:**
-In order for [backups] to work correctly, the storage path must **not** be a
-mount point and the GitLab user should have correct permissions for the parent
-directory of the path. In Omnibus GitLab this is taken care of automatically,
-but for source installations you should be extra careful.
->
-The thing is that for compatibility reasons `gitlab.yml` has a different
-structure than Omnibus. In `gitlab.yml` you indicate the path for the
-repositories, for example `/home/git/repositories`, while in Omnibus you
-indicate `git_data_dirs`, which for the example above would be `/home/git`.
-Then, Omnibus will create a `repositories` directory under that path to use with
-`gitlab.yml`.
->
-This little detail matters because while restoring a backup, the current
-contents of `/home/git/repositories` [are moved to][raketask] `/home/git/repositories.old`,
-so if `/home/git/repositories` is the mount point, then `mv` would be moving
-things between mount points, and bad things could happen. Ideally,
-`/home/git` would be the mount point, so then things would be moving within the
-same mount point. This is guaranteed with Omnibus installations (because they
-don't specify the full repository path but the parent path), but not for source
-installations.
-
----
-
-Now that you've read that big fat warning above, let's edit the configuration
-files and add the full paths of the alternative repository storage paths. In
-the example below, we add two more mountpoints that are named `nfs` and `cephfs`
-respectively.
-
-**For installations from source**
-
-1. Edit `gitlab.yml` and add the storage paths:
-
- ```yaml
- repositories:
- # Paths where repositories can be stored. Give the canonicalized absolute pathname.
- # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!!
- storages: # You must have at least a 'default' storage path.
- default: /home/git/repositories
- nfs: /mnt/nfs/repositories
- cephfs: /mnt/cephfs/repositories
- ```
-
-1. [Restart GitLab] for the changes to take effect.
-
->**Note:**
-The [`gitlab_shell: repos_path` entry][repospath] in `gitlab.yml` will be
-deprecated and replaced by `repositories: storages` in the future, so if you
-are upgrading from a version prior to 8.10, make sure to add the configuration
-as described in the step above. After you make the changes and confirm they are
-working, you can remove the `repos_path` line.
-
----
-
-**For Omnibus installations**
-
-1. Edit `/etc/gitlab/gitlab.rb` by appending the rest of the paths to the
- default one:
-
- ```ruby
- git_data_dirs({
- "default" => "/var/opt/gitlab/git-data",
- "nfs" => "/mnt/nfs/git-data",
- "cephfs" => "/mnt/cephfs/git-data"
- })
- ```
-
- Note that Omnibus stores the repositories in a `repositories` subdirectory
- of the `git-data` directory.
-
-## Choose where new project repositories will be stored
-
-Once you set the multiple storage paths, you can choose where new projects will
-be stored via the **Application Settings** in the Admin area.
-
-![Choose repository storage path in Admin area](img/repository_storages_admin_ui.png)
-
-Beginning with GitLab 8.13.4, multiple paths can be chosen. New projects will be
-randomly placed on one of the selected paths.
-
-[ce-4578]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4578
-[restart gitlab]: restart_gitlab.md#installations-from-source
-[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
-[backups]: ../raketasks/backup_restore.md
-[raketask]: https://gitlab.com/gitlab-org/gitlab-ce/blob/033e5423a2594e08a7ebcd2379bd2331f4c39032/lib/backup/repository.rb#L54-56
-[repospath]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-9-stable/config/gitlab.yml.example#L457
+This document was moved to a [new location](repository_storage_paths.md).
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 5c11d0f83bb..53ce381c8ae 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -245,7 +245,7 @@ Example response:
```json
[
{
- "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files",
+ "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files",
"new_path": "doc/update/5.4-to-6.0.md",
"old_path": "doc/update/5.4-to-6.0.md",
"a_mode": null,
diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md
index ffc310ec8c7..5377bf9ee80 100644
--- a/doc/ci/examples/README.md
+++ b/doc/ci/examples/README.md
@@ -14,6 +14,12 @@ Apart from those, here is an collection of tutorials and guides on setting up yo
- [Test a Phoenix application](test-phoenix-application.md)
- [Using `dpl` as deployment tool](deployment/README.md)
- [Example project that shows how to use Review Apps](https://gitlab.com/gitlab-examples/review-apps-nginx/)
+- [Run PHP Composer & NPM scripts then deploy them to a staging server](deployment/composer-npm-deploy.md)
+- Help your favorite programming language and GitLab by sending a merge request
+ with a guide for that language.
+
+## Outside the documentation
+
- [Blog post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/)
- [Repositories with examples for various languages](https://gitlab.com/groups/gitlab-examples)
- [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
diff --git a/doc/ci/examples/deployment/composer-npm-deploy.md b/doc/ci/examples/deployment/composer-npm-deploy.md
new file mode 100644
index 00000000000..5334a73e1f5
--- /dev/null
+++ b/doc/ci/examples/deployment/composer-npm-deploy.md
@@ -0,0 +1,156 @@
+## Running Composer and NPM scripts with deployment via SCP
+
+This guide covers the building dependencies of a PHP project while compiling assets via an NPM script.
+
+While is possible to create your own image with custom PHP and Node JS versions, for brevity, we will use an existing [Docker image](https://hub.docker.com/r/tetraweb/php/) that contains both PHP and NodeJS installed.
+
+
+```yaml
+image: tetraweb/php
+```
+
+The next step is to install zip/unzip packages and make composer available. We will place these in the `before_script` section:
+
+```yaml
+before_script:
+ - apt-get update
+ - apt-get install zip unzip
+ - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
+ - php composer-setup.php
+ - php -r "unlink('composer-setup.php');"
+```
+
+This will make sure we have all requirements ready. Next, we want to run `composer update` to fetch all PHP dependencies and `npm install` to load node packages, then run the `npm` script. We need to append them into `before_script` section:
+
+```yaml
+before_script:
+ # ...
+ - php composer.phar update
+ - npm install
+ - npm run deploy
+```
+
+In this particular case, the `npm deploy` script is a Gulp script that does the following:
+
+1. Compile CSS & JS
+2. Create sprites
+3. Copy various assets (images, fonts) around
+4. Replace some strings
+
+All these operations will put all files into a `build` folder, which is ready to be deployed to a live server.
+
+### How to transfer files to a live server?
+
+You have multiple options: rsync, scp, sftp and so on. For now, we will use scp.
+
+To make this work, you need to add a GitLab Secret Variable (accessible on _gitlab.example/your-project-name/variables_). That variable will be called `STAGING_PRIVATE_KEY` and it's the **private** ssh key of your server.
+
+#### Security tip
+
+Create a user that has access **only** to the folder that needs to be updated!
+
+After you create that variable, you need to make sure that key will be added to the docker container on run:
+
+```yaml
+before_script:
+ # - ....
+ - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
+ - mkdir -p ~/.ssh
+ - eval $(ssh-agent -s)
+ - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
+```
+
+In order, this means that:
+
+1. We check if the `ssh-agent` is available and we install it if it's not;
+2. We create the `~/.ssh` folder;
+3. We make sure we're running bash;
+4. We disable host checking (we don't ask for user accept when we first connect to a server; and since every build will equal a first connect, we kind of need this)
+
+And this is basically all you need in the `before_script` section.
+
+## How to deploy things?
+
+As we stated above, we need to deploy the `build` folder from the docker image to our server. To do so, we create a new job:
+
+```yaml
+stage_deploy:
+ artifacts:
+ paths:
+ - build/
+ only:
+ - dev
+ script:
+ - ssh-add <(echo "$STAGING_PRIVATE_KEY")
+ - ssh -p22 server_user@server_host "mkdir htdocs/wp-content/themes/_tmp"
+ - scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/_tmp
+ - ssh -p22 server_user@server_host "mv htdocs/wp-content/themes/live htdocs/wp-content/themes/_old && mv htdocs/wp-content/themes/_tmp htdocs/wp-content/themes/live"
+ - ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/_old"
+```
+
+### What's going on here?
+
+1. `only:dev` means that this build will run only when something is pushed to the `dev` branch. You can remove this block completely and have everything be ran on every push (but probably this is something you don't want)
+2. `ssh-add ...` we will add that private key you added on the web UI to the docker container
+3. We will connect via `ssh` and create a new `_tmp` folder
+4. We will connect via `scp` and upload the `build` folder (which was generated by a `npm` script) to our previously created `_tmp` folder
+5. We will connect again to `ssh` and move the `live` folder to an `_old` folder, then move `_tmp` to `live`.
+6. We connect to ssh and remove the `_old` folder
+
+What's the deal with the artifacts? We just tell GitLab CI to keep the `build` directory (later on, you can download that as needed).
+
+#### Why we do it this way?
+
+If you're using this only for stage server, you could do this in two steps:
+
+```yaml
+- ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/live/*"
+- scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/live
+```
+
+The problem is that there will be a small period of time when you won't have the app on your server.
+
+So we use so many steps because we want to make sure that at any given time we have a functional app in place.
+
+## Where to go next?
+
+Since this was a WordPress project, I gave real life code snippets. Some ideas you can pursuit:
+
+- Having a slightly different script for `master` branch will allow you to deploy to a production server from that branch and to a stage server from any other branches;
+- Instead of pushing it live, you can push it to WordPress official repo (with creating a SVN commit & stuff);
+- You could generate i18n text domains on the fly.
+
+---
+
+Our final `.gitlab-ci.yml` will look like this:
+
+```yaml
+image: tetraweb/php
+
+before_script:
+ - apt-get update
+ - apt-get install zip unzip
+ - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
+ - php composer-setup.php
+ - php -r "unlink('composer-setup.php');"
+ - php composer.phar update
+ - npm install
+ - npm run deploy
+ - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
+ - mkdir -p ~/.ssh
+ - eval $(ssh-agent -s)
+ - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
+
+stage_deploy:
+ artifacts:
+ paths:
+ - build/
+ only:
+ - dev
+ script:
+ - ssh-add <(echo "$STAGING_PRIVATE_KEY")
+ - ssh -p22 server_user@server_host "mkdir htdocs/wp-content/themes/_tmp"
+ - scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/_tmp
+ - ssh -p22 server_user@server_host "mv htdocs/wp-content/themes/live htdocs/wp-content/themes/_old && mv htdocs/wp-content/themes/_tmp htdocs/wp-content/themes/live"
+ - ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/_old"
+``` \ No newline at end of file
diff --git a/doc/ci/examples/php.md b/doc/ci/examples/php.md
index 82ffb841729..5eeec92d976 100644
--- a/doc/ci/examples/php.md
+++ b/doc/ci/examples/php.md
@@ -235,7 +235,11 @@ cache:
before_script:
# Install composer dependencies
-- curl --silent --show-error https://getcomposer.org/installer | php
+- wget https://composer.github.io/installer.sig -O - -q | tr -d '\n' > installer.sig
+- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
+- php -r "if (hash_file('SHA384', 'composer-setup.php') === file_get_contents('installer.sig')) { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
+- php composer-setup.php
+- php -r "unlink('composer-setup.php'); unlink('installer.sig');"
- php composer.phar install
...
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 75a0897eb15..f11257be5c3 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -86,7 +86,7 @@ used for time of the build. The configuration of this feature is covered in
### before_script
`before_script` is used to define the command that should be run before all
-builds, including deploy builds. This can be an array or a multi-line string.
+builds, including deploy builds, but after the restoration of artifacts. This can be an array or a multi-line string.
### after_script
diff --git a/doc/development/README.md b/doc/development/README.md
index 6f2ca7b8590..265df98fb87 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -18,6 +18,7 @@
- [Frontend guidelines](frontend.md)
- [SQL guidelines](sql.md) for working with SQL queries
- [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
+- [`Gemfile` guidelines](gemfile.md)
## Process
diff --git a/doc/development/gemfile.md b/doc/development/gemfile.md
new file mode 100644
index 00000000000..ec9718cea71
--- /dev/null
+++ b/doc/development/gemfile.md
@@ -0,0 +1,14 @@
+# `Gemfile` guidelines
+
+When adding a new entry to `Gemfile` or upgrading an existing dependency pay
+attention to the following rules.
+
+## No gems fetched from git repositories
+
+We do not allow gems that are fetched from git repositories. All gems have
+to be available in the RubyGems index. We want to minimize external build
+dependencies and build times.
+
+## License compliance
+
+Refer to [licensing guidelines](licensing.md) for ensuring license compliance.
diff --git a/doc/development/performance.md b/doc/development/performance.md
index f936a49a2aa..c1f129e576c 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -211,6 +211,41 @@ suite first. See the
[StackProf documentation](https://github.com/tmm1/stackprof/blob/master/README.md)
for details.
+## RSpec profiling
+
+GitLab's development environment also includes the
+[rspec_profiling](https://github.com/foraker/rspec_profiling) gem, which is used
+to collect data on spec execution times. This is useful for analyzing the
+performance of the test suite itself, or seeing how the performance of a spec
+may have changed over time.
+
+To activate profiling in your local environment, run the following:
+
+```
+$ export RSPEC_PROFILING=yes
+$ rake rspec_profiling:install
+```
+
+This creates an SQLite3 database in `tmp/rspec_profiling`, into which statistics
+are saved every time you run specs with the `RSPEC_PROFILING` environment
+variable set.
+
+Ad-hoc investigation of the collected results can be performed in an interactive
+shell:
+
+```
+$ rake rspec_profiling:console
+irb(main):001:0> results.count
+=> 231
+irb(main):002:0> results.last.attributes.keys
+=> ["id", "commit", "date", "file", "line_number", "description", "time", "status", "exception", "query_count", "query_time", "request_count", "request_time", "created_at", "updated_at"]
+irb(main):003:0> results.where(status: "passed").average(:time).to_s
+=> "0.211340155844156"
+```
+These results can also be placed into a PostgreSQL database by setting the
+`RSPEC_PROFILING_POSTGRES_URL` variable. This is used to profile the test suite
+when running in the CI environment.
+
## Importance of Changes
When working on performance improvements, it's important to always ask yourself
diff --git a/doc/development/ux_guide/components.md b/doc/development/ux_guide/components.md
index 706bb180912..1b19587a0b8 100644
--- a/doc/development/ux_guide/components.md
+++ b/doc/development/ux_guide/components.md
@@ -109,7 +109,7 @@ Dropdowns are used to allow users to choose one (or many) options from a list of
### Max size
-The max height for dropdowns should target **10-15 items**. If the height of the dropdown is too large, the list becomes very hard to parse and it is easy to visually lose track of the item you are looking for. Usability also suffers as more mouse movement is required, and you have a larger area in which you hijack the scroll away from the page level. While it may initially seem counterintuitive to not show as many items as you can, it is actually quicker and easier to process the information when it is cropped at a reasonable height.
+The max height for dropdowns should target **10-15** single line items, or **7-10** multi-line items. If the height of the dropdown is too large, the list becomes very hard to parse and it is easy to visually lose track of the item you are looking for. Usability also suffers as more mouse movement is required, and you have a larger area in which you hijack the scroll away from the page level. While it may initially seem counterintuitive to not show as many items as you can, it is actually quicker and easier to process the information when it is cropped at a reasonable height.
---
diff --git a/doc/development/ux_guide/copy.md b/doc/development/ux_guide/copy.md
index 31cc9dd2a53..5b65d531e54 100644
--- a/doc/development/ux_guide/copy.md
+++ b/doc/development/ux_guide/copy.md
@@ -102,6 +102,12 @@ When using the <kbd>Alt</kbd> keystrokes in Windows, use the numeric keypad, not
## Terminology
Only use the terms in the tables below.
+### Projects and Groups
+
+| Term | Use | :no_entry_sign: Don't |
+| ---- | --- | ----- |
+| Members | When discussing the people who are a part of a project or a group. | Don't use `users`. |
+
### Issues
#### Adjectives (states)
@@ -117,7 +123,7 @@ Use `5 open issues` and don’t use `5 pending issues`.
#### Verbs (actions)
-| Term | Use | Don’t |
+| Term | Use | :no_entry_sign: Don’t |
| ---- | --- | --- |
| Add | Add an issue | Don’t use `create` or `new` |
| View | View an open or closed issue ||
@@ -158,7 +164,7 @@ The form should be titled `Edit issue`. The submit button should be labeled `Sav
#### Verbs (actions)
-| Term | Use | Don’t |
+| Term | Use | :no_entry_sign: Don’t |
| ---- | --- | --- |
| Add | Add a merge request | Do not use `create` or `new` |
| View | View an open or merged merge request ||
diff --git a/doc/gitlab-basics/add-image.md b/doc/gitlab-basics/add-image.md
index 476b48a217c..1a44123aa81 100644
--- a/doc/gitlab-basics/add-image.md
+++ b/doc/gitlab-basics/add-image.md
@@ -1,62 +1,56 @@
# How to add an image
-The following are the steps to add images to your repository in
-GitLab:
+Using your standard tool for copying files (e.g. Finder in Mac OS, or Explorer
+in Windows, or...), put the image file into the GitLab project. You can find the
+project as a regular folder in your files.
-Find the image that you’d like to add.
+Go to your [shell](command-line-commands.md), and move into the folder of your
+Gitlab project. This usually means running the following command until you get
+to the desired destination:
-In your computer files, find the GitLab project to which you'd like to add the image
-(you'll find it as a regular file). Click on every file until you find exactly where you'd
-like to add the image. There, paste the image.
-
-Go to your [shell](command-line-commands.md), and add the following commands:
-
-Add this command for every directory that you'd like to open:
```
-cd NAME-OF-FILE-YOU'D-LIKE-TO-OPEN
+cd NAME-OF-FOLDER-YOU'D-LIKE-TO-OPEN
```
-Create a new branch:
-```
-git checkout -b NAME-OF-BRANCH
-```
+Check if your image is actually present in the directory (if you are in Windows,
+use `dir` instead):
-Check if your image was correctly added to the directory:
```
ls
```
You should see the name of the image in the list shown.
-Move up the hierarchy through directories:
-```
-cd ../
-```
+Check the status:
-Check the status and you should see your image’s name in red:
```
git status
```
-Add your changes:
+Your image's name should appear in red, so `git` took notice of it! Now add it
+to the repository:
+
```
git add NAME-OF-YOUR-IMAGE
```
-Check the status and you should see your image’s name in green:
+Check the status again, your image's name should have turned green:
+
```
git status
```
-Add the commit:
+Commit:
+
```
-git commit -m “DESCRIBE COMMIT IN A FEW WORDS”
+git commit -m "DESCRIBE COMMIT IN A FEW WORDS"
```
-Now you can push (send) your changes (in the branch NAME-OF-BRANCH) to GitLab (the git remote named 'origin'):
+Now you can push (send) your changes (in the branch NAME-OF-BRANCH) to GitLab
+(the git remote named 'origin'):
+
```
git push origin NAME-OF-BRANCH
```
-Your image will be added to your branch in your repository in GitLab. Create a [Merge Request](add-merge-request.md)
-to integrate your changes to your project.
+Your image will be added to your branch in your repository in GitLab.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 3e7674e13ab..425c5d93efb 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -448,7 +448,7 @@ Check if GitLab and its environment are configured correctly:
### Compile Assets
- sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
+ sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production
### Start Your GitLab Instance
diff --git a/doc/install/relative_url.md b/doc/install/relative_url.md
index 44d2a14f366..713d11b75e4 100644
--- a/doc/install/relative_url.md
+++ b/doc/install/relative_url.md
@@ -113,14 +113,6 @@ Make sure to follow all steps below:
If you are using a custom init script, make sure to edit the above
gitlab-workhorse setting as needed.
-1. After all the above changes recompile the assets. This is an important task
- and will take some time to complete depending on the server resources:
-
- ```
- cd /home/git/gitlab
- sudo -u git -H bundle exec rake assets:clean assets:precompile RAILS_ENV=production
- ```
-
1. [Restart GitLab][] for the changes to take effect.
### Disable relative URL in GitLab
diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md
index 54d523b59fd..154a0f817da 100644
--- a/doc/update/patch_versions.md
+++ b/doc/update/patch_versions.md
@@ -57,7 +57,7 @@ sudo -u git -H bundle clean
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Clean up assets and cache
-sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+sudo -u git -H bundle exec rake gitlab:assets:clean gitlab:assets:compile cache:clear RAILS_ENV=production
```
### 4. Update gitlab-workhorse to the corresponding version
diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index df33d54cc26..cc688a7f99c 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -140,70 +140,68 @@ into the password field.
## Recovery options
-If you lose your code generation device (such as your mobile phone) and you need
-to disable two-factor authentication on your account, you have several options.
+To disable two-factor authentication on your account (for example, if you
+have lost your code generation device) you can:
+* [Use a saved recovery code](#use-a-saved-recovery-code)
+* [Generate new recovery codes using SSH](#generate-new-recovery-codes-using-SSH)
+* [Ask a GitLab administrator to disable two-factor authentication on your account](#ask-a-gitlab-administrator-to-disable-two-factor-authentication-on-your-account)
### Use a saved recovery code
-When you enabled two-factor authentication for your account, a series of
-recovery codes were generated. If you saved those codes somewhere safe, you
-may use one to sign in.
+Enabling two-factor authentication for your account generated several recovery
+codes. If you saved these codes, you can use one of them to sign in.
-First, enter your username/email and password on the GitLab sign in page. When
-prompted for a two-factor code, enter one of the recovery codes you saved
-previously.
+To use a recovery code, enter your username/email and password on the GitLab
+sign-in page. When prompted for a two-factor code, enter the recovery code.
-> **Note:** Once a particular recovery code has been used, it cannot be used again.
- You may still use the other saved recovery codes at a later time.
+> **Note:** Once you use a recovery code, you cannot re-use it. You can still
+ use the other recovery codes you saved.
### Generate new recovery codes using SSH
-It's not uncommon for users to forget to save the recovery codes when enabling
-two-factor authentication. If you have an SSH key added to your GitLab account,
-you can generate a new set of recovery codes using SSH.
-
-Run `ssh git@gitlab.example.com 2fa_recovery_codes`. You will be prompted to
-confirm that you wish to generate new codes. If you choose to continue, any
-previously saved codes will be invalidated.
-
-```bash
-$ ssh git@gitlab.example.com 2fa_recovery_codes
-Are you sure you want to generate new two-factor recovery codes?
-Any existing recovery codes you saved will be invalidated. (yes/no)
-yes
-
-Your two-factor authentication recovery codes are:
-
-119135e5a3ebce8e
-11f6v2a498810dcd
-3924c7ab2089c902
-e79a3398bfe4f224
-34bd7b74adbc8861
-f061691d5107df1a
-169bf32a18e63e7f
-b510e7422e81c947
-20dbed24c5e74663
-df9d3b9403b9c9f0
-
-During sign in, use one of the codes above when prompted for
-your two-factor code. Then, visit your Profile Settings and add
-a new device so you do not lose access to your account again.
-```
-
-Next, go to the GitLab sign in page and enter your username/email and password.
-When prompted for a two-factor code, enter one of the recovery codes obtained
-from the command line output.
-
-> **Note:** After signing in, you should immediately visit your **Profile Settings
- -> Account** to set up two-factor authentication with a new device.
-
-### Ask a GitLab administrator to disable two-factor on your account
-
-If the above two methods are not possible, you may ask a GitLab global
-administrator to disable two-factor authentication for your account. Please
-be aware that this will temporarily leave your account in a less secure state.
-You should sign in and re-enable two-factor authentication as soon as possible
-after the administrator disables it.
+Users often forget to save their recovery codes when enabling two-factor
+authentication. If an SSH key is added to your GitLab account, you can generate
+a new set of recovery codes with SSH.
+
+1. Run `ssh git@gitlab.example.com 2fa_recovery_codes`.
+2. You are prompted to confirm that you want to generate new codes. Continuing this process invalidates previously saved codes.
+ ```
+ bash
+ $ ssh git@gitlab.example.com 2fa_recovery_codes
+ Are you sure you want to generate new two-factor recovery codes?
+ Any existing recovery codes you saved will be invalidated. (yes/no)
+
+ yes
+
+ Your two-factor authentication recovery codes are:
+
+ 119135e5a3ebce8e
+ 11f6v2a498810dcd
+ 3924c7ab2089c902
+ e79a3398bfe4f224
+ 34bd7b74adbc8861
+ f061691d5107df1a
+ 169bf32a18e63e7f
+ b510e7422e81c947
+ 20dbed24c5e74663
+ df9d3b9403b9c9f0
+
+ During sign in, use one of the codes above when prompted for your
+ two-factor code. Then, visit your Profile Settings and add a new device
+ so you do not lose access to your account again.
+ ```
+3. Go to the GitLab sign-in page and enter your username/email and password. When prompted for a two-factor code, enter one of the recovery codes obtained
+from the command-line output.
+
+> **Note:** After signing in, visit your **Profile Settings -> Account** immediately to set up two-factor authentication with a new
+ device.
+
+### Ask a GitLab administrator to disable two-factor authentication on your account
+
+If you cannot use a saved recovery code or generate new recovery codes, ask a
+GitLab global administrator to disable two-factor authentication for your
+account. This will temporarily leave your account in a less secure state.
+Sign in and re-enable two-factor authentication as soon as possible.
## Note to GitLab administrators
diff --git a/lib/gitlab/ci/trace_reader.rb b/lib/gitlab/ci/trace_reader.rb
index 37e51536e8f..1d7ddeb3e0f 100644
--- a/lib/gitlab/ci/trace_reader.rb
+++ b/lib/gitlab/ci/trace_reader.rb
@@ -42,6 +42,7 @@ module Gitlab
end
chunks.join.lines.last(max_lines).join
+ .force_encoding(Encoding.default_external)
end
end
end
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 4ebd48a3fc7..e20f5f6f514 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -30,7 +30,7 @@ module Gitlab
end
def in_memory_application_settings
- @in_memory_application_settings ||= ::ApplicationSetting.new(::ApplicationSetting::DEFAULTS)
+ @in_memory_application_settings ||= ::ApplicationSetting.new(::ApplicationSetting.defaults)
# In case migrations the application_settings table is not created yet,
# we fallback to a simple OpenStruct
rescue ActiveRecord::StatementInvalid, ActiveRecord::UnknownAttributeError
@@ -38,7 +38,7 @@ module Gitlab
end
def fake_application_settings
- OpenStruct.new(::ApplicationSetting::DEFAULTS)
+ OpenStruct.new(::ApplicationSetting.defaults)
end
private
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/shell.rb
index 82e194c1af1..82e194c1af1 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/shell.rb
diff --git a/lib/gitlab/backend/shell_adapter.rb b/lib/gitlab/shell_adapter.rb
index fbe2a7a0d72..fbe2a7a0d72 100644
--- a/lib/gitlab/backend/shell_adapter.rb
+++ b/lib/gitlab/shell_adapter.rb
diff --git a/lib/gitlab/upgrader.rb b/lib/gitlab/upgrader.rb
index f3567f3ef85..e78d0c34a02 100644
--- a/lib/gitlab/upgrader.rb
+++ b/lib/gitlab/upgrader.rb
@@ -61,7 +61,7 @@ module Gitlab
"Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}),
"Install gems" => %W(bundle),
"Migrate DB" => %W(bundle exec rake db:migrate),
- "Recompile assets" => %W(bundle exec rake assets:clean assets:precompile),
+ "Recompile assets" => %W(bundle exec rake gitlab:assets:clean gitlab:assets:compile),
"Clear cache" => %W(bundle exec rake cache:clear)
}
end
diff --git a/lib/gitlab/view/presenter/base.rb b/lib/gitlab/view/presenter/base.rb
index 83c8ba5c1cf..dbfe0941e4d 100644
--- a/lib/gitlab/view/presenter/base.rb
+++ b/lib/gitlab/view/presenter/base.rb
@@ -1,6 +1,8 @@
module Gitlab
module View
module Presenter
+ CannotOverrideMethodError = Class.new(StandardError)
+
module Base
extend ActiveSupport::Concern
diff --git a/lib/gitlab/view/presenter/delegated.rb b/lib/gitlab/view/presenter/delegated.rb
index f4d330c590e..387ff0f5d43 100644
--- a/lib/gitlab/view/presenter/delegated.rb
+++ b/lib/gitlab/view/presenter/delegated.rb
@@ -8,6 +8,10 @@ module Gitlab
@subject = subject
attributes.each do |key, value|
+ if subject.respond_to?(key)
+ raise CannotOverrideMethodError.new("#{subject} already respond to #{key}!")
+ end
+
define_singleton_method(key) { value }
end
diff --git a/lib/support/deploy/deploy.sh b/lib/support/deploy/deploy.sh
index adea4c7a747..ab46c47d8f5 100755
--- a/lib/support/deploy/deploy.sh
+++ b/lib/support/deploy/deploy.sh
@@ -31,8 +31,8 @@ echo 'Deploy: Bundle and migrate'
sudo -u git -H bundle --without aws development test mysql --deployment
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
-sudo -u git -H bundle exec rake assets:clean RAILS_ENV=production
-sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
+sudo -u git -H bundle exec rake gitlab:assets:clean RAILS_ENV=production
+sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production
sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
# return stashed changes (if necessary)
diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake
new file mode 100644
index 00000000000..5d884bf9f66
--- /dev/null
+++ b/lib/tasks/gitlab/assets.rake
@@ -0,0 +1,47 @@
+namespace :gitlab do
+ namespace :assets do
+ desc 'GitLab | Assets | Compile all frontend assets'
+ task :compile do
+ Rake::Task['assets:precompile'].invoke
+ Rake::Task['gitlab:assets:fix_urls'].invoke
+ end
+
+ desc 'GitLab | Assets | Clean up old compiled frontend assets'
+ task :clean do
+ Rake::Task['assets:clean'].invoke
+ end
+
+ desc 'GitLab | Assets | Remove all compiled frontend assets'
+ task :purge do
+ Rake::Task['assets:clobber'].invoke
+ end
+
+ desc 'GitLab | Assets | Fix all absolute url references in CSS'
+ task :fix_urls do
+ css_files = Dir['public/assets/*.css']
+ css_files.each do | file |
+ # replace url(/assets/*) with url(./*)
+ puts "Fixing #{file}"
+ system "sed", "-i", "-e", 's/url(\([\"\']\?\)\/assets\//url(\1.\//g', file
+
+ # rewrite the corresponding gzip file (if it exists)
+ gzip = "#{file}.gz"
+ if File.exist?(gzip)
+ puts "Fixing #{gzip}"
+
+ FileUtils.rm(gzip)
+ mtime = File.stat(file).mtime
+
+ File.open(gzip, 'wb+') do |f|
+ gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
+ gz.mtime = mtime
+ gz.write IO.binread(file)
+ gz.close
+
+ File.utime(mtime, mtime, f.path)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb
new file mode 100644
index 00000000000..9dceeca168d
--- /dev/null
+++ b/spec/controllers/explore/projects_controller_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Explore::ProjectsController do
+ describe 'GET #trending' do
+ context 'sorting by update date' do
+ let(:project1) { create(:empty_project, :public, updated_at: 3.days.ago) }
+ let(:project2) { create(:empty_project, :public, updated_at: 1.day.ago) }
+
+ before do
+ create(:trending_project, project: project1)
+ create(:trending_project, project: project2)
+ end
+
+ it 'sorts by last updated' do
+ get :trending, sort: 'updated_desc'
+
+ expect(assigns(:projects)).to eq [project2, project1]
+ end
+
+ it 'sorts by oldest updated' do
+ get :trending, sort: 'updated_asc'
+
+ expect(assigns(:projects)).to eq [project1, project2]
+ end
+ end
+ end
+end
diff --git a/spec/factories/trending_project.rb b/spec/factories/trending_project.rb
new file mode 100644
index 00000000000..246176611dc
--- /dev/null
+++ b/spec/factories/trending_project.rb
@@ -0,0 +1,6 @@
+FactoryGirl.define do
+ # TrendingProject
+ factory :trending_project, class: 'TrendingProject' do
+ project
+ end
+end
diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index 8a155c3bfc5..93763f092fb 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -43,14 +43,6 @@ describe 'Dropdown assignee', js: true, feature: true do
expect(page).to have_css(js_dropdown_assignee, visible: true)
end
- it 'shows assigned to me link' do
- filtered_search.set('assignee:')
-
- page.within js_dropdown_assignee do
- expect(page).to have_content('Assigned to me')
- end
- end
-
it 'closes when the search bar is unfocused' do
find('body').click()
@@ -129,14 +121,6 @@ describe 'Dropdown assignee', js: true, feature: true do
filtered_search.set('assignee:')
end
- it 'filters by current user' do
- page.within js_dropdown_assignee do
- click_button 'Assigned to me'
- end
-
- expect(filtered_search.value).to eq("assignee:#{user.to_reference} ")
- end
-
it 'fills in the assignee username when the assignee has not been filtered' do
click_assignee(user_jacob.name)
@@ -185,4 +169,22 @@ describe 'Dropdown assignee', js: true, feature: true do
expect(page).to have_css(js_dropdown_assignee, visible: true)
end
end
+
+ describe 'caching requests' do
+ it 'caches requests after the first load' do
+ filtered_search.set('assignee')
+ send_keys_to_filtered_search(':')
+ initial_size = dropdown_assignee_size
+
+ expect(initial_size).to be > 0
+
+ new_user = create(:user)
+ project.team << [new_user, :master]
+ find('.filtered-search-input-container .clear-search').click
+ filtered_search.set('assignee')
+ send_keys_to_filtered_search(':')
+
+ expect(dropdown_assignee_size).to eq(initial_size)
+ end
+ end
end
diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb
index a5d5d9d4c5e..59e302f0e2d 100644
--- a/spec/features/issues/filtered_search/dropdown_author_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb
@@ -157,4 +157,22 @@ describe 'Dropdown author', js: true, feature: true do
expect(page).to have_css(js_dropdown_author, visible: true)
end
end
+
+ describe 'caching requests' do
+ it 'caches requests after the first load' do
+ filtered_search.set('author')
+ send_keys_to_filtered_search(':')
+ initial_size = dropdown_author_size
+
+ expect(initial_size).to be > 0
+
+ new_user = create(:user)
+ project.team << [new_user, :master]
+ find('.filtered-search-input-container .clear-search').click
+ filtered_search.set('author')
+ send_keys_to_filtered_search(':')
+
+ expect(dropdown_author_size).to eq(initial_size)
+ end
+ end
end
diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb
index f09ad2dd86b..5079eb8dd00 100644
--- a/spec/features/issues/filtered_search/dropdown_label_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb
@@ -249,4 +249,21 @@ describe 'Dropdown label', js: true, feature: true do
expect(page).to have_css(js_dropdown_label, visible: true)
end
end
+
+ describe 'caching requests' do
+ it 'caches requests after the first load' do
+ filtered_search.set('label')
+ send_keys_to_filtered_search(':')
+ initial_size = dropdown_label_size
+
+ expect(initial_size).to be > 0
+
+ create(:label, project: project)
+ find('.filtered-search-input-container .clear-search').click
+ filtered_search.set('label')
+ send_keys_to_filtered_search(':')
+
+ expect(dropdown_label_size).to eq(initial_size)
+ end
+ end
end
diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
index 134e58ad586..0ce16715b86 100644
--- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
@@ -219,4 +219,21 @@ describe 'Dropdown milestone', js: true, feature: true do
expect(page).to have_css(js_dropdown_milestone, visible: true)
end
end
+
+ describe 'caching requests' do
+ it 'caches requests after the first load' do
+ filtered_search.set('milestone')
+ send_keys_to_filtered_search(':')
+ initial_size = dropdown_milestone_size
+
+ expect(initial_size).to be > 0
+
+ create(:milestone, project: project)
+ find('.filtered-search-input-container .clear-search').click
+ filtered_search.set('milestone')
+ send_keys_to_filtered_search(':')
+
+ expect(dropdown_milestone_size).to eq(initial_size)
+ end
+ end
end
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index f48a0193545..3f70a6aa75f 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -773,7 +773,7 @@ describe 'Filter issues', js: true, feature: true do
describe 'RSS feeds' do
it 'updates atom feed link for project issues' do
visit namespace_project_issues_path(project.namespace, project, milestone_title: milestone.title, assignee_id: user.id)
- link = find('.nav-controls a', text: 'Subscribe')
+ link = find_link('Subscribe')
params = CGI.parse(URI.parse(link[:href]).query)
auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index bc068b5e7e0..1eb981942ea 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -2,6 +2,7 @@ require 'rails_helper'
feature 'Issue Sidebar', feature: true do
include WaitForAjax
+ include MobileHelpers
let(:project) { create(:project, :public) }
let(:issue) { create(:issue, project: project) }
@@ -59,6 +60,23 @@ feature 'Issue Sidebar', feature: true do
end
end
+ context 'sidebar', js: true do
+ it 'changes size when the screen size is smaller' do
+ sidebar_selector = 'aside.right-sidebar.right-sidebar-collapsed'
+ # Resize the window
+ resize_screen_sm
+ # Make sure the sidebar is collapsed
+ expect(page).to have_css(sidebar_selector)
+ # Once is collapsed let's open the sidebard and reload
+ open_issue_sidebar
+ refresh
+ expect(page).to have_css(sidebar_selector)
+ # Restore the window size as it was including the sidebar
+ restore_window_size
+ open_issue_sidebar
+ end
+ end
+
context 'creating a new label', js: true do
it 'shows option to crate a new label is present' do
page.within('.block.labels') do
@@ -109,4 +127,11 @@ feature 'Issue Sidebar', feature: true do
def visit_issue(project, issue)
visit namespace_project_issue_path(project.namespace, project, issue)
end
+
+ def open_issue_sidebar
+ page.within('aside.right-sidebar.right-sidebar-collapsed') do
+ find('.js-sidebar-toggle').click
+ sleep 1
+ end
+ end
end
diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb
index 55d5d082c6e..5d0314d5c09 100644
--- a/spec/features/projects/project_settings_spec.rb
+++ b/spec/features/projects/project_settings_spec.rb
@@ -37,7 +37,7 @@ describe 'Edit Project Settings', feature: true do
it 'shows errors for invalid project path/name' do
visit edit_namespace_project_path(project.namespace, project)
- fill_in 'Project name', with: 'foo&bar'
+ fill_in 'project_name', with: 'foo&bar'
fill_in 'Path', with: 'foo&bar'
click_button 'Rename project'
@@ -53,7 +53,7 @@ describe 'Edit Project Settings', feature: true do
it 'shows error for invalid project name' do
visit edit_namespace_project_path(project.namespace, project)
- fill_in 'Project name', with: '🚀 foo bar ☁️'
+ fill_in 'project_name', with: '🚀 foo bar ☁️'
click_button 'Rename project'
diff --git a/spec/javascripts/commits_spec.js.es6 b/spec/javascripts/commits_spec.js.es6
new file mode 100644
index 00000000000..bb9a9072f3a
--- /dev/null
+++ b/spec/javascripts/commits_spec.js.es6
@@ -0,0 +1,50 @@
+/* global CommitsList */
+
+//= require jquery.endless-scroll
+//= require pager
+//= require commits
+
+(() => {
+ describe('Commits List', () => {
+ beforeEach(() => {
+ setFixtures(`
+ <form class="commits-search-form" action="/h5bp/html5-boilerplate/commits/master">
+ <input id="commits-search">
+ </form>
+ <ol id="commits-list"></ol>
+ `);
+ });
+
+ it('should be defined', () => {
+ expect(CommitsList).toBeDefined();
+ });
+
+ describe('on entering input', () => {
+ let ajaxSpy;
+
+ beforeEach(() => {
+ CommitsList.init(25);
+ CommitsList.searchField.val('');
+ spyOn(history, 'replaceState').and.stub();
+ ajaxSpy = spyOn(jQuery, 'ajax').and.callFake((req) => {
+ req.success({
+ data: '<li>Result</li>',
+ });
+ });
+ });
+
+ it('should save the last search string', () => {
+ CommitsList.searchField.val('GitLab');
+ CommitsList.filterResults();
+ expect(ajaxSpy).toHaveBeenCalled();
+ expect(CommitsList.lastSearch).toEqual('GitLab');
+ });
+
+ it('should not make ajax call if the input does not change', () => {
+ CommitsList.filterResults();
+ expect(ajaxSpy).not.toHaveBeenCalled();
+ expect(CommitsList.lastSearch).toEqual('');
+ });
+ });
+ });
+})();
diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6
index 19bd8d53219..89e49b7c511 100644
--- a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6
+++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6
@@ -64,6 +64,68 @@
const updatedItem = gl.DropdownUtils.filterWithSymbol('@', input, item);
expect(updatedItem.droplab_hidden).toBe(false);
});
+
+ describe('filters multiple word title', () => {
+ const multipleWordItem = {
+ title: 'Community Contributions',
+ };
+
+ it('should filter with double quote', () => {
+ input.value = 'label:"';
+
+ const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
+ expect(updatedItem.droplab_hidden).toBe(false);
+ });
+
+ it('should filter with double quote and symbol', () => {
+ input.value = 'label:~"';
+
+ const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
+ expect(updatedItem.droplab_hidden).toBe(false);
+ });
+
+ it('should filter with double quote and multiple words', () => {
+ input.value = 'label:"community con';
+
+ const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
+ expect(updatedItem.droplab_hidden).toBe(false);
+ });
+
+ it('should filter with double quote, symbol and multiple words', () => {
+ input.value = 'label:~"community con';
+
+ const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
+ expect(updatedItem.droplab_hidden).toBe(false);
+ });
+
+ it('should filter with single quote', () => {
+ input.value = 'label:\'';
+
+ const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
+ expect(updatedItem.droplab_hidden).toBe(false);
+ });
+
+ it('should filter with single quote and symbol', () => {
+ input.value = 'label:~\'';
+
+ const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
+ expect(updatedItem.droplab_hidden).toBe(false);
+ });
+
+ it('should filter with single quote and multiple words', () => {
+ input.value = 'label:\'community con';
+
+ const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
+ expect(updatedItem.droplab_hidden).toBe(false);
+ });
+
+ it('should filter with single quote, symbol and multiple words', () => {
+ input.value = 'label:~\'community con';
+
+ const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
+ expect(updatedItem.droplab_hidden).toBe(false);
+ });
+ });
});
describe('filterHint', () => {
@@ -130,5 +192,99 @@
expect(result).toBe(false);
});
});
+
+ describe('getInputSelectionPosition', () => {
+ describe('word with trailing spaces', () => {
+ const value = 'label:none ';
+
+ it('should return selectionStart when cursor is at the trailing space', () => {
+ const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
+ selectionStart: 11,
+ value,
+ });
+
+ expect(left).toBe(11);
+ expect(right).toBe(11);
+ });
+
+ it('should return input when cursor is at the start of input', () => {
+ const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
+ selectionStart: 0,
+ value,
+ });
+
+ expect(left).toBe(0);
+ expect(right).toBe(10);
+ });
+
+ it('should return input when cursor is at the middle of input', () => {
+ const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
+ selectionStart: 7,
+ value,
+ });
+
+ expect(left).toBe(0);
+ expect(right).toBe(10);
+ });
+
+ it('should return input when cursor is at the end of input', () => {
+ const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
+ selectionStart: 10,
+ value,
+ });
+
+ expect(left).toBe(0);
+ expect(right).toBe(10);
+ });
+ });
+
+ describe('multiple words', () => {
+ const value = 'label:~"Community Contribution"';
+
+ it('should return input when cursor is after the first word', () => {
+ const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
+ selectionStart: 17,
+ value,
+ });
+
+ expect(left).toBe(0);
+ expect(right).toBe(31);
+ });
+
+ it('should return input when cursor is before the second word', () => {
+ const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
+ selectionStart: 18,
+ value,
+ });
+
+ expect(left).toBe(0);
+ expect(right).toBe(31);
+ });
+ });
+
+ describe('incomplete multiple words', () => {
+ const value = 'label:~"Community Contribution';
+
+ it('should return entire input when cursor is at the start of input', () => {
+ const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
+ selectionStart: 0,
+ value,
+ });
+
+ expect(left).toBe(0);
+ expect(right).toBe(30);
+ });
+
+ it('should return entire input when cursor is at the end of input', () => {
+ const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
+ selectionStart: 30,
+ value,
+ });
+
+ expect(left).toBe(0);
+ expect(right).toBe(30);
+ });
+ });
+ });
});
})();
diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6
new file mode 100644
index 00000000000..c8b5c2b36ad
--- /dev/null
+++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6
@@ -0,0 +1,68 @@
+/* global Turbolinks */
+
+//= require turbolinks
+//= require lib/utils/common_utils
+//= require filtered_search/filtered_search_token_keys
+//= require filtered_search/filtered_search_tokenizer
+//= require filtered_search/filtered_search_dropdown_manager
+//= require filtered_search/filtered_search_manager
+
+(() => {
+ describe('Filtered Search Manager', () => {
+ describe('search', () => {
+ let manager;
+ const defaultParams = '?scope=all&utf8=✓&state=opened';
+
+ function getInput() {
+ return document.querySelector('.filtered-search');
+ }
+
+ beforeEach(() => {
+ setFixtures(`
+ <input type='text' class='filtered-search' />
+ `);
+
+ spyOn(gl.FilteredSearchManager.prototype, 'bindEvents').and.callFake(() => {});
+ spyOn(gl.FilteredSearchManager.prototype, 'loadSearchParamsFromURL').and.callFake(() => {});
+ spyOn(gl.FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {});
+ spyOn(gl.utils, 'getParameterByName').and.returnValue(null);
+
+ manager = new gl.FilteredSearchManager();
+ });
+
+ afterEach(() => {
+ getInput().outerHTML = '';
+ });
+
+ it('should search with a single word', () => {
+ getInput().value = 'searchTerm';
+
+ spyOn(Turbolinks, 'visit').and.callFake((url) => {
+ expect(url).toEqual(`${defaultParams}&search=searchTerm`);
+ });
+
+ manager.search();
+ });
+
+ it('should search with multiple words', () => {
+ getInput().value = 'awesome search terms';
+
+ spyOn(Turbolinks, 'visit').and.callFake((url) => {
+ expect(url).toEqual(`${defaultParams}&search=awesome+search+terms`);
+ });
+
+ manager.search();
+ });
+
+ it('should search with special characters', () => {
+ getInput().value = '~!@#$%^&*()_+{}:<>,.?/';
+
+ spyOn(Turbolinks, 'visit').and.callFake((url) => {
+ expect(url).toEqual(`${defaultParams}&search=~!%40%23%24%25%5E%26*()_%2B%7B%7D%3A%3C%3E%2C.%3F%2F`);
+ });
+
+ manager.search();
+ });
+ });
+ });
+})();
diff --git a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6
index 6df7c0e44ef..9d9097419ea 100644
--- a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6
+++ b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6
@@ -72,6 +72,12 @@
const result = gl.FilteredSearchTokenKeys.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`);
expect(result).toEqual(tokenKeys[0]);
});
+
+ it('should return alternative tokenKey when found by key param', () => {
+ const tokenKeys = gl.FilteredSearchTokenKeys.getAlternatives();
+ const result = gl.FilteredSearchTokenKeys.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`);
+ expect(result).toEqual(tokenKeys[0]);
+ });
});
describe('searchByConditionUrl', () => {
diff --git a/spec/lib/gitlab/ci/trace_reader_spec.rb b/spec/lib/gitlab/ci/trace_reader_spec.rb
index f06d78694d6..ff5551bf703 100644
--- a/spec/lib/gitlab/ci/trace_reader_spec.rb
+++ b/spec/lib/gitlab/ci/trace_reader_spec.rb
@@ -11,13 +11,25 @@ describe Gitlab::Ci::TraceReader do
last_lines = random_lines
expected = lines.last(last_lines).join
+ result = subject.read(last_lines: last_lines)
- expect(subject.read(last_lines: last_lines)).to eq(expected)
+ expect(result).to eq(expected)
+ expect(result.encoding).to eq(Encoding.default_external)
end
end
it 'returns everything if trying to get too many lines' do
- expect(build_subject.read(last_lines: lines.size * 2)).to eq(lines.join)
+ result = build_subject.read(last_lines: lines.size * 2)
+
+ expect(result).to eq(lines.join)
+ expect(result.encoding).to eq(Encoding.default_external)
+ end
+
+ it 'returns all contents if last_lines is not specified' do
+ result = build_subject.read
+
+ expect(result).to eq(lines.join)
+ expect(result.encoding).to eq(Encoding.default_external)
end
it 'raises an error if not passing an integer for last_lines' do
diff --git a/spec/lib/gitlab/view/presenter/delegated_spec.rb b/spec/lib/gitlab/view/presenter/delegated_spec.rb
index 888ab80cad5..e9d4af54389 100644
--- a/spec/lib/gitlab/view/presenter/delegated_spec.rb
+++ b/spec/lib/gitlab/view/presenter/delegated_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::View::Presenter::Delegated do
- let(:project) { double(:project, bar: 'baz') }
+ let(:project) { double(:project, user: 'John Doe') }
let(:presenter_class) do
Class.new(described_class)
end
@@ -12,10 +12,14 @@ describe Gitlab::View::Presenter::Delegated do
describe '#initialize' do
it 'takes arbitrary key/values and exposes them' do
- presenter = presenter_class.new(project, user: 'user', foo: 'bar')
+ presenter = presenter_class.new(project, current_user: 'Jane Doe')
- expect(presenter.user).to eq('user')
- expect(presenter.foo).to eq('bar')
+ expect(presenter.current_user).to eq('Jane Doe')
+ end
+
+ it 'raise an error if the presentee already respond to method' do
+ expect { presenter_class.new(project, user: 'Jane Doe') }.
+ to raise_error Gitlab::View::Presenter::CannotOverrideMethodError
end
end
@@ -23,7 +27,7 @@ describe Gitlab::View::Presenter::Delegated do
it 'forwards missing methods to subject' do
presenter = presenter_class.new(project)
- expect(presenter.bar).to eq('baz')
+ expect(presenter.user).to eq('John Doe')
end
end
end
diff --git a/spec/lib/gitlab/view/presenter/factory_spec.rb b/spec/lib/gitlab/view/presenter/factory_spec.rb
index 55c5ecbf92f..70d2e22b48f 100644
--- a/spec/lib/gitlab/view/presenter/factory_spec.rb
+++ b/spec/lib/gitlab/view/presenter/factory_spec.rb
@@ -22,13 +22,6 @@ describe Gitlab::View::Presenter::Factory do
end
describe '#fabricate!' do
- it 'exposes given params' do
- presenter = described_class.new(build, user: 'user', foo: 'bar').fabricate!
-
- expect(presenter.user).to eq('user')
- expect(presenter.foo).to eq('bar')
- end
-
it 'detects the presenter based on the given subject' do
presenter = described_class.new(build).fabricate!
diff --git a/spec/lib/gitlab/view/presenter/simple_spec.rb b/spec/lib/gitlab/view/presenter/simple_spec.rb
index b489bdf1981..1795ed2405b 100644
--- a/spec/lib/gitlab/view/presenter/simple_spec.rb
+++ b/spec/lib/gitlab/view/presenter/simple_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::View::Presenter::Simple do
- let(:project) { double(:project) }
+ let(:project) { double(:project, user: 'John Doe') }
let(:presenter_class) do
Class.new(described_class)
end
@@ -12,10 +12,15 @@ describe Gitlab::View::Presenter::Simple do
describe '#initialize' do
it 'takes arbitrary key/values and exposes them' do
- presenter = presenter_class.new(project, user: 'user', foo: 'bar')
+ presenter = presenter_class.new(project, current_user: 'Jane Doe')
- expect(presenter.user).to eq('user')
- expect(presenter.foo).to eq('bar')
+ expect(presenter.current_user).to eq('Jane Doe')
+ end
+
+ it 'override the presentee attributes' do
+ presenter = presenter_class.new(project, user: 'Jane Doe')
+
+ expect(presenter.user).to eq('Jane Doe')
end
end
@@ -23,7 +28,7 @@ describe Gitlab::View::Presenter::Simple do
it 'does not forward missing methods to subject' do
presenter = presenter_class.new(project)
- expect { presenter.foo }.to raise_error(NoMethodError)
+ expect { presenter.user }.to raise_error(NoMethodError)
end
end
end
diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb
index 4d57efd3c53..2f4a33a1868 100644
--- a/spec/models/ability_spec.rb
+++ b/spec/models/ability_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Ability, lib: true do
describe '.can_edit_note?' do
let(:project) { create(:empty_project) }
- let!(:note) { create(:note_on_issue, project: project) }
+ let(:note) { create(:note_on_issue, project: project) }
context 'using an anonymous user' do
it 'returns false' do
@@ -60,7 +60,7 @@ describe Ability, lib: true do
describe '.users_that_can_read_project' do
context 'using a public project' do
it 'returns all the users' do
- project = create(:project, :public)
+ project = create(:empty_project, :public)
user = build(:user)
expect(described_class.users_that_can_read_project([user], project)).
@@ -69,7 +69,7 @@ describe Ability, lib: true do
end
context 'using an internal project' do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:empty_project, :internal) }
it 'returns users that are administrators' do
user = build(:user, admin: true)
@@ -120,7 +120,7 @@ describe Ability, lib: true do
end
context 'using a private project' do
- let(:project) { create(:project, :private) }
+ let(:project) { create(:empty_project, :private) }
it 'returns users that are administrators' do
user = build(:user, admin: true)
@@ -247,7 +247,7 @@ describe Ability, lib: true do
end
describe '.project_disabled_features_rules' do
- let(:project) { create(:project, wiki_access_level: ProjectFeature::DISABLED) }
+ let(:project) { create(:empty_project, wiki_access_level: ProjectFeature::DISABLED) }
subject { described_class.allowed(project.owner, project) }
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index f031876e812..47cd5075a7d 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Ci::Build, :models do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:test_trace) { 'This is a test' }
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 2bdd611aeed..426be74cd02 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -284,7 +284,7 @@ describe Ci::Pipeline, models: true do
end
describe 'merge request metrics' do
- let(:project) { FactoryGirl.create :project }
+ let(:project) { create(:project, :repository) }
let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) }
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: pipeline.ref) }
@@ -339,7 +339,7 @@ describe Ci::Pipeline, models: true do
end
context 'with non-empty project' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
@@ -890,7 +890,7 @@ describe Ci::Pipeline, models: true do
end
describe "#merge_requests" do
- let(:project) { FactoryGirl.create :project }
+ let(:project) { create(:project, :repository) }
let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) }
it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do
@@ -956,7 +956,7 @@ describe Ci::Pipeline, models: true do
end
describe 'notifications when pipeline success or failed' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 2b856ca7af7..3f32248e52b 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -91,8 +91,7 @@ describe Ci::Runner, models: true do
end
describe '#can_pick?' do
- let(:project) { create(:project) }
- let(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:pipeline) { create(:ci_pipeline) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:runner) { create(:ci_runner) }
@@ -321,8 +320,8 @@ describe Ci::Runner, models: true do
describe '.assignable_for' do
let(:runner) { create(:ci_runner) }
- let(:project) { create(:project) }
- let(:another_project) { create(:project) }
+ let(:project) { create(:empty_project) }
+ let(:another_project) { create(:empty_project) }
before do
project.runners << runner
diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb
index 30782ca75a0..e4bddf67096 100644
--- a/spec/models/commit_range_spec.rb
+++ b/spec/models/commit_range_spec.rb
@@ -7,7 +7,7 @@ describe CommitRange, models: true do
it { is_expected.to include_module(Referable) }
end
- let!(:project) { create(:project, :public) }
+ let!(:project) { create(:project, :public, :repository) }
let!(:commit1) { project.commit("HEAD~2") }
let!(:commit2) { project.commit }
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index b2202f0fd44..32f9366a14c 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Commit, models: true do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:commit) { project.commit }
describe 'modules' do
@@ -34,7 +34,7 @@ describe Commit, models: true do
end
describe '#to_reference' do
- let(:project) { create(:project, path: 'sample-project') }
+ let(:project) { create(:project, :repository, path: 'sample-project') }
let(:commit) { project.commit }
it 'returns a String reference to the object' do
@@ -42,13 +42,13 @@ describe Commit, models: true do
end
it 'supports a cross-project reference' do
- another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace)
expect(commit.to_reference(another_project)).to eq "sample-project@#{commit.id}"
end
end
describe '#reference_link_text' do
- let(:project) { create(:project, path: 'sample-project') }
+ let(:project) { create(:project, :repository, path: 'sample-project') }
let(:commit) { project.commit }
it 'returns a String reference to the object' do
@@ -56,7 +56,7 @@ describe Commit, models: true do
end
it 'supports a cross-project reference' do
- another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace)
expect(commit.reference_link_text(another_project)).to eq "sample-project@#{commit.short_id}"
end
end
@@ -131,7 +131,7 @@ eos
describe '#closes_issues' do
let(:issue) { create :issue, project: project }
- let(:other_project) { create :project, :public }
+ let(:other_project) { create(:empty_project, :public) }
let(:other_issue) { create :issue, project: other_project }
let(:commiter) { create :user }
@@ -154,7 +154,7 @@ eos
end
it_behaves_like 'a mentionable' do
- subject { create(:project).commit }
+ subject { create(:project, :repository).commit }
let(:author) { create(:user, email: subject.author_email) }
let(:backref_text) { "commit #{subject.id}" }
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 64ea607eb95..bf4394f7d5b 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe CommitStatus, models: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline, project: project, sha: project.commit.id)
diff --git a/spec/models/compare_spec.rb b/spec/models/compare_spec.rb
index 49ab3c4b6e9..da003dbf794 100644
--- a/spec/models/compare_spec.rb
+++ b/spec/models/compare_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Compare, models: true do
include RepoHelpers
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:commit) { project.commit }
let(:start_commit) { sample_image_commit }
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index d7d31892e12..545a11912e3 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -301,7 +301,7 @@ describe Issue, "Issuable" do
end
describe '#labels_array' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:bug) { create(:label, project: project, title: 'bug') }
let(:issue) { create(:issue, project: project) }
@@ -315,7 +315,7 @@ describe Issue, "Issuable" do
end
describe '#user_notes_count' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
@@ -359,7 +359,7 @@ describe Issue, "Issuable" do
end
describe ".with_label" do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:bug) { create(:label, project: project, title: 'bug') }
let(:feature) { create(:label, project: project, title: 'feature') }
let(:enhancement) { create(:label, project: project, title: 'enhancement') }
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index b73028f0bc0..2092576e981 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -13,7 +13,7 @@ describe Mentionable do
end
describe 'references' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:mentionable) { Example.new }
it 'excludes JIRA references' do
@@ -83,13 +83,13 @@ describe Issue, "Mentionable" do
end
describe '#create_cross_references!' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:author) { build(:user) }
let(:commit) { project.commit }
let(:commit2) { project.commit }
let!(:issue) do
- create(:issue, project: project, description: commit.to_reference)
+ create(:issue, project: project, description: "See #{commit.to_reference}")
end
it 'correctly removes already-mentioned Commits' do
@@ -100,7 +100,7 @@ describe Issue, "Mentionable" do
end
describe '#create_new_cross_references!' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:author) { create(:author) }
let(:issues) { create_list(:issue, 2, project: project, author: author) }
diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb
index 0e097559b59..ad703a6c8bb 100644
--- a/spec/models/concerns/milestoneish_spec.rb
+++ b/spec/models/concerns/milestoneish_spec.rb
@@ -7,7 +7,7 @@ describe Milestone, 'Milestoneish' do
let(:member) { create(:user) }
let(:guest) { create(:user) }
let(:admin) { create(:admin) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: project) }
let!(:issue) { create(:issue, project: project, milestone: milestone) }
let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone) }
diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb
index 9041690023f..6cf5877424d 100644
--- a/spec/models/concerns/project_features_compatibility_spec.rb
+++ b/spec/models/concerns/project_features_compatibility_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe ProjectFeaturesCompatibility do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:features) { %w(issues wiki builds merge_requests snippets) }
# We had issues_enabled, snippets_enabled, builds_enabled, merge_requests_enabled and issues_enabled fields on projects table
diff --git a/spec/models/cycle_analytics/code_spec.rb b/spec/models/cycle_analytics/code_spec.rb
index 70f985afefb..3b7cc7d9e2e 100644
--- a/spec/models/cycle_analytics/code_spec.rb
+++ b/spec/models/cycle_analytics/code_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#code', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb
index e4b6a8f4518..5c73edbbc53 100644
--- a/spec/models/cycle_analytics/issue_spec.rb
+++ b/spec/models/cycle_analytics/issue_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#issue', models: true do
extend CycleAnalyticsHelpers::TestGeneration
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
diff --git a/spec/models/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb
index dc5b04852d6..55483fc876a 100644
--- a/spec/models/cycle_analytics/plan_spec.rb
+++ b/spec/models/cycle_analytics/plan_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#plan', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb
index 5e99188f318..591bbdddf55 100644
--- a/spec/models/cycle_analytics/production_spec.rb
+++ b/spec/models/cycle_analytics/production_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#production', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
diff --git a/spec/models/cycle_analytics/review_spec.rb b/spec/models/cycle_analytics/review_spec.rb
index 45baa5f7006..33d2c0a7416 100644
--- a/spec/models/cycle_analytics/review_spec.rb
+++ b/spec/models/cycle_analytics/review_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#review', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb
index 77625aad580..00693d67475 100644
--- a/spec/models/cycle_analytics/staging_spec.rb
+++ b/spec/models/cycle_analytics/staging_spec.rb
@@ -3,9 +3,10 @@ require 'spec_helper'
describe 'CycleAnalytics#staging', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
+
subject { CycleAnalytics.new(project, from: from_date) }
generate_cycle_analytics_spec(
diff --git a/spec/models/cycle_analytics/test_spec.rb b/spec/models/cycle_analytics/test_spec.rb
index 27a117d2d76..f857ea6cbec 100644
--- a/spec/models/cycle_analytics/test_spec.rb
+++ b/spec/models/cycle_analytics/test_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#test', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb
index 8a1e337c1a3..aacc178a19e 100644
--- a/spec/models/deploy_keys_project_spec.rb
+++ b/spec/models/deploy_keys_project_spec.rb
@@ -12,7 +12,7 @@ describe DeployKeysProject, models: true do
end
describe "Destroying" do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
subject { create(:deploy_keys_project, project: project) }
let(:deploy_key) { subject.deploy_key }
@@ -39,7 +39,7 @@ describe DeployKeysProject, models: true do
end
context "when the deploy key is used by more than one project" do
- let!(:other_project) { create(:project) }
+ let!(:other_project) { create(:empty_project) }
before do
other_project.deploy_keys << deploy_key
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index ca594a320c0..fc4435a2f64 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -17,7 +17,7 @@ describe Deployment, models: true do
it { is_expected.to validate_presence_of(:sha) }
describe '#includes_commit?' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, project: project) }
let(:deployment) do
create(:deployment, environment: environment, sha: project.commit.id)
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index 3db5937a4f3..9ea3a4b7020 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
describe DiffNote, models: true do
include RepoHelpers
- let(:project) { create(:project) }
- let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:merge_request) { create(:merge_request) }
+ let(:project) { merge_request.project }
let(:commit) { project.commit(sample_commit.id) }
let(:path) { "files/ruby/popen.rb" }
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 96efe1696c3..b2e06541e66 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -32,7 +32,7 @@ describe Environment, models: true do
end
describe '#includes_commit?' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
context 'without a last deployment' do
it "returns false" do
@@ -81,7 +81,7 @@ describe Environment, models: true do
end
describe '#first_deployment_for' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) }
let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) }
let(:head_commit) { project.commit }
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index f8660da031d..349474bb656 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -27,7 +27,7 @@ describe Event, models: true do
end
describe "Push event" do
- let(:project) { create(:project, :private) }
+ let(:project) { create(:empty_project, :private) }
let(:user) { project.owner }
let(:event) { create_event(project, user) }
@@ -187,7 +187,7 @@ describe Event, models: true do
end
context 'merge request diff note event' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:merge_request) { create(:merge_request, source_project: project, author: author, assignee: assignee) }
let(:note_on_merge_request) { create(:legacy_diff_note_on_merge_request, noteable: merge_request, project: project) }
let(:target) { note_on_merge_request }
@@ -202,7 +202,7 @@ describe Event, models: true do
end
context 'private project' do
- let(:project) { create(:project, :private) }
+ let(:project) { create(:empty_project, :private) }
it do
expect(event.visible_to_user?(non_member)).to eq false
diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb
index 1863581f57b..454550c9710 100644
--- a/spec/models/forked_project_link_spec.rb
+++ b/spec/models/forked_project_link_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe ForkedProjectLink, "add link on fork" do
- let(:project_from) { create(:project) }
+ let(:project_from) { create(:project, :repository) }
let(:namespace) { create(:namespace) }
let(:user) { create(:user, namespace: namespace) }
@@ -21,7 +21,7 @@ end
describe '#forked?' do
let(:forked_project_link) { build(:forked_project_link) }
- let(:project_from) { create(:project) }
+ let(:project_from) { create(:project, :repository) }
let(:project_to) { create(:project, forked_project_link: forked_project_link) }
before :each do
diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb
index d87684fd49e..cacbab8bcb1 100644
--- a/spec/models/global_milestone_spec.rb
+++ b/spec/models/global_milestone_spec.rb
@@ -4,9 +4,9 @@ describe GlobalMilestone, models: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:group) { create(:group) }
- let(:project1) { create(:project, group: group) }
- let(:project2) { create(:project, path: 'gitlab-ci', group: group) }
- let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) }
+ let(:project1) { create(:empty_project, group: group) }
+ let(:project2) { create(:empty_project, path: 'gitlab-ci', group: group) }
+ let(:project3) { create(:empty_project, path: 'cookbook-gitlab', group: group) }
describe '.build_collection' do
let(:milestone1_due_date) { 2.weeks.from_now.to_date }
diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb
index 601167c3bd3..916afb7aaf5 100644
--- a/spec/models/group_milestone_spec.rb
+++ b/spec/models/group_milestone_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe GroupMilestone, models: true do
let(:group) { create(:group) }
- let(:project) { create(:project, group: group) }
+ let(:project) { create(:empty_project, group: group) }
let(:project_milestone) do
create(:milestone, title: "Milestone v1.2", project: project)
end
diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb
index d79f929f7a1..582b54c0712 100644
--- a/spec/models/guest_spec.rb
+++ b/spec/models/guest_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
describe Guest, lib: true do
- let(:public_project) { create(:project, :public) }
- let(:private_project) { create(:project, :private) }
- let(:internal_project) { create(:project, :internal) }
+ let(:public_project) { build_stubbed(:empty_project, :public) }
+ let(:private_project) { build_stubbed(:empty_project, :private) }
+ let(:internal_project) { build_stubbed(:empty_project, :internal) }
describe '.can_pull?' do
context 'when project is private' do
diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb
index ad2b710041a..e8caad00c44 100644
--- a/spec/models/hooks/system_hook_spec.rb
+++ b/spec/models/hooks/system_hook_spec.rb
@@ -4,7 +4,7 @@ describe SystemHook, models: true do
describe "execute" do
let(:system_hook) { create(:system_hook) }
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
let(:group) { create(:group) }
before do
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index e52b9d75cef..9d4db1bfb52 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -25,7 +25,7 @@ describe WebHook, models: true do
end
describe "execute" do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:project_hook) { create(:project_hook) }
before(:each) do
diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb
index 2459a49f095..08712f2a768 100644
--- a/spec/models/issue/metrics_spec.rb
+++ b/spec/models/issue/metrics_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Issue::Metrics, models: true do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
subject { create(:issue, project: project) }
diff --git a/spec/models/issue_collection_spec.rb b/spec/models/issue_collection_spec.rb
index d742c814680..d8aed25c041 100644
--- a/spec/models/issue_collection_spec.rb
+++ b/spec/models/issue_collection_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe IssueCollection do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
let(:collection) { described_class.new([issue1, issue2]) }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 61d72925736..40c0a75c364 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -35,7 +35,7 @@ describe Issue, models: true do
end
it 'supports a cross-project reference' do
- another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ another_project = build(:empty_project, name: 'another-project', namespace: project.namespace)
expect(issue.to_reference(another_project)).to eq "sample-project#1"
end
end
@@ -60,9 +60,9 @@ describe Issue, models: true do
end
describe '#closed_by_merge_requests' do
- let(:project) { create(:project) }
- let(:issue) { create(:issue, project: project, state: "opened")}
- let(:closed_issue) { build(:issue, project: project, state: "closed")}
+ let(:project) { create(:project, :repository) }
+ let(:issue) { create(:issue, project: project)}
+ let(:closed_issue) { build(:issue, :closed, project: project)}
let(:mr) do
opts = {
@@ -104,7 +104,7 @@ describe Issue, models: true do
describe '#referenced_merge_requests' do
it 'returns the referenced merge requests' do
- project = create(:project, :public)
+ project = create(:empty_project, :public)
mr1 = create(:merge_request,
source_project: project,
@@ -137,7 +137,7 @@ describe Issue, models: true do
end
context 'user is reporter in project issue belongs to' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
before { project.team << [user, :reporter] }
@@ -151,7 +151,7 @@ describe Issue, models: true do
context 'checking destination project also' do
subject { issue.can_move?(user, to_project) }
- let(:to_project) { create(:project) }
+ let(:to_project) { create(:empty_project) }
context 'destination project allowed' do
before { to_project.team << [user, :reporter] }
@@ -246,7 +246,7 @@ describe Issue, models: true do
describe '#participants' do
context 'using a public project' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project) }
let!(:note1) do
@@ -268,7 +268,7 @@ describe Issue, models: true do
context 'using a private project' do
it 'does not include mentioned users that do not have access to the project' do
- project = create(:project)
+ project = create(:empty_project)
user = create(:user)
issue = create(:issue, project: project)
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 4f7c8a36cb5..16e2144d6a1 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -481,7 +481,7 @@ describe Member, models: true do
describe "destroying a record", truncate: true do
it "refreshes user's authorized projects" do
- project = create(:project, :private)
+ project = create(:empty_project, :private)
user = create(:user)
member = project.team << [user, :reporter]
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index 68f72f5c86e..90d14c2c0b9 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -83,8 +83,8 @@ describe ProjectMember, models: true do
describe '.import_team' do
before do
- @project_1 = create :project
- @project_2 = create :project
+ @project_1 = create(:empty_project)
+ @project_2 = create(:empty_project)
@user_1 = create :user
@user_2 = create :user
@@ -131,8 +131,8 @@ describe ProjectMember, models: true do
describe '.truncate_teams' do
before do
- @project_1 = create :project
- @project_2 = create :project
+ @project_1 = create(:empty_project)
+ @project_2 = create(:empty_project)
@user_1 = create :user
@user_2 = create :user
diff --git a/spec/models/merge_request/metrics_spec.rb b/spec/models/merge_request/metrics_spec.rb
index 255db41cb19..9afed311e27 100644
--- a/spec/models/merge_request/metrics_spec.rb
+++ b/spec/models/merge_request/metrics_spec.rb
@@ -1,9 +1,7 @@
require 'spec_helper'
describe MergeRequest::Metrics, models: true do
- let(:project) { create(:project) }
-
- subject { create(:merge_request, source_project: project) }
+ subject { create(:merge_request) }
describe "when recording the default set of metrics on merge request save" do
it "records the merge time" do
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 064f29d2d66..3cee2b7714f 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -24,7 +24,7 @@ describe Milestone, models: true do
it { is_expected.to have_many(:issues) }
end
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: project) }
let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
@@ -44,7 +44,7 @@ describe Milestone, models: true do
end
it "accepts the same title in another project" do
- project = build(:project)
+ project = build(:empty_project)
new_milestone = Milestone.new(project: project, title: milestone.title)
expect(new_milestone).to be_valid
@@ -257,7 +257,7 @@ describe Milestone, models: true do
end
it 'supports a cross-project reference' do
- another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ another_project = build(:empty_project, name: 'another-project', namespace: project.namespace)
expect(milestone.to_reference(another_project)).to eq "sample-project%1"
end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 8d613a88ca0..4e96f19eb6f 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -107,7 +107,7 @@ describe Namespace, models: true do
describe '#move_dir' do
before do
@namespace = create :namespace
- @project = create :project, namespace: @namespace
+ @project = create(:empty_project, namespace: @namespace)
allow(@namespace).to receive(:path_changed?).and_return(true)
end
@@ -139,7 +139,7 @@ describe Namespace, models: true do
end
describe :rm_dir do
- let!(:project) { create(:project, namespace: namespace) }
+ let!(:project) { create(:empty_project, namespace: namespace) }
let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) }
it "removes its dirs when deleted" do
diff --git a/spec/models/network/graph_spec.rb b/spec/models/network/graph_spec.rb
index b76513d2a3c..492c4e01bd8 100644
--- a/spec/models/network/graph_spec.rb
+++ b/spec/models/network/graph_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Network::Graph, models: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let!(:note_on_commit) { create(:note_on_commit, project: project) }
it '#initialize' do
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 6f9ae655fed..1cde9e04951 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -42,7 +42,7 @@ describe Note, models: true do
context 'when noteable and note project differ' do
subject do
build(:note, noteable: build_stubbed(:issue),
- project: build_stubbed(:project))
+ project: build_stubbed(:empty_project))
end
it { is_expected.to be_invalid }
@@ -93,8 +93,8 @@ describe Note, models: true do
describe 'authorization' do
before do
- @p1 = create(:project)
- @p2 = create(:project)
+ @p1 = create(:empty_project)
+ @p2 = create(:empty_project)
@u1 = create(:user)
@u2 = create(:user)
@u3 = create(:user)
@@ -191,10 +191,10 @@ describe Note, models: true do
describe "cross_reference_not_visible_for?" do
let(:private_user) { create(:user) }
- let(:private_project) { create(:project, namespace: private_user.namespace).tap { |p| p.team << [private_user, :master] } }
+ let(:private_project) { create(:empty_project, namespace: private_user.namespace) { |p| p.team << [private_user, :master] } }
let(:private_issue) { create(:issue, project: private_project) }
- let(:ext_proj) { create(:project, :public) }
+ let(:ext_proj) { create(:empty_project, :public) }
let(:ext_issue) { create(:issue, project: ext_proj) }
let(:note) do
@@ -237,7 +237,7 @@ describe Note, models: true do
describe '#participants' do
it 'includes the note author' do
- project = create(:project, :public)
+ project = create(:empty_project, :public)
issue = create(:issue, project: project)
note = create(:note_on_issue, noteable: issue, project: project)
diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb
index a55d43ab2f9..8589f1eb712 100644
--- a/spec/models/project_feature_spec.rb
+++ b/spec/models/project_feature_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe ProjectFeature do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:user) { create(:user) }
describe '#feature_available?' do
@@ -35,7 +35,7 @@ describe ProjectFeature do
it "returns true when user is a member of project group" do
group = create(:group)
- project = create(:project, namespace: group)
+ project = create(:empty_project, namespace: group)
group.add_developer(user)
features.each do |feature|
diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb
index 47397a822c1..59a4ae1b799 100644
--- a/spec/models/project_group_link_spec.rb
+++ b/spec/models/project_group_link_spec.rb
@@ -17,7 +17,7 @@ describe ProjectGroupLink do
describe "destroying a record", truncate: true do
it "refreshes group users' authorized projects" do
- project = create(:project, :private)
+ project = create(:empty_project, :private)
group = create(:group)
reporter = create(:user)
group_users = group.users
diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb
index 4d538cac007..9cdbfa44e5b 100644
--- a/spec/models/project_label_spec.rb
+++ b/spec/models/project_label_spec.rb
@@ -100,7 +100,7 @@ describe ProjectLabel, models: true do
end
context 'cross project reference' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
context 'using name' do
it 'returns cross reference with label name' do
diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb
index 8e5145e824b..48aef3a93f2 100644
--- a/spec/models/project_services/asana_service_spec.rb
+++ b/spec/models/project_services/asana_service_spec.rb
@@ -18,7 +18,7 @@ describe AsanaService, models: true do
describe 'Execute' do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
def create_data_for_commits(*messages)
{
diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb
index 4c5acb7990b..96f00af898e 100644
--- a/spec/models/project_services/assembla_service_spec.rb
+++ b/spec/models/project_services/assembla_service_spec.rb
@@ -8,7 +8,7 @@ describe AssemblaService, models: true do
describe "Execute" do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
@assembla_service = AssemblaService.new
diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb
index a3b9d084a75..953e664fb66 100644
--- a/spec/models/project_services/campfire_service_spec.rb
+++ b/spec/models/project_services/campfire_service_spec.rb
@@ -22,7 +22,7 @@ describe CampfireService, models: true do
describe "#execute" do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
@campfire_service = CampfireService.new
diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb
index 42c2ed668bc..f9307d6de7b 100644
--- a/spec/models/project_services/drone_ci_service_spec.rb
+++ b/spec/models/project_services/drone_ci_service_spec.rb
@@ -27,7 +27,7 @@ describe DroneCiService, models: true, caching: true do
shared_context :drone_ci_service do
let(:drone) { DroneCiService.new }
- let(:project) { create(:project, name: 'project') }
+ let(:project) { create(:project, :repository, name: 'project') }
let(:path) { "#{project.namespace.path}/#{project.path}" }
let(:drone_url) { 'http://drone.example.com' }
let(:sha) { '2ab7834c' }
diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb
index 342d86aeca9..bdeea1db1e3 100644
--- a/spec/models/project_services/external_wiki_service_spec.rb
+++ b/spec/models/project_services/external_wiki_service_spec.rb
@@ -23,7 +23,7 @@ describe ExternalWikiService, models: true do
end
describe 'External wiki' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
context 'when it is active' do
before do
diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb
index d6db02d6e76..a97e8c6e4ce 100644
--- a/spec/models/project_services/flowdock_service_spec.rb
+++ b/spec/models/project_services/flowdock_service_spec.rb
@@ -22,7 +22,7 @@ describe FlowdockService, models: true do
describe "Execute" do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
@flowdock_service = FlowdockService.new
diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb
index 529044d1d8b..a13fbae03eb 100644
--- a/spec/models/project_services/gemnasium_service_spec.rb
+++ b/spec/models/project_services/gemnasium_service_spec.rb
@@ -24,7 +24,7 @@ describe GemnasiumService, models: true do
describe "Execute" do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
@gemnasium_service = GemnasiumService.new
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index 9b80f0e7296..dcb70ee28a8 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -8,21 +8,21 @@ describe GitlabIssueTrackerService, models: true do
describe 'Validations' do
context 'when service is active' do
- subject { described_class.new(project: create(:project), active: true) }
+ subject { described_class.new(project: create(:empty_project), active: true) }
it { is_expected.to validate_presence_of(:issues_url) }
it_behaves_like 'issue tracker service URL attribute', :issues_url
end
context 'when service is inactive' do
- subject { described_class.new(project: create(:project), active: false) }
+ subject { described_class.new(project: create(:empty_project), active: false) }
it { is_expected.not_to validate_presence_of(:issues_url) }
end
end
describe 'project and issue urls' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
context 'with absolute urls' do
before do
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index 2da3a9cb09f..bf422ac7ce1 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -22,8 +22,8 @@ describe HipchatService, models: true do
describe "Execute" do
let(:hipchat) { HipchatService.new }
- let(:user) { create(:user, username: 'username') }
- let(:project) { create(:project, name: 'project') }
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
let(:api_url) { 'https://hipchat.example.com/v2/room/123456/notification?auth_token=verySecret' }
let(:project_name) { project.name_with_namespace.gsub(/\s/, '') }
let(:token) { 'verySecret' }
@@ -165,7 +165,7 @@ describe HipchatService, models: true do
context "Note events" do
let(:user) { create(:user) }
- let(:project) { create(:project, creator_id: user.id) }
+ let(:project) { create(:project, :repository, creator: user) }
context 'when commit comment event triggered' do
let(:commit_note) do
diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb
index f8c45b37561..b9fb6f3f6f4 100644
--- a/spec/models/project_services/irker_service_spec.rb
+++ b/spec/models/project_services/irker_service_spec.rb
@@ -25,7 +25,7 @@ describe IrkerService, models: true do
describe 'Execute' do
let(:irker) { IrkerService.new }
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:sample_data) do
Gitlab::DataBuilder::Push.build_sample(project, user)
end
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 862e3a72a73..2f6b159d76e 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -71,7 +71,7 @@ describe JiraService, models: true do
describe '#close_issue' do
let(:custom_base_url) { 'http://custom_url' }
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:merge_request) { create(:merge_request) }
before do
@@ -207,12 +207,12 @@ describe JiraService, models: true do
end
describe "Stored password invalidation" do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
context "when a password was previously set" do
before do
@jira_service = JiraService.create!(
- project: create(:project),
+ project: project,
properties: {
url: 'http://jira.example.com/rest/api/2',
username: 'mic',
@@ -252,7 +252,7 @@ describe JiraService, models: true do
context "when no password was previously set" do
before do
@jira_service = JiraService.create(
- project: create(:project),
+ project: project,
properties: {
url: 'http://jira.example.com/rest/api/2',
username: 'mic'
@@ -281,7 +281,7 @@ describe JiraService, models: true do
end
describe 'description and title' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
context 'when it is not set' do
before do
@@ -316,7 +316,7 @@ describe JiraService, models: true do
end
describe 'project and issue urls' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
context 'when gitlab.yml was initialized' do
before do
diff --git a/spec/models/project_services/pipeline_email_service_spec.rb b/spec/models/project_services/pipeline_email_service_spec.rb
index 7c8824485f5..03932895b0e 100644
--- a/spec/models/project_services/pipeline_email_service_spec.rb
+++ b/spec/models/project_services/pipeline_email_service_spec.rb
@@ -7,7 +7,7 @@ describe PipelinesEmailService do
create(:ci_pipeline, project: project, sha: project.commit('master').sha)
end
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:recipient) { 'test@gitlab.com' }
let(:data) do
diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb
index 8fc92a9ab51..a7e7594a7d5 100644
--- a/spec/models/project_services/pushover_service_spec.rb
+++ b/spec/models/project_services/pushover_service_spec.rb
@@ -27,7 +27,7 @@ describe PushoverService, models: true do
describe 'Execute' do
let(:pushover) { PushoverService.new }
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:sample_data) do
Gitlab::DataBuilder::Push.build_sample(project, user)
end
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 0475cecaa2d..942eeab251d 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -265,10 +265,10 @@ describe ProjectTeam, models: true do
let(:group) { create(:group) }
let(:developer) { create(:user) }
let(:master) { create(:user) }
- let(:personal_project) { create(:project, namespace: developer.namespace) }
- let(:group_project) { create(:project, namespace: group) }
- let(:members_project) { create(:project) }
- let(:shared_project) { create(:project) }
+ let(:personal_project) { create(:empty_project, namespace: developer.namespace) }
+ let(:group_project) { create(:empty_project, namespace: group) }
+ let(:members_project) { create(:empty_project) }
+ let(:shared_project) { create(:empty_project) }
before do
group.add_master(master)
@@ -330,7 +330,7 @@ describe ProjectTeam, models: true do
reporter = create(:user)
promoted_guest = create(:user)
guest = create(:user)
- project = create(:project)
+ project = create(:empty_project)
project.add_master(master)
project.add_reporter(reporter)
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 99ca53938c8..829b69093c9 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -4,7 +4,7 @@ describe Repository, models: true do
include RepoHelpers
TestBlob = Struct.new(:name)
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
@@ -90,6 +90,30 @@ describe Repository, models: true do
it { is_expected.to eq(['v1.1.0', 'v1.0.0']) }
end
+
+ context 'annotated tag pointing to a blob' do
+ let(:annotated_tag_name) { 'annotated-tag' }
+
+ subject { repository.tags_sorted_by('updated_asc').map(&:name) }
+
+ before do
+ options = { message: 'test tag message\n',
+ tagger: { name: 'John Smith', email: 'john@gmail.com' } }
+ repository.rugged.tags.create(annotated_tag_name, 'a48e4fc218069f68ef2e769dd8dfea3991362175', options)
+
+ double_first = double(committed_date: Time.now - 1.second)
+ double_last = double(committed_date: Time.now)
+
+ allow(tag_a).to receive(:dereferenced_target).and_return(double_last)
+ allow(tag_b).to receive(:dereferenced_target).and_return(double_first)
+ end
+
+ it { is_expected.to eq(['v1.1.0', 'v1.0.0', annotated_tag_name]) }
+
+ after do
+ repository.rugged.tags.delete(annotated_tag_name)
+ end
+ end
end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 691511cd93f..0e2f07e945f 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -12,7 +12,7 @@ describe Service, models: true do
end
describe "Testable" do
- let(:project) { create :project }
+ let(:project) { create(:project, :repository) }
before do
allow(@service).to receive(:project).and_return(project)
@@ -35,7 +35,7 @@ describe Service, models: true do
end
describe "With commits" do
- let(:project) { create :project }
+ let(:project) { create(:project, :repository) }
before do
allow(@service).to receive(:project).and_return(project)
@@ -60,7 +60,7 @@ describe Service, models: true do
api_key: '123456789'
})
end
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
describe 'is prefilled for projects pushover service' do
it "has all fields prefilled" do
@@ -79,7 +79,7 @@ describe Service, models: true do
describe "{property}_changed?" do
let(:service) do
BambooService.create(
- project: create(:project),
+ project: create(:empty_project),
properties: {
bamboo_url: 'http://gitlab.com',
username: 'mic',
@@ -119,7 +119,7 @@ describe Service, models: true do
describe "{property}_touched?" do
let(:service) do
BambooService.create(
- project: create(:project),
+ project: create(:empty_project),
properties: {
bamboo_url: 'http://gitlab.com',
username: 'mic',
@@ -159,7 +159,7 @@ describe Service, models: true do
describe "{property}_was" do
let(:service) do
BambooService.create(
- project: create(:project),
+ project: create(:empty_project),
properties: {
bamboo_url: 'http://gitlab.com',
username: 'mic',
@@ -199,7 +199,7 @@ describe Service, models: true do
describe 'initialize service with no properties' do
let(:service) do
GitlabIssueTrackerService.create(
- project: create(:project),
+ project: create(:empty_project),
title: 'random title'
)
end
@@ -214,7 +214,7 @@ describe Service, models: true do
end
describe "callbacks" do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let!(:service) do
RedmineService.new(
project: project,
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 7425a897769..219ab1989ea 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -42,7 +42,7 @@ describe Snippet, models: true do
end
it 'supports a cross-project reference' do
- another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ another_project = build(:empty_project, name: 'another-project', namespace: project.namespace)
expect(snippet.to_reference(another_project)).to eq "sample-project$1"
end
end
@@ -55,7 +55,7 @@ describe Snippet, models: true do
end
it 'still returns shortest reference when project arg present' do
- another_project = build(:project, name: 'another-project')
+ another_project = build(:empty_project, name: 'another-project')
expect(snippet.to_reference(another_project)).to eq "$1"
end
end
@@ -173,7 +173,7 @@ describe Snippet, models: true do
end
describe '#participants' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:snippet) { create(:snippet, content: 'foo', project: project) }
let!(:note1) do
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index 623b82c01d8..8017d1c3324 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe Todo, models: true do
- let(:project) { create(:project) }
- let(:commit) { project.commit }
let(:issue) { create(:issue) }
describe 'relationships' do
@@ -82,6 +80,9 @@ describe Todo, models: true do
describe '#target' do
context 'for commits' do
+ let(:project) { create(:project, :repository) }
+ let(:commit) { project.commit }
+
it 'returns an instance of Commit when exists' do
subject.project = project
subject.target_type = 'Commit'
@@ -109,6 +110,9 @@ describe Todo, models: true do
describe '#target_reference' do
it 'returns the short commit id for commits' do
+ project = create(:project, :repository)
+ commit = project.commit
+
subject.project = project
subject.target_type = 'Commit'
subject.commit_id = commit.id
diff --git a/spec/models/tree_spec.rb b/spec/models/tree_spec.rb
index 0737999e125..a87983b7492 100644
--- a/spec/models/tree_spec.rb
+++ b/spec/models/tree_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Tree, models: true do
- let(:repository) { create(:project).repository }
+ let(:repository) { create(:project, :repository).repository }
let(:sha) { repository.root_ref }
subject { described_class.new(repository, '54fcc214') }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 0adfc30fe58..6ca5ad747d1 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1382,14 +1382,14 @@ describe User, models: true do
let!(:user) { create(:user) }
let!(:group) { create(:group) }
let!(:nested_group) { create(:group, parent: group) }
- let!(:project) { create(:project, namespace: group) }
- let!(:nested_project) { create(:project, namespace: nested_group) }
+ let!(:project) { create(:empty_project, namespace: group) }
+ let!(:nested_project) { create(:empty_project, namespace: nested_group) }
before do
group.add_owner(user)
# Add more data to ensure method does not include wrong projects
- other_project = create(:project, namespace: create(:group, :nested))
+ other_project = create(:empty_project, namespace: create(:group, :nested))
other_project.add_developer(create(:user))
end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 2878e0cb59b..5a3ffc284f2 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -6,7 +6,7 @@ describe API::Branches, api: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
- let!(:project) { create(:project, creator_id: user.id) }
+ let!(:project) { create(:project, :repository, creator: user) }
let!(:master) { create(:project_member, :master, user: user, project: project) }
let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
let!(:branch_name) { 'feature' }
diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb
index 7be7acebb19..645e36683bc 100644
--- a/spec/requests/api/builds_spec.rb
+++ b/spec/requests/api/builds_spec.rb
@@ -5,7 +5,7 @@ describe API::Builds, api: true do
let(:user) { create(:user) }
let(:api_user) { user }
- let!(:project) { create(:project, creator_id: user.id, public_builds: false) }
+ let!(:project) { create(:project, :repository, creator: user, public_builds: false) }
let!(:developer) { create(:project_member, :developer, user: user, project: project) }
let(:reporter) { create(:project_member, :reporter, project: project) }
let(:guest) { create(:project_member, :guest, project: project) }
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index c1c7c0882de..88361def3cf 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe API::CommitStatuses, api: true do
include ApiHelpers
- let!(:project) { create(:project) }
+ let!(:project) { create(:project, :repository) }
let(:commit) { project.repository.commit }
let(:commit_status) { create(:commit_status, pipeline: pipeline) }
let(:guest) { create_user(:guest) }
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 7f8ea5251f0..af9028a8978 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -5,7 +5,7 @@ describe API::Commits, api: true do
include ApiHelpers
let(:user) { create(:user) }
let(:user2) { create(:user) }
- let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
+ let!(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
let!(:master) { create(:project_member, :master, user: user, project: project) }
let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index 685da28c673..5e26e779366 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
describe API::Files, api: true do
include ApiHelpers
let(:user) { create(:user) }
- let!(:project) { create(:project, namespace: user.namespace ) }
- let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } }
+ let!(:project) { create(:project, :repository, namespace: user.namespace ) }
+ let(:guest) { create(:user) { |u| project.add_guest(u) } }
let(:file_path) { 'files/ruby/popen.rb' }
let(:params) do
{
diff --git a/spec/requests/api/fork_spec.rb b/spec/requests/api/fork_spec.rb
index df29099bc2f..92ac4fd334d 100644
--- a/spec/requests/api/fork_spec.rb
+++ b/spec/requests/api/fork_spec.rb
@@ -4,7 +4,6 @@ describe API::Projects, api: true do
include ApiHelpers
let(:user) { create(:user) }
let(:user2) { create(:user) }
- let(:user3) { create(:user) }
let(:admin) { create(:admin) }
let(:group) { create(:group) }
let(:group2) do
@@ -13,17 +12,14 @@ describe API::Projects, api: true do
group
end
- let(:project) do
- create(:project, creator_id: user.id, namespace: user.namespace)
- end
-
- let(:project_user2) do
- create(:project_member, :reporter, user: user2, project: project)
- end
-
describe 'POST /projects/fork/:id' do
- before { project_user2 }
- before { user3 }
+ let(:project) do
+ create(:project, :repository, creator: user, namespace: user.namespace)
+ end
+
+ before do
+ project.add_reporter(user2)
+ end
context 'when authenticated' do
it 'forks if user has sufficient access to project' do
@@ -49,7 +45,8 @@ describe API::Projects, api: true do
end
it 'fails on missing project access for the project to fork' do
- post api("/projects/fork/#{project.id}", user3)
+ new_user = create(:user)
+ post api("/projects/fork/#{project.id}", new_user)
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Project Not Found')
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 91202244227..ffeacb15f17 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -4,7 +4,7 @@ describe API::Internal, api: true do
include ApiHelpers
let(:user) { create(:user) }
let(:key) { create(:key, user: user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:secret_token) { Gitlab::Shell.secret_token }
describe "GET /internal/check", no_db: true do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 71a7994e544..21a2c583aa8 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -6,12 +6,10 @@ describe API::MergeRequests, api: true do
let(:user) { create(:user) }
let(:admin) { create(:user, :admin) }
let(:non_member) { create(:user) }
- let!(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace) }
- let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) }
- let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) }
- let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') }
- let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
- let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
+ let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) }
+ let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, title: "Test", created_at: base_time) }
+ let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, title: "Closed test", created_at: base_time + 1.second) }
+ let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') }
let(:milestone) { create(:milestone, title: '1.0.0', project: project) }
before do
@@ -556,11 +554,12 @@ describe API::MergeRequests, api: true do
original_count = merge_request.notes.size
post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user), note: "My comment"
+
expect(response).to have_http_status(201)
expect(json_response['note']).to eq('My comment')
expect(json_response['author']['name']).to eq(user.name)
expect(json_response['author']['username']).to eq(user.username)
- expect(merge_request.notes.size).to eq(original_count + 1)
+ expect(merge_request.reload.notes.size).to eq(original_count + 1)
end
it "returns 400 if note is missing" do
@@ -576,6 +575,9 @@ describe API::MergeRequests, api: true do
end
describe "GET :id/merge_requests/:merge_request_id/comments" do
+ let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
+ let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
+
it "returns merge_request comments ordered by created_at" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user)
expect(response).to have_http_status(200)
diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb
index 9a01f7fa1c4..b7a0b5a9e13 100644
--- a/spec/requests/api/pipelines_spec.rb
+++ b/spec/requests/api/pipelines_spec.rb
@@ -5,7 +5,7 @@ describe API::Pipelines, api: true do
let(:user) { create(:user) }
let(:non_member) { create(:user) }
- let(:project) { create(:project, creator_id: user.id) }
+ let(:project) { create(:project, :repository, creator: user) }
let!(:pipeline) do
create(:ci_empty_pipeline, project: project, sha: project.commit.id,
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index cc5c532de83..a1db81ce18c 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -17,6 +17,7 @@ describe API::Projects, api: true do
let(:project3) do
create(:project,
:private,
+ :repository,
name: 'second_project',
path: 'second_project',
creator_id: user.id,
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 0b19fa38c55..c61208e395c 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -8,7 +8,7 @@ describe API::Repositories, api: true do
let(:user) { create(:user) }
let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } }
- let!(:project) { create(:project, creator_id: user.id) }
+ let!(:project) { create(:project, :repository, creator: user) }
let!(:master) { create(:project_member, :master, user: user, project: project) }
describe "GET /projects/:id/repository/tree" do
@@ -74,7 +74,7 @@ describe API::Repositories, api: true do
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository tree' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
@@ -144,7 +144,7 @@ describe API::Repositories, api: true do
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository blob' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
@@ -198,7 +198,7 @@ describe API::Repositories, api: true do
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository raw blob' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
@@ -273,7 +273,7 @@ describe API::Repositories, api: true do
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository archive' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
@@ -347,7 +347,7 @@ describe API::Repositories, api: true do
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository compare' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
@@ -394,7 +394,7 @@ describe API::Repositories, api: true do
context 'when unauthenticated', 'and project is public' do
it_behaves_like 'repository contributors' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index a1c32ae65ba..898d2b27e5c 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -7,7 +7,7 @@ describe API::Tags, api: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
- let!(:project) { create(:project, creator_id: user.id) }
+ let!(:project) { create(:project, :repository, creator: user) }
let!(:master) { create(:project_member, :master, user: user, project: project) }
let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
@@ -29,7 +29,7 @@ describe API::Tags, api: true do
context 'when unauthenticated' do
it_behaves_like 'repository tags' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
@@ -88,7 +88,7 @@ describe API::Tags, api: true do
context 'when unauthenticated' do
it_behaves_like 'repository tag' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb
index cd01283b655..84104aa66ee 100644
--- a/spec/requests/api/triggers_spec.rb
+++ b/spec/requests/api/triggers_spec.rb
@@ -7,7 +7,7 @@ describe API::Triggers do
let(:user2) { create(:user) }
let!(:trigger_token) { 'secure_token' }
let!(:trigger_token_2) { 'secure_token_2' }
- let!(:project) { create(:project, creator_id: user.id) }
+ let!(:project) { create(:project, :repository, creator: user) }
let!(:master) { create(:project_member, :master, user: user, project: project) }
let!(:developer) { create(:project_member, :developer, user: user2, project: project) }
let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) }
diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb
index 2d434ab5dd8..a30be767119 100644
--- a/spec/requests/ci/api/triggers_spec.rb
+++ b/spec/requests/ci/api/triggers_spec.rb
@@ -5,9 +5,9 @@ describe Ci::API::Triggers do
describe 'POST /projects/:project_id/refs/:ref/trigger' do
let!(:trigger_token) { 'secure token' }
- let!(:project) { FactoryGirl.create(:project, ci_id: 10) }
- let!(:project2) { FactoryGirl.create(:empty_project, ci_id: 11) }
- let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) }
+ let!(:project) { create(:project, :repository, ci_id: 10) }
+ let!(:project2) { create(:empty_project, ci_id: 11) }
+ let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) }
let(:options) do
{
token: trigger_token
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 6a5ad6deb74..4a16824de04 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -12,7 +12,7 @@ describe 'Git HTTP requests', lib: true do
describe "User with no identities" do
let(:user) { create(:user) }
- let(:project) { create(:project, path: 'project.git-project') }
+ let(:project) { create(:project, :repository, path: 'project.git-project') }
context "when the project doesn't exist" do
context "when no authentication is provided" do
diff --git a/spec/requests/projects/artifacts_controller_spec.rb b/spec/requests/projects/artifacts_controller_spec.rb
index e02f0eacc93..d20866c0d44 100644
--- a/spec/requests/projects/artifacts_controller_spec.rb
+++ b/spec/requests/projects/artifacts_controller_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Projects::ArtifactsController do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
index 28b485e4b15..0edbffbcd3b 100644
--- a/spec/requests/projects/cycle_analytics_events_spec.rb
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -4,7 +4,7 @@ describe 'cycle analytics events' do
include ApiHelpers
let(:user) { create(:user) }
- let(:project) { create(:project, public_builds: false) }
+ let(:project) { create(:project, :repository, public_builds: false) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
describe 'GET /:namespace/:project/cycle_analytics/events/issues' do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index bfbee7ca35f..309985a5d90 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -33,6 +33,49 @@ describe NotificationService, services: true do
end
end
+ # Next shared examples are intended to test notifications of "participants"
+ #
+ # they take the following parameters:
+ # * issuable
+ # * notification trigger
+ # * participant
+ #
+ shared_examples 'participating by note notification' do
+ it 'emails the participant' do
+ create(:note_on_issue, noteable: issuable, project_id: project.id, note: 'anything', author: participant)
+
+ notification_trigger
+
+ should_email(participant)
+ end
+ end
+
+ shared_examples 'participating by assignee notification' do
+ it 'emails the participant' do
+ issuable.update_attribute(:assignee, participant)
+
+ notification_trigger
+
+ should_email(participant)
+ end
+ end
+
+ shared_examples 'participating by author notification' do
+ it 'emails the participant' do
+ issuable.author = participant
+
+ notification_trigger
+
+ should_email(participant)
+ end
+ end
+
+ shared_examples_for 'participating notifications' do
+ it_should_behave_like 'participating by note notification'
+ it_should_behave_like 'participating by author notification'
+ it_should_behave_like 'participating by assignee notification'
+ end
+
describe 'Keys' do
describe '#new_key' do
let!(:key) { create(:personal_key) }
@@ -588,32 +631,10 @@ describe NotificationService, services: true do
should_not_email(@u_lazy_participant)
end
- context 'participating' do
- context 'by assignee' do
- before do
- issue.update_attribute(:assignee, @u_lazy_participant)
- notification.reassigned_issue(issue, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by note' do
- let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) }
-
- before { notification.reassigned_issue(issue, @u_disabled) }
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by author' do
- before do
- issue.author = @u_lazy_participant
- notification.reassigned_issue(issue, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
+ it_behaves_like 'participating notifications' do
+ let(:participant) { create(:user, username: 'user-participant') }
+ let(:issuable) { issue }
+ let(:notification_trigger) { notification.reassigned_issue(issue, @u_disabled) }
end
end
@@ -720,32 +741,10 @@ describe NotificationService, services: true do
should_not_email(@u_lazy_participant)
end
- context 'participating' do
- context 'by assignee' do
- before do
- issue.update_attribute(:assignee, @u_lazy_participant)
- notification.close_issue(issue, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by note' do
- let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) }
-
- before { notification.close_issue(issue, @u_disabled) }
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by author' do
- before do
- issue.author = @u_lazy_participant
- notification.close_issue(issue, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
+ it_behaves_like 'participating notifications' do
+ let(:participant) { create(:user, username: 'user-participant') }
+ let(:issuable) { issue }
+ let(:notification_trigger) { notification.close_issue(issue, @u_disabled) }
end
end
@@ -772,32 +771,10 @@ describe NotificationService, services: true do
should_not_email(@u_lazy_participant)
end
- context 'participating' do
- context 'by assignee' do
- before do
- issue.update_attribute(:assignee, @u_lazy_participant)
- notification.reopen_issue(issue, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by note' do
- let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) }
-
- before { notification.reopen_issue(issue, @u_disabled) }
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by author' do
- before do
- issue.author = @u_lazy_participant
- notification.reopen_issue(issue, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
+ it_behaves_like 'participating notifications' do
+ let(:participant) { create(:user, username: 'user-participant') }
+ let(:issuable) { issue }
+ let(:notification_trigger) { notification.reopen_issue(issue, @u_disabled) }
end
end
end
@@ -858,31 +835,28 @@ describe NotificationService, services: true do
end
context 'participating' do
- context 'by assignee' do
- before do
- merge_request.update_attribute(:assignee, @u_lazy_participant)
- notification.new_merge_request(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
+ it_should_behave_like 'participating by assignee notification' do
+ let(:participant) { create(:user, username: 'user-participant')}
+ let(:issuable) { merge_request }
+ let(:notification_trigger) { notification.new_merge_request(merge_request, @u_disabled) }
end
- context 'by note' do
- let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
-
- before { notification.new_merge_request(merge_request, @u_disabled) }
-
- it { should_email(@u_lazy_participant) }
+ it_should_behave_like 'participating by note notification' do
+ let(:participant) { create(:user, username: 'user-participant')}
+ let(:issuable) { merge_request }
+ let(:notification_trigger) { notification.new_merge_request(merge_request, @u_disabled) }
end
context 'by author' do
+ let(:participant) { create(:user, username: 'user-participant')}
+
before do
- merge_request.author = @u_lazy_participant
+ merge_request.author = participant
merge_request.save
notification.new_merge_request(merge_request, @u_disabled)
end
- it { should_not_email(@u_lazy_participant) }
+ it { should_not_email(participant) }
end
end
end
@@ -917,33 +891,10 @@ describe NotificationService, services: true do
should_not_email(@u_lazy_participant)
end
- context 'participating' do
- context 'by assignee' do
- before do
- merge_request.update_attribute(:assignee, @u_lazy_participant)
- notification.reassigned_merge_request(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by note' do
- let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
-
- before { notification.reassigned_merge_request(merge_request, @u_disabled) }
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by author' do
- before do
- merge_request.author = @u_lazy_participant
- merge_request.save
- notification.reassigned_merge_request(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
+ it_behaves_like 'participating notifications' do
+ let(:participant) { create(:user, username: 'user-participant') }
+ let(:issuable) { merge_request }
+ let(:notification_trigger) { notification.reassigned_merge_request(merge_request, @u_disabled) }
end
end
@@ -1014,33 +965,10 @@ describe NotificationService, services: true do
should_not_email(@u_lazy_participant)
end
- context 'participating' do
- context 'by assignee' do
- before do
- merge_request.update_attribute(:assignee, @u_lazy_participant)
- notification.close_mr(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by note' do
- let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
-
- before { notification.close_mr(merge_request, @u_disabled) }
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by author' do
- before do
- merge_request.author = @u_lazy_participant
- merge_request.save
- notification.close_mr(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
+ it_behaves_like 'participating notifications' do
+ let(:participant) { create(:user, username: 'user-participant') }
+ let(:issuable) { merge_request }
+ let(:notification_trigger) { notification.close_mr(merge_request, @u_disabled) }
end
end
@@ -1081,33 +1009,10 @@ describe NotificationService, services: true do
should_not_email(@u_watcher)
end
- context 'participating' do
- context 'by assignee' do
- before do
- merge_request.update_attribute(:assignee, @u_lazy_participant)
- notification.merge_mr(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by note' do
- let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
-
- before { notification.merge_mr(merge_request, @u_disabled) }
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by author' do
- before do
- merge_request.author = @u_lazy_participant
- merge_request.save
- notification.merge_mr(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
+ it_behaves_like 'participating notifications' do
+ let(:participant) { create(:user, username: 'user-participant') }
+ let(:issuable) { merge_request }
+ let(:notification_trigger) { notification.merge_mr(merge_request, @u_disabled) }
end
end
@@ -1134,33 +1039,10 @@ describe NotificationService, services: true do
should_not_email(@u_lazy_participant)
end
- context 'participating' do
- context 'by assignee' do
- before do
- merge_request.update_attribute(:assignee, @u_lazy_participant)
- notification.reopen_mr(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by note' do
- let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
-
- before { notification.reopen_mr(merge_request, @u_disabled) }
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by author' do
- before do
- merge_request.author = @u_lazy_participant
- merge_request.save
- notification.reopen_mr(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
+ it_behaves_like 'participating notifications' do
+ let(:participant) { create(:user, username: 'user-participant') }
+ let(:issuable) { merge_request }
+ let(:notification_trigger) { notification.reopen_mr(merge_request, @u_disabled) }
end
end
@@ -1180,33 +1062,10 @@ describe NotificationService, services: true do
should_not_email(@u_lazy_participant)
end
- context 'participating' do
- context 'by assignee' do
- before do
- merge_request.update_attribute(:assignee, @u_lazy_participant)
- notification.resolve_all_discussions(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by note' do
- let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
-
- before { notification.resolve_all_discussions(merge_request, @u_disabled) }
-
- it { should_email(@u_lazy_participant) }
- end
-
- context 'by author' do
- before do
- merge_request.author = @u_lazy_participant
- merge_request.save
- notification.resolve_all_discussions(merge_request, @u_disabled)
- end
-
- it { should_email(@u_lazy_participant) }
- end
+ it_behaves_like 'participating notifications' do
+ let(:participant) { create(:user, username: 'user-participant') }
+ let(:issuable) { merge_request }
+ let(:notification_trigger) { notification.resolve_all_discussions(merge_request, @u_disabled) }
end
end
end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 9f5a0ac4ec6..bd7269045e1 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -245,6 +245,8 @@ describe SystemNoteService, services: true do
end
describe '.change_title' do
+ let(:noteable) { create(:issue, project: project, title: 'Lorem ipsum') }
+
subject { described_class.change_title(noteable, project, author, 'Old title') }
context 'when noteable responds to `title`' do
@@ -252,7 +254,7 @@ describe SystemNoteService, services: true do
it 'sets the note text' do
expect(subject.note).
- to eq "changed title from **{-Old title-}** to **{+#{noteable.title}+}**"
+ to eq "changed title from **{-Old title-}** to **{+Lorem ipsum+}**"
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index e160c11111b..ab38dac65c5 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -9,6 +9,10 @@ require 'rspec/rails'
require 'shoulda/matchers'
require 'rspec/retry'
+if ENV['RSPEC_PROFILING_POSTGRES_URL'] || ENV['RSPEC_PROFILING']
+ require 'rspec_profiling/rspec'
+end
+
if ENV['CI'] && !ENV['NO_KNAPSACK']
require 'knapsack'
Knapsack::Adapters::RSpecAdapter.bind
diff --git a/spec/support/cycle_analytics_helpers/test_generation.rb b/spec/support/cycle_analytics_helpers/test_generation.rb
index 35b40d73191..10b90b40ba7 100644
--- a/spec/support/cycle_analytics_helpers/test_generation.rb
+++ b/spec/support/cycle_analytics_helpers/test_generation.rb
@@ -54,7 +54,7 @@ module CycleAnalyticsHelpers
end
context "when the data belongs to another project" do
- let(:other_project) { create(:project) }
+ let(:other_project) { create(:project, :repository) }
it "returns nil" do
# Use a stub to "trick" the data/condition functions
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index f57c82809a6..87936bb4859 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -12,7 +12,7 @@ shared_context 'mentionable context' do
let!(:mentioned_mr) { create(:merge_request, source_project: project) }
let(:mentioned_commit) { project.commit("HEAD~1") }
- let(:ext_proj) { create(:project, :public) }
+ let(:ext_proj) { create(:project, :public, :repository) }
let(:ext_issue) { create(:issue, project: ext_proj) }
let(:ext_mr) { create(:merge_request, :simple, source_project: ext_proj) }
let(:ext_commit) { ext_proj.commit("HEAD~2") }
diff --git a/spec/support/mobile_helpers.rb b/spec/support/mobile_helpers.rb
new file mode 100644
index 00000000000..20d5849bcab
--- /dev/null
+++ b/spec/support/mobile_helpers.rb
@@ -0,0 +1,13 @@
+module MobileHelpers
+ def resize_screen_sm
+ resize_window(900, 768)
+ end
+
+ def restore_window_size
+ resize_window(1366, 768)
+ end
+
+ def resize_window(width, height)
+ page.driver.resize_window width, height
+ end
+end
diff --git a/spec/support/slack_mattermost_notifications_shared_examples.rb b/spec/support/slack_mattermost_notifications_shared_examples.rb
index 74d9b8c6313..704922b6cf4 100644
--- a/spec/support/slack_mattermost_notifications_shared_examples.rb
+++ b/spec/support/slack_mattermost_notifications_shared_examples.rb
@@ -26,7 +26,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do
describe "#execute" do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:username) { 'slack_username' }
let(:channel) { 'slack_channel' }
@@ -196,7 +196,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do
describe "Note events" do
let(:user) { create(:user) }
- let(:project) { create(:project, creator_id: user.id) }
+ let(:project) { create(:project, :repository, creator: user) }
before do
allow(chat_service).to receive_messages(
@@ -269,7 +269,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do
describe 'Pipeline events' do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
diff --git a/spec/views/ci/lints/show.html.haml_spec.rb b/spec/views/ci/lints/show.html.haml_spec.rb
index 2dac5ee23c8..3390ae247ff 100644
--- a/spec/views/ci/lints/show.html.haml_spec.rb
+++ b/spec/views/ci/lints/show.html.haml_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe 'ci/lints/show' do
- include Devise::TestHelpers
+ include Devise::Test::ControllerHelpers
describe 'XSS protection' do
let(:config_processor) { Ci::GitlabCiYamlProcessor.new(YAML.dump(content)) }
diff --git a/spec/views/projects/builds/show.html.haml_spec.rb b/spec/views/projects/builds/show.html.haml_spec.rb
index 745d0c745bd..44870cfcfb3 100644
--- a/spec/views/projects/builds/show.html.haml_spec.rb
+++ b/spec/views/projects/builds/show.html.haml_spec.rb
@@ -15,6 +15,36 @@ describe 'projects/builds/show', :view do
allow(view).to receive(:can?).and_return(true)
end
+ describe 'build information in header' do
+ let(:build) do
+ create(:ci_build, :success, environment: 'staging')
+ end
+
+ before do
+ render
+ end
+
+ it 'shows status name' do
+ expect(rendered).to have_css('.ci-status.ci-success', text: 'passed')
+ end
+
+ it 'does not render a link to the build' do
+ expect(rendered).not_to have_link('passed')
+ end
+
+ it 'shows build id' do
+ expect(rendered).to have_css('.js-build-id', text: build.id)
+ end
+
+ it 'shows a link to the pipeline' do
+ expect(rendered).to have_link(build.pipeline.id)
+ end
+
+ it 'shows a link to the commit' do
+ expect(rendered).to have_link(build.pipeline.short_sha)
+ end
+ end
+
describe 'environment info in build view' do
context 'build with latest deployment' do
let(:build) do