summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md16
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock18
-rw-r--r--app/assets/javascripts/dispatcher.js7
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_hint.js5
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_non_user.js5
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_user.js5
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown.js2
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js26
-rw-r--r--app/assets/javascripts/protected_branches/index.js9
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js53
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_create.js106
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_dropdown.js39
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_edit.js114
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_edit_list.js28
-rw-r--r--app/assets/javascripts/protected_branches/protected_branches_bundle.js5
-rw-r--r--app/assets/javascripts/protected_tags/index.js11
-rw-r--r--app/assets/stylesheets/new_sidebar.scss3
-rw-r--r--app/assets/stylesheets/pages/projects.scss3
-rw-r--r--app/helpers/triggers_helper.rb2
-rw-r--r--app/views/admin/application_settings/_form.html.haml15
-rw-r--r--app/views/admin/runners/index.html.haml33
-rw-r--r--app/views/ci/runner/_how_to_setup_runner.html.haml16
-rw-r--r--app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml2
-rw-r--r--app/views/projects/protected_branches/shared/_branches_list.html.haml4
-rw-r--r--app/views/projects/protected_branches/shared/_create_protected_branch.html.haml2
-rw-r--r--app/views/projects/protected_tags/shared/_tags_list.html.haml2
-rw-r--r--app/views/projects/runners/_specific_runners.html.haml19
-rw-r--r--changelogs/unreleased/20817-please-add-coordinator-url-to-admin-area-runner-page.yml4
-rw-r--r--changelogs/unreleased/34549-extract-devise-mappings-into-helper.yml4
-rw-r--r--changelogs/unreleased/34973-sub-nav-item-font-size.yml4
-rw-r--r--changelogs/unreleased/fix-re2-infinite-loop-nick.yml4
-rw-r--r--changelogs/unreleased/fix-sm-32790-pipeline_schedules-pages-throwing-error-500.yml4
-rw-r--r--config/initializers/lograge.rb2
-rw-r--r--config/webpack.config.js2
-rw-r--r--doc/README.md1
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md16
-rw-r--r--doc/development/background_migrations.md36
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/integration/img/enable_trello_powerup.pngbin0 -> 17905 bytes
-rw-r--r--doc/integration/img/trello_card_with_gitlab_powerup.pngbin0 -> 18667 bytes
-rw-r--r--doc/integration/trello_power_up.md42
-rw-r--r--lib/api/access_requests.rb1
-rw-r--r--lib/api/award_emoji.rb1
-rw-r--r--lib/api/broadcast_messages.rb1
-rw-r--r--lib/api/deploy_keys.rb1
-rw-r--r--lib/api/environments.rb1
-rw-r--r--lib/api/groups.rb2
-rw-r--r--lib/api/issues.rb1
-rw-r--r--lib/api/labels.rb1
-rw-r--r--lib/api/members.rb1
-rw-r--r--lib/api/merge_requests.rb1
-rw-r--r--lib/api/notes.rb1
-rw-r--r--lib/api/project_hooks.rb1
-rw-r--r--lib/api/project_snippets.rb1
-rw-r--r--lib/api/projects.rb2
-rw-r--r--lib/api/runner.rb1
-rw-r--r--lib/api/runners.rb2
-rw-r--r--lib/api/snippets.rb1
-rw-r--r--lib/api/system_hooks.rb1
-rw-r--r--lib/api/triggers.rb1
-rw-r--r--lib/api/users.rb5
-rw-r--r--lib/api/variables.rb1
-rw-r--r--lib/gitlab/ee_compat_check.rb13
-rw-r--r--lib/gitlab/git/commit.rb38
-rw-r--r--lib/gitlab/gitaly_client/commit.rb14
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb20
-rw-r--r--lib/gitlab/untrusted_regexp.rb29
-rw-r--r--lib/tasks/gitlab/task_helpers.rb9
-rw-r--r--locale/zh_TW/gitlab.po33
-rw-r--r--qa/qa.rb9
-rw-r--r--qa/qa/page/dashboard/groups.rb (renamed from qa/qa/page/main/groups.rb)6
-rw-r--r--qa/qa/page/group/show.rb11
-rw-r--r--qa/qa/page/main/menu.rb7
-rw-r--r--qa/qa/scenario/gitlab/project/create.rb4
-rw-r--r--spec/controllers/sessions_controller_spec.rb8
-rw-r--r--spec/features/admin/admin_runners_spec.rb9
-rw-r--r--spec/features/issues/user_uses_slash_commands_spec.rb36
-rw-r--r--spec/features/merge_requests/user_uses_slash_commands_spec.rb8
-rw-r--r--spec/features/oauth_login_spec.rb4
-rw-r--r--spec/features/projects/pipeline_schedules_spec.rb24
-rw-r--r--spec/features/projects/services/mattermost_slash_command_spec.rb2
-rw-r--r--spec/features/projects/services/slack_slash_command_spec.rb2
-rw-r--r--spec/javascripts/filtered_search/dropdown_user_spec.js9
-rw-r--r--spec/javascripts/fixtures/u2f.rb4
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb116
-rw-r--r--spec/lib/gitlab/untrusted_regexp_spec.rb20
-rw-r--r--spec/support/devise_helpers.rb14
-rw-r--r--spec/support/login_helpers.rb4
-rw-r--r--spec/support/shared_examples/features/protected_branches_access_control_ce.rb4
-rw-r--r--spec/tasks/gitlab/task_helpers_spec.rb15
92 files changed, 753 insertions, 424 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index de3b4b0d3e7..2f6398537a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 9.3.9 (2017-07-20)
+
+- Fix an infinite loop when handling user-supplied regular expressions.
+
## 9.3.8 (2017-07-19)
- Improve support for external issue references. !12485
@@ -270,6 +274,10 @@ entry.
- Remove foreigh key on ci_trigger_schedules only if it exists.
- Allow translation of Pipeline Schedules.
+## 9.2.9 (2017-07-20)
+
+- Fix an infinite loop when handling user-supplied regular expressions.
+
## 9.2.8 (2017-07-19)
- Improve support for external issue references. !12485
@@ -521,6 +529,10 @@ entry.
- Fix preemptive scroll bar on user activity calendar.
- Pipeline chat notifications convert seconds to minutes and hours.
+## 9.1.9 (2017-07-20)
+
+- Fix an infinite loop when handling user-supplied regular expressions.
+
## 9.1.8 (2017-07-19)
- Improve support for external issue references. !12485
@@ -840,6 +852,10 @@ entry.
- Only send chat notifications for the default branch.
- Don't fill in the default kubernetes namespace.
+## 9.0.12 (2017-07-20)
+
+- Fix an infinite loop when handling user-supplied regular expressions.
+
## 9.0.11 (2017-07-19)
- Renders 404 if given project is not readable by the user on Todos dashboard.
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index c7cb1311a64..8a30e8f94a3 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-5.3.1
+5.4.0
diff --git a/Gemfile b/Gemfile
index 893299fb635..1ee44680774 100644
--- a/Gemfile
+++ b/Gemfile
@@ -71,7 +71,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.4', require: false
gem 'github-linguist', '~> 4.7.0', require: 'linguist'
# API
-gem 'grape', '~> 0.19.0'
+gem 'grape', '~> 0.19.2'
gem 'grape-entity', '~> 0.6.0'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
@@ -386,7 +386,7 @@ gem 'vmstat', '~> 2.3.0'
gem 'sys-filesystem', '~> 1.1.6'
# Gitaly GRPC client
-gem 'gitaly', '~> 0.17.0'
+gem 'gitaly', '~> 0.18.0'
gem 'toml-rb', '~> 0.3.15', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 0c4fc1fee0c..b0b437ae342 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -269,7 +269,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
- gitaly (0.17.0)
+ gitaly (0.18.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
@@ -332,13 +332,13 @@ GEM
multi_json (~> 1.11)
os (~> 0.9)
signet (~> 0.7)
- grape (0.19.1)
+ grape (0.19.2)
activesupport
builder
hashie (>= 2.1.0)
multi_json (>= 1.3.2)
multi_xml (>= 0.5.2)
- mustermann-grape (~> 0.4.0)
+ mustermann-grape (~> 1.0.0)
rack (>= 1.3.0)
rack-accept
virtus (>= 1.0.0)
@@ -463,10 +463,9 @@ GEM
multi_json (1.12.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
- mustermann (0.4.0)
- tool (~> 0.2)
- mustermann-grape (0.4.0)
- mustermann (= 0.4.0)
+ mustermann (1.0.0)
+ mustermann-grape (1.0.0)
+ mustermann (~> 1.0.0)
mysql2 (0.4.5)
net-ldap (0.12.1)
netrc (0.11.0)
@@ -850,7 +849,6 @@ GEM
timfel-krb5-auth (0.8.3)
toml-rb (0.3.15)
citrus (~> 3.0, > 3.0)
- tool (0.2.3)
truncato (0.7.8)
htmlentities (~> 4.3.1)
nokogiri (~> 1.6.1)
@@ -972,7 +970,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
- gitaly (~> 0.17.0)
+ gitaly (~> 0.18.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.5.1)
@@ -981,7 +979,7 @@ DEPENDENCIES
gollum-rugged_adapter (~> 0.4.4)
gon (~> 6.1.0)
google-api-client (~> 0.8.6)
- grape (~> 0.19.0)
+ grape (~> 0.19.2)
grape-entity (~> 0.6.0)
haml_lint (~> 0.21.0)
hamlit (~> 2.6.1)
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 9e90a36a364..ffe97c071ba 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -41,7 +41,6 @@ import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater';
import Landing from './landing';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import UserCallout from './user_callout';
-import { ProtectedTagCreate, ProtectedTagEditList } from './protected_tags';
import ShortcutsWiki from './shortcuts_wiki';
import Pipelines from './pipelines';
import BlobViewer from './blob/viewer/index';
@@ -396,12 +395,6 @@ import PerformanceBar from './performance_bar';
new Search();
break;
case 'projects:settings:repository:show':
- // Initialize Protected Branch Settings
- new gl.ProtectedBranchCreate();
- new gl.ProtectedBranchEditList();
- // Initialize Protected Tag Settings
- new ProtectedTagCreate();
- new ProtectedTagEditList();
// Initialize expandable settings panels
initSettingsPanels();
break;
diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js b/app/assets/javascripts/filtered_search/dropdown_hint.js
index 5838b1bdbb7..a81389ab088 100644
--- a/app/assets/javascripts/filtered_search/dropdown_hint.js
+++ b/app/assets/javascripts/filtered_search/dropdown_hint.js
@@ -2,8 +2,9 @@ import Filter from '~/droplab/plugins/filter';
import './filtered_search_dropdown';
class DropdownHint extends gl.FilteredSearchDropdown {
- constructor(droplab, dropdown, input, tokenKeys, filter) {
- super(droplab, dropdown, input, filter);
+ constructor(options = {}) {
+ const { input, tokenKeys } = options;
+ super(options);
this.config = {
Filter: {
template: 'hint',
diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js b/app/assets/javascripts/filtered_search/dropdown_non_user.js
index 34a9e34070c..2615d626c4c 100644
--- a/app/assets/javascripts/filtered_search/dropdown_non_user.js
+++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js
@@ -5,8 +5,9 @@ import Filter from '~/droplab/plugins/filter';
import './filtered_search_dropdown';
class DropdownNonUser extends gl.FilteredSearchDropdown {
- constructor(droplab, dropdown, input, tokenKeys, filter, endpoint, symbol) {
- super(droplab, dropdown, input, filter);
+ constructor(options = {}) {
+ const { input, endpoint, symbol } = options;
+ super(options);
this.symbol = symbol;
this.config = {
Ajax: {
diff --git a/app/assets/javascripts/filtered_search/dropdown_user.js b/app/assets/javascripts/filtered_search/dropdown_user.js
index 19fed771197..7246ccbb281 100644
--- a/app/assets/javascripts/filtered_search/dropdown_user.js
+++ b/app/assets/javascripts/filtered_search/dropdown_user.js
@@ -5,8 +5,9 @@ import './filtered_search_dropdown';
import { addClassIfElementExists } from '../lib/utils/dom_utils';
class DropdownUser extends gl.FilteredSearchDropdown {
- constructor(droplab, dropdown, input, tokenKeys, filter) {
- super(droplab, dropdown, input, filter);
+ constructor(options = {}) {
+ const { tokenKeys } = options;
+ super(options);
this.config = {
AjaxFilter: {
endpoint: `${gon.relative_url_root || ''}/autocomplete/users.json`,
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
index 4209ca0d6e2..9e9a9ef74be 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
@@ -1,7 +1,7 @@
const DATA_DROPDOWN_TRIGGER = 'data-dropdown-trigger';
class FilteredSearchDropdown {
- constructor(droplab, dropdown, input, filter) {
+ constructor({ droplab, dropdown, input, filter }) {
this.droplab = droplab;
this.hookId = input && input.id;
this.input = input;
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
index 6bc6bc43f51..61cef435209 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
@@ -42,13 +42,19 @@ class FilteredSearchDropdownManager {
milestone: {
reference: null,
gl: 'DropdownNonUser',
- extraArguments: [`${this.baseEndpoint}/milestones.json`, '%'],
+ extraArguments: {
+ endpoint: `${this.baseEndpoint}/milestones.json`,
+ symbol: '%',
+ },
element: this.container.querySelector('#js-dropdown-milestone'),
},
label: {
reference: null,
gl: 'DropdownNonUser',
- extraArguments: [`${this.baseEndpoint}/labels.json`, '~'],
+ extraArguments: {
+ endpoint: `${this.baseEndpoint}/labels.json`,
+ symbol: '~',
+ },
element: this.container.querySelector('#js-dropdown-label'),
},
hint: {
@@ -97,13 +103,19 @@ class FilteredSearchDropdownManager {
let forceShowList = false;
if (!mappingKey.reference) {
- const dl = this.droplab;
- const defaultArguments =
- [null, dl, element, this.filteredSearchInput, this.filteredSearchTokenKeys, key];
- const glArguments = defaultArguments.concat(mappingKey.extraArguments || []);
+ const defaultArguments = {
+ droplab: this.droplab,
+ dropdown: element,
+ input: this.filteredSearchInput,
+ tokenKeys: this.filteredSearchTokenKeys,
+ filter: key,
+ };
+ const extraArguments = mappingKey.extraArguments || {};
+ const glArguments = Object.assign({}, defaultArguments, extraArguments);
// Passing glArguments to `new gl[glClass](<arguments>)`
- mappingKey.reference = new (Function.prototype.bind.apply(gl[glClass], glArguments))();
+ mappingKey.reference =
+ new (Function.prototype.bind.apply(gl[glClass], [null, glArguments]))();
}
if (firstLoad) {
diff --git a/app/assets/javascripts/protected_branches/index.js b/app/assets/javascripts/protected_branches/index.js
new file mode 100644
index 00000000000..c9e7af127d2
--- /dev/null
+++ b/app/assets/javascripts/protected_branches/index.js
@@ -0,0 +1,9 @@
+/* eslint-disable no-unused-vars */
+
+import ProtectedBranchCreate from './protected_branch_create';
+import ProtectedBranchEditList from './protected_branch_edit_list';
+
+$(() => {
+ const protectedBranchCreate = new ProtectedBranchCreate();
+ const protectedBranchEditList = new ProtectedBranchEditList();
+});
diff --git a/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js b/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js
index 42993a252c3..38b1406a99f 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js
@@ -1,31 +1,26 @@
-/* eslint-disable arrow-parens, no-param-reassign, object-shorthand, no-else-return, comma-dangle, max-len */
+export default class ProtectedBranchAccessDropdown {
+ constructor(options) {
+ this.options = options;
+ this.initDropdown();
+ }
-(global => {
- global.gl = global.gl || {};
-
- gl.ProtectedBranchAccessDropdown = class {
- constructor(options) {
- const { $dropdown, data, onSelect } = options;
-
- $dropdown.glDropdown({
- data: data,
- selectable: true,
- inputId: $dropdown.data('input-id'),
- fieldName: $dropdown.data('field-name'),
- toggleLabel(item, el) {
- if (el.is('.is-active')) {
- return item.text;
- } else {
- return 'Select';
- }
- },
- clicked(opts) {
- const { e } = opts;
-
- e.preventDefault();
- onSelect();
+ initDropdown() {
+ const { $dropdown, data, onSelect } = this.options;
+ $dropdown.glDropdown({
+ data,
+ selectable: true,
+ inputId: $dropdown.data('input-id'),
+ fieldName: $dropdown.data('field-name'),
+ toggleLabel(item, $el) {
+ if ($el.is('.is-active')) {
+ return item.text;
}
- });
- }
- };
-})(window);
+ return 'Select';
+ },
+ clicked(options) {
+ options.e.preventDefault();
+ onSelect();
+ },
+ });
+ }
+}
diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js b/app/assets/javascripts/protected_branches/protected_branch_create.js
index 57ea2f52814..10da3783123 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_create.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_create.js
@@ -1,55 +1,51 @@
-/* eslint-disable no-new, arrow-parens, no-param-reassign, comma-dangle, max-len */
-/* global ProtectedBranchDropdown */
-
-(global => {
- global.gl = global.gl || {};
-
- gl.ProtectedBranchCreate = class {
- constructor() {
- this.$wrap = this.$form = $('#new_protected_branch');
- this.buildDropdowns();
- }
-
- buildDropdowns() {
- const $allowedToMergeDropdown = this.$wrap.find('.js-allowed-to-merge');
- const $allowedToPushDropdown = this.$wrap.find('.js-allowed-to-push');
-
- // Cache callback
- this.onSelectCallback = this.onSelect.bind(this);
-
- // Allowed to Merge dropdown
- new gl.ProtectedBranchAccessDropdown({
- $dropdown: $allowedToMergeDropdown,
- data: gon.merge_access_levels,
- onSelect: this.onSelectCallback
- });
-
- // Allowed to Push dropdown
- new gl.ProtectedBranchAccessDropdown({
- $dropdown: $allowedToPushDropdown,
- data: gon.push_access_levels,
- onSelect: this.onSelectCallback
- });
-
- // Select default
- $allowedToPushDropdown.data('glDropdown').selectRowAtIndex(0);
- $allowedToMergeDropdown.data('glDropdown').selectRowAtIndex(0);
-
- // Protected branch dropdown
- new ProtectedBranchDropdown({
- $dropdown: this.$wrap.find('.js-protected-branch-select'),
- onSelect: this.onSelectCallback
- });
- }
-
- // This will run after clicked callback
- onSelect() {
- // Enable submit button
- const $branchInput = this.$wrap.find('input[name="protected_branch[name]"]');
- const $allowedToMergeInput = this.$wrap.find('input[name="protected_branch[merge_access_levels_attributes][0][access_level]"]');
- const $allowedToPushInput = this.$wrap.find('input[name="protected_branch[push_access_levels_attributes][0][access_level]"]');
-
- this.$form.find('input[type="submit"]').attr('disabled', !($branchInput.val() && $allowedToMergeInput.length && $allowedToPushInput.length));
- }
- };
-})(window);
+import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown';
+import ProtectedBranchDropdown from './protected_branch_dropdown';
+
+export default class ProtectedBranchCreate {
+ constructor() {
+ this.$form = $('.js-new-protected-branch');
+ this.buildDropdowns();
+ }
+
+ buildDropdowns() {
+ const $allowedToMergeDropdown = this.$form.find('.js-allowed-to-merge');
+ const $allowedToPushDropdown = this.$form.find('.js-allowed-to-push');
+
+ // Cache callback
+ this.onSelectCallback = this.onSelect.bind(this);
+
+ // Allowed to Merge dropdown
+ this.protectedBranchMergeAccessDropdown = new ProtectedBranchAccessDropdown({
+ $dropdown: $allowedToMergeDropdown,
+ data: gon.merge_access_levels,
+ onSelect: this.onSelectCallback,
+ });
+
+ // Allowed to Push dropdown
+ this.protectedBranchPushAccessDropdown = new ProtectedBranchAccessDropdown({
+ $dropdown: $allowedToPushDropdown,
+ data: gon.push_access_levels,
+ onSelect: this.onSelectCallback,
+ });
+
+ // Select default
+ $allowedToPushDropdown.data('glDropdown').selectRowAtIndex(0);
+ $allowedToMergeDropdown.data('glDropdown').selectRowAtIndex(0);
+
+ // Protected branch dropdown
+ this.protectedBranchDropdown = new ProtectedBranchDropdown({
+ $dropdown: this.$form.find('.js-protected-branch-select'),
+ onSelect: this.onSelectCallback,
+ });
+ }
+
+ // This will run after clicked callback
+ onSelect() {
+ // Enable submit button
+ const $branchInput = this.$form.find('input[name="protected_branch[name]"]');
+ const $allowedToMergeInput = this.$form.find('input[name="protected_branch[merge_access_levels_attributes][0][access_level]"]');
+ const $allowedToPushInput = this.$form.find('input[name="protected_branch[push_access_levels_attributes][0][access_level]"]');
+
+ this.$form.find('input[type="submit"]').attr('disabled', !($branchInput.val() && $allowedToMergeInput.length && $allowedToPushInput.length));
+ }
+}
diff --git a/app/assets/javascripts/protected_branches/protected_branch_dropdown.js b/app/assets/javascripts/protected_branches/protected_branch_dropdown.js
index bc6110fcd4e..cc0b2ebe071 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_dropdown.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_dropdown.js
@@ -1,6 +1,10 @@
-/* eslint-disable comma-dangle, no-unused-vars */
-
-class ProtectedBranchDropdown {
+export default class ProtectedBranchDropdown {
+ /**
+ * @param {Object} options containing
+ * `$dropdown` target element
+ * `onSelect` event callback
+ * $dropdown must be an element created using `dropdown_branch()` rails helper
+ */
constructor(options) {
this.onSelect = options.onSelect;
this.$dropdown = options.$dropdown;
@@ -12,7 +16,7 @@ class ProtectedBranchDropdown {
this.bindEvents();
// Hide footer
- this.$dropdownFooter.addClass('hidden');
+ this.toggleFooter(true);
}
buildDropdown() {
@@ -21,7 +25,7 @@ class ProtectedBranchDropdown {
filterable: true,
remote: false,
search: {
- fields: ['title']
+ fields: ['title'],
},
selectable: true,
toggleLabel(selected) {
@@ -36,10 +40,9 @@ class ProtectedBranchDropdown {
},
onFilter: this.toggleCreateNewButton.bind(this),
clicked: (options) => {
- const { $el, e } = options;
- e.preventDefault();
+ options.e.preventDefault();
this.onSelect();
- }
+ },
});
}
@@ -64,20 +67,22 @@ class ProtectedBranchDropdown {
}
toggleCreateNewButton(branchName) {
- this.selectedBranch = {
- title: branchName,
- id: branchName,
- text: branchName
- };
-
if (branchName) {
+ this.selectedBranch = {
+ title: branchName,
+ id: branchName,
+ text: branchName,
+ };
+
this.$dropdownContainer
.find('.js-create-new-protected-branch code')
.text(branchName);
}
- this.$dropdownFooter.toggleClass('hidden', !branchName);
+ this.toggleFooter(!branchName);
}
-}
-window.ProtectedBranchDropdown = ProtectedBranchDropdown;
+ toggleFooter(toggleState) {
+ this.$dropdownFooter.toggleClass('hidden', toggleState);
+ }
+}
diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit.js b/app/assets/javascripts/protected_branches/protected_branch_edit.js
index 6ef59e94384..3b920942a3f 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_edit.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_edit.js
@@ -1,69 +1,67 @@
-/* eslint-disable no-new, arrow-parens, no-param-reassign, comma-dangle, max-len */
+/* eslint-disable no-new */
/* global Flash */
-(global => {
- global.gl = global.gl || {};
+import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown';
- gl.ProtectedBranchEdit = class {
- constructor(options) {
- this.$wrap = options.$wrap;
- this.$allowedToMergeDropdown = this.$wrap.find('.js-allowed-to-merge');
- this.$allowedToPushDropdown = this.$wrap.find('.js-allowed-to-push');
+export default class ProtectedBranchEdit {
+ constructor(options) {
+ this.$wrap = options.$wrap;
+ this.$allowedToMergeDropdown = this.$wrap.find('.js-allowed-to-merge');
+ this.$allowedToPushDropdown = this.$wrap.find('.js-allowed-to-push');
+ this.onSelectCallback = this.onSelect.bind(this);
- this.buildDropdowns();
- }
+ this.buildDropdowns();
+ }
- buildDropdowns() {
- // Allowed to merge dropdown
- new gl.ProtectedBranchAccessDropdown({
- $dropdown: this.$allowedToMergeDropdown,
- data: gon.merge_access_levels,
- onSelect: this.onSelect.bind(this)
- });
+ buildDropdowns() {
+ // Allowed to merge dropdown
+ this.protectedBranchAccessDropdown = new ProtectedBranchAccessDropdown({
+ $dropdown: this.$allowedToMergeDropdown,
+ data: gon.merge_access_levels,
+ onSelect: this.onSelectCallback,
+ });
- // Allowed to push dropdown
- new gl.ProtectedBranchAccessDropdown({
- $dropdown: this.$allowedToPushDropdown,
- data: gon.push_access_levels,
- onSelect: this.onSelect.bind(this)
- });
- }
+ // Allowed to push dropdown
+ this.protectedBranchAccessDropdown = new ProtectedBranchAccessDropdown({
+ $dropdown: this.$allowedToPushDropdown,
+ data: gon.push_access_levels,
+ onSelect: this.onSelectCallback,
+ });
+ }
- onSelect() {
- const $allowedToMergeInput = this.$wrap.find(`input[name="${this.$allowedToMergeDropdown.data('fieldName')}"]`);
- const $allowedToPushInput = this.$wrap.find(`input[name="${this.$allowedToPushDropdown.data('fieldName')}"]`);
+ onSelect() {
+ const $allowedToMergeInput = this.$wrap.find(`input[name="${this.$allowedToMergeDropdown.data('fieldName')}"]`);
+ const $allowedToPushInput = this.$wrap.find(`input[name="${this.$allowedToPushDropdown.data('fieldName')}"]`);
- // Do not update if one dropdown has not selected any option
- if (!($allowedToMergeInput.length && $allowedToPushInput.length)) return;
+ // Do not update if one dropdown has not selected any option
+ if (!($allowedToMergeInput.length && $allowedToPushInput.length)) return;
- this.$allowedToMergeDropdown.disable();
- this.$allowedToPushDropdown.disable();
+ this.$allowedToMergeDropdown.disable();
+ this.$allowedToPushDropdown.disable();
- $.ajax({
- type: 'POST',
- url: this.$wrap.data('url'),
- dataType: 'json',
- data: {
- _method: 'PATCH',
- protected_branch: {
- merge_access_levels_attributes: [{
- id: this.$allowedToMergeDropdown.data('access-level-id'),
- access_level: $allowedToMergeInput.val()
- }],
- push_access_levels_attributes: [{
- id: this.$allowedToPushDropdown.data('access-level-id'),
- access_level: $allowedToPushInput.val()
- }]
- }
+ $.ajax({
+ type: 'POST',
+ url: this.$wrap.data('url'),
+ dataType: 'json',
+ data: {
+ _method: 'PATCH',
+ protected_branch: {
+ merge_access_levels_attributes: [{
+ id: this.$allowedToMergeDropdown.data('access-level-id'),
+ access_level: $allowedToMergeInput.val(),
+ }],
+ push_access_levels_attributes: [{
+ id: this.$allowedToPushDropdown.data('access-level-id'),
+ access_level: $allowedToPushInput.val(),
+ }],
},
- error() {
- $.scrollTo(0);
- new Flash('Failed to update branch!');
- }
- }).always(() => {
- this.$allowedToMergeDropdown.enable();
- this.$allowedToPushDropdown.enable();
- });
- }
- };
-})(window);
+ },
+ error() {
+ new Flash('Failed to update branch!', null, $('.js-protected-branches-list'));
+ },
+ }).always(() => {
+ this.$allowedToMergeDropdown.enable();
+ this.$allowedToPushDropdown.enable();
+ });
+ }
+}
diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit_list.js b/app/assets/javascripts/protected_branches/protected_branch_edit_list.js
index 336fa6c57a7..b40d3827c30 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_edit_list.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_edit_list.js
@@ -1,18 +1,18 @@
-/* eslint-disable arrow-parens, no-param-reassign, no-new, comma-dangle */
+/* eslint-disable no-new */
-(global => {
- global.gl = global.gl || {};
+import ProtectedBranchEdit from './protected_branch_edit';
- gl.ProtectedBranchEditList = class {
- constructor() {
- this.$wrap = $('.protected-branches-list');
+export default class ProtectedBranchEditList {
+ constructor() {
+ this.$wrap = $('.protected-branches-list');
+ this.initEditForm();
+ }
- // Build edit forms
- this.$wrap.find('.js-protected-branch-edit-form').each((i, el) => {
- new gl.ProtectedBranchEdit({
- $wrap: $(el)
- });
+ initEditForm() {
+ this.$wrap.find('.js-protected-branch-edit-form').each((i, el) => {
+ new ProtectedBranchEdit({
+ $wrap: $(el),
});
- }
- };
-})(window);
+ });
+ }
+}
diff --git a/app/assets/javascripts/protected_branches/protected_branches_bundle.js b/app/assets/javascripts/protected_branches/protected_branches_bundle.js
deleted file mode 100644
index 874d70a1431..00000000000
--- a/app/assets/javascripts/protected_branches/protected_branches_bundle.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import './protected_branch_access_dropdown';
-import './protected_branch_create';
-import './protected_branch_dropdown';
-import './protected_branch_edit';
-import './protected_branch_edit_list';
diff --git a/app/assets/javascripts/protected_tags/index.js b/app/assets/javascripts/protected_tags/index.js
index 61e7ba53862..b1618e24e49 100644
--- a/app/assets/javascripts/protected_tags/index.js
+++ b/app/assets/javascripts/protected_tags/index.js
@@ -1,2 +1,9 @@
-export { default as ProtectedTagCreate } from './protected_tag_create';
-export { default as ProtectedTagEditList } from './protected_tag_edit_list';
+/* eslint-disable no-unused-vars */
+
+import ProtectedTagCreate from './protected_tag_create';
+import ProtectedTagEditList from './protected_tag_edit_list';
+
+$(() => {
+ const protectedtTagCreate = new ProtectedTagCreate();
+ const protectedtTagEditList = new ProtectedTagEditList();
+});
diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/new_sidebar.scss
index ce8f4c41cb5..6255ed96910 100644
--- a/app/assets/stylesheets/new_sidebar.scss
+++ b/app/assets/stylesheets/new_sidebar.scss
@@ -165,7 +165,6 @@ $new-sidebar-width: 220px;
> li {
a {
- font-size: 12px;
padding: 8px 16px 8px 24px;
&:hover,
@@ -262,7 +261,7 @@ $new-sidebar-width: 220px;
@media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
// scss-lint:disable DuplicateProperty
- height: calc(100vh - 120px);
+ height: calc(100vh - 180px);
// scss-lint:enable DuplicateProperty
}
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index c1423965d0a..a3e07a36c33 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -742,7 +742,8 @@ pre.light-well {
}
}
-.protected-tags-list {
+.protected-tags-list,
+.protected-branches-list {
.dropdown-menu-toggle {
width: 100%;
max-width: 300px;
diff --git a/app/helpers/triggers_helper.rb b/app/helpers/triggers_helper.rb
index a48d4475e97..ce435ca2241 100644
--- a/app/helpers/triggers_helper.rb
+++ b/app/helpers/triggers_helper.rb
@@ -8,6 +8,6 @@ module TriggersHelper
end
def service_trigger_url(service)
- "#{Settings.gitlab.url}/api/v3/projects/#{service.project_id}/services/#{service.to_param}/trigger"
+ "#{Settings.gitlab.url}/api/v4/projects/#{service.project_id}/services/#{service.to_param}/trigger"
end
end
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 26f7c1a473a..8bb2a563990 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -315,7 +315,9 @@
%fieldset
%legend Metrics - Prometheus
%p
- Enable a Prometheus metrics endpoint at `#{metrics_path}` to expose a variety of statistics on the health and performance of GitLab. Additional information on authenticating and connecting to the metrics endpoint is available
+ Enable a Prometheus metrics endpoint at
+ %code= metrics_path
+ to expose a variety of statistics on the health and performance of GitLab. Additional information on authenticating and connecting to the metrics endpoint is available
= link_to 'here', admin_health_check_path
\. This setting requires a
= link_to 'restart', help_page_path('administration/restart_gitlab')
@@ -327,10 +329,13 @@
= f.label :prometheus_metrics_enabled do
= f.check_box :prometheus_metrics_enabled
Enable Prometheus Metrics
- - unless Gitlab::Metrics.metrics_folder_present?
- .help-block
- %strong.cred WARNING:
- Environment variable `prometheus_multiproc_dir` does not exist or is not pointing to a valid directory.
+ - unless Gitlab::Metrics.metrics_folder_present?
+ .help-block
+ %strong.cred WARNING:
+ Environment variable
+ %code prometheus_multiproc_dir
+ does not exist or is not pointing to a valid directory.
+ = link_to icon('question-circle'), help_page_path('administration/monitoring/prometheus/gitlab_metrics', anchor: 'metrics-shared-directory')
%fieldset
%legend Profiling - Performance Bar
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index 2da8f615470..126550ee10e 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -2,26 +2,6 @@
= render "admin/dashboard/head"
%div{ class: container_class }
-
- %p.prepend-top-default
- %span
- To register a new Runner you should enter the following registration
- token.
- With this token the Runner will request a unique Runner token and use
- that for future communication.
- %br
- Registration token is
- %code#runners-token= current_application_settings.runners_registration_token
-
- .bs-callout.clearfix
- .pull-left
- %p
- You can reset runners registration token by pressing a button below.
- .prepend-top-10
- = button_to "Reset runners registration token", reset_runners_token_admin_application_settings_path,
- method: :put, class: 'btn btn-default',
- data: { confirm: 'Are you sure you want to reset registration token?' }
-
.bs-callout
%p
A 'Runner' is a process which runs a job.
@@ -46,6 +26,19 @@
%span.label.label-danger paused
\- Runner will not receive any new jobs
+ .bs-callout.clearfix
+ .pull-left
+ %p
+ You can reset runners registration token by pressing a button below.
+ .prepend-top-10
+ = button_to _("Reset runners registration token"), reset_runners_token_admin_application_settings_path,
+ method: :put, class: 'btn btn-default',
+ data: { confirm: _("Are you sure you want to reset registration token?") }
+
+ = render partial: 'ci/runner/how_to_setup_runner',
+ locals: { registration_token: current_application_settings.runners_registration_token,
+ type: 'shared' }
+
.append-bottom-20.clearfix
.pull-left
= form_tag admin_runners_path, id: 'runners-search', class: 'form-inline', method: :get do
diff --git a/app/views/ci/runner/_how_to_setup_runner.html.haml b/app/views/ci/runner/_how_to_setup_runner.html.haml
new file mode 100644
index 00000000000..b75dab0acc5
--- /dev/null
+++ b/app/views/ci/runner/_how_to_setup_runner.html.haml
@@ -0,0 +1,16 @@
+- link = link_to _("GitLab Runner section"), 'https://about.gitlab.com/gitlab-ci/#gitlab-runner', target: '_blank'
+.bs-callout.help-callout
+ %h4= _("How to setup a #{type} Runner for a new project")
+
+ %ol
+ %li
+ = _("Install a Runner compatible with GitLab CI")
+ = (_("(checkout the %{link} for information on how to install it).") % { link: link }).html_safe
+ %li
+ = _("Specify the following URL during the Runner setup:")
+ %code= root_url(only_path: false)
+ %li
+ = _("Use the following registration token during setup:")
+ %code#registration_token= registration_token
+ %li
+ = _("Start the Runner!")
diff --git a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
index 97c0407a01d..7343d6e039c 100644
--- a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
+++ b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
@@ -4,7 +4,7 @@
= pipeline_schedule.description
%td.branch-name-cell
= icon('code-fork')
- - if pipeline_schedule.ref
+ - if pipeline_schedule.ref.present?
= link_to pipeline_schedule.ref, project_ref_path(@project, pipeline_schedule.ref), class: "ref-name"
%td
- if pipeline_schedule.last_pipeline
diff --git a/app/views/projects/protected_branches/shared/_branches_list.html.haml b/app/views/projects/protected_branches/shared/_branches_list.html.haml
index 5c00bb6883c..2a0704bc7af 100644
--- a/app/views/projects/protected_branches/shared/_branches_list.html.haml
+++ b/app/views/projects/protected_branches/shared/_branches_list.html.haml
@@ -1,4 +1,4 @@
-.panel.panel-default.protected-branches-list
+.panel.panel-default.protected-branches-list.js-protected-branches-list
- if @protected_branches.empty?
.panel-heading
%h3.panel-title
@@ -23,6 +23,8 @@
- if can_admin_project
%th
%tbody
+ %tr
+ %td.flash-container{ colspan: 5 }
= yield
= paginate @protected_branches, theme: 'gitlab'
diff --git a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml
index b619fa57e05..9f0c4f3b3a8 100644
--- a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml
+++ b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml
@@ -1,4 +1,4 @@
-= form_for [@project.namespace.becomes(Namespace), @project, @protected_branch] do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @protected_branch], html: { class: 'new-protected-branch js-new-protected-branch' } do |f|
.panel.panel-default
.panel-heading
%h3.panel-title
diff --git a/app/views/projects/protected_tags/shared/_tags_list.html.haml b/app/views/projects/protected_tags/shared/_tags_list.html.haml
index 6e3cd4ada71..3f42ae58438 100644
--- a/app/views/projects/protected_tags/shared/_tags_list.html.haml
+++ b/app/views/projects/protected_tags/shared/_tags_list.html.haml
@@ -1,4 +1,4 @@
-.panel.panel-default.protected-tags-list
+.panel.panel-default.protected-tags-list.js-protected-tags-list
- if @protected_tags.empty?
.panel-heading
%h3.panel-title
diff --git a/app/views/projects/runners/_specific_runners.html.haml b/app/views/projects/runners/_specific_runners.html.haml
index f8835454140..28ccbf7eb15 100644
--- a/app/views/projects/runners/_specific_runners.html.haml
+++ b/app/views/projects/runners/_specific_runners.html.haml
@@ -1,21 +1,8 @@
%h3 Specific Runners
-.bs-callout.help-callout
- %h4 How to setup a specific Runner for a new project
-
- %ol
- %li
- Install a Runner compatible with GitLab CI
- (checkout the #{link_to 'GitLab Runner section', 'https://about.gitlab.com/gitlab-ci/#gitlab-runner', target: '_blank'} for information on how to install it).
- %li
- Specify the following URL during the Runner setup:
- %code= root_url(only_path: false)
- %li
- Use the following registration token during setup:
- %code= @project.runners_token
- %li
- Start the Runner!
-
+= render partial: 'ci/runner/how_to_setup_runner',
+ locals: { registration_token: @project.runners_token,
+ type: 'specific' }
- if @project_runners.any?
%h4.underlined-title Runners activated for this project
diff --git a/changelogs/unreleased/20817-please-add-coordinator-url-to-admin-area-runner-page.yml b/changelogs/unreleased/20817-please-add-coordinator-url-to-admin-area-runner-page.yml
new file mode 100644
index 00000000000..c4c3fc7ceb2
--- /dev/null
+++ b/changelogs/unreleased/20817-please-add-coordinator-url-to-admin-area-runner-page.yml
@@ -0,0 +1,4 @@
+---
+title: Add coordinator url to admin area runner page
+merge_request: 11603
+author:
diff --git a/changelogs/unreleased/34549-extract-devise-mappings-into-helper.yml b/changelogs/unreleased/34549-extract-devise-mappings-into-helper.yml
new file mode 100644
index 00000000000..e843bbac239
--- /dev/null
+++ b/changelogs/unreleased/34549-extract-devise-mappings-into-helper.yml
@@ -0,0 +1,4 @@
+---
+title: Extract "@request.env[devise.mapping] = Devise.mappings[:user]" to a test helper
+merge_request: 12742
+author: Jacopo Beschi @jacopo-beschi
diff --git a/changelogs/unreleased/34973-sub-nav-item-font-size.yml b/changelogs/unreleased/34973-sub-nav-item-font-size.yml
new file mode 100644
index 00000000000..90bf171fe3b
--- /dev/null
+++ b/changelogs/unreleased/34973-sub-nav-item-font-size.yml
@@ -0,0 +1,4 @@
+---
+title: Make font size of contextual sub menu items 14px
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix-re2-infinite-loop-nick.yml b/changelogs/unreleased/fix-re2-infinite-loop-nick.yml
new file mode 100644
index 00000000000..3c314ab2718
--- /dev/null
+++ b/changelogs/unreleased/fix-re2-infinite-loop-nick.yml
@@ -0,0 +1,4 @@
+---
+title: Fix an infinite loop when handling user-supplied regular expressions
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix-sm-32790-pipeline_schedules-pages-throwing-error-500.yml b/changelogs/unreleased/fix-sm-32790-pipeline_schedules-pages-throwing-error-500.yml
new file mode 100644
index 00000000000..334d8ca4d9e
--- /dev/null
+++ b/changelogs/unreleased/fix-sm-32790-pipeline_schedules-pages-throwing-error-500.yml
@@ -0,0 +1,4 @@
+---
+title: Fix pipeline_schedules pages throwing error 500 (when ref is empty)
+merge_request: 12983
+author:
diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb
index 14902316240..c9a515dfcd5 100644
--- a/config/initializers/lograge.rb
+++ b/config/initializers/lograge.rb
@@ -13,7 +13,7 @@ unless Sidekiq.server?
# Add request parameters to log output
config.lograge.custom_options = lambda do |event|
{
- time: event.time,
+ time: event.time.utc.iso8601(3),
params: event.payload[:params].except(%w(controller action format))
}
end
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 1113241e402..a7d92bc53b7 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -56,7 +56,7 @@ var config = {
pipelines_details: './pipelines/pipeline_details_bundle.js',
profile: './profile/profile_bundle.js',
prometheus_metrics: './prometheus_metrics',
- protected_branches: './protected_branches/protected_branches_bundle.js',
+ protected_branches: './protected_branches',
protected_tags: './protected_tags',
sidebar: './sidebar/sidebar_bundle.js',
schedule_form: './pipeline_schedules/pipeline_schedule_form_bundle.js',
diff --git a/doc/README.md b/doc/README.md
index 1a7638b3d7e..2b3b0998fcc 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -115,6 +115,7 @@ Manage files and branches from the UI (user interface):
- [Project Services](user/project/integrations/project_services.md): Integrate a project with external services, such as CI and chat.
- [GitLab Integration](integration/README.md): Integrate with multiple third-party services with GitLab to allow external issue trackers and external authentication.
+- [Trello Power-Up](integration/trello_power_up.md): Integrate with GitLab's Trello Power-Up
----
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index 7072ab5d02a..6baae20d16a 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -20,7 +20,7 @@ it, the client IP needs to be [included in a whitelist][whitelist].
Currently the embedded Prometheus server is not automatically configured to
collect metrics from this endpoint. We recommend setting up another Prometheus
server, because the embedded server configuration is overwritten once every
-[reconfigure of GitLab][reconfigure]. In the future this will not be required.
+[reconfigure of GitLab][reconfigure]. In the future this will not be required.
## Metrics available
@@ -46,6 +46,20 @@ In this experimental phase, only a few metrics are available:
| redis_ping_latency_seconds | Gauge | 9.4 | Round trip time of the redis ping |
| user_session_logins_total | Counter | 9.4 | Counter of how many users have logged in |
+## Metrics shared directory
+
+GitLab's Prometheus client requires a directory to store metrics data shared between multi-process services.
+Those files are shared among all instances running under Unicorn server.
+The directory needs to be accessible to all running Unicorn's processes otherwise
+metrics will not function correctly.
+
+For best performance its advisable that this directory will be located in `tmpfs`.
+
+Its location is configured using environment variable `prometheus_multiproc_dir`.
+
+If GitLab is installed using Omnibus and `tmpfs` is available then metrics
+directory will be automatically configured.
+
[← Back to the main Prometheus page](index.md)
[29118]: https://gitlab.com/gitlab-org/gitlab-ce/issues/29118
diff --git a/doc/development/background_migrations.md b/doc/development/background_migrations.md
index 72a34aa7de9..e67db9ff142 100644
--- a/doc/development/background_migrations.md
+++ b/doc/development/background_migrations.md
@@ -31,6 +31,18 @@ It's also possible for different migrations to be executed at the same time.
This means that different background migrations should not migrate data in a
way that would cause conflicts.
+## Idempotence
+
+Background migrations are executed in a context of a Sidekiq process.
+Usual Sidekiq rules apply, especially the rule that jobs should be small
+and idempotent.
+
+See [Sidekiq best practices guidelines](https://github.com/mperham/sidekiq/wiki/Best-Practices)
+for more details.
+
+Make sure that in case that your migration job is going to be retried data
+integrity is guarateed.
+
## How It Works
Background migrations are simple classes that define a `perform` method. A
@@ -212,3 +224,27 @@ end
This migration will then process any jobs for the ExtractServicesUrl migration
and continue once all jobs have been processed. Once done you can safely remove
the `services.properties` column.
+
+## Testing
+
+It is required to write tests for background migrations' scheduling migration
+(either a regular migration or a post deployment migration), background
+migration itself and a cleanup migration. You can use the `:migration` RSpec
+tag when testing a regular / post deployment migration.
+See [README][migrations-readme].
+
+When you do that, keep in mind that `before` and `after` RSpec hooks are going
+to migrate you database down and up, which can result in other background
+migrations being called. That means that using `spy` test doubles with
+`have_received` is encouraged, instead of using regular test doubles, because
+your expectations defined in a `it` block can conflict with what is being
+called in RSpec hooks. See [gitlab-org/gitlab-ce#35351][issue-rspec-hooks]
+for more details.
+
+## Best practices
+
+1. Make sure that background migration jobs are idempotent.
+1. Make sure that tests you write are not false positives.
+
+[migrations-readme]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/migrations/README.md
+[issue-rspec-hooks]: https://gitlab.com/gitlab-org/gitlab-ce/issues/35351
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 5e981b0b3e7..8ded607bcab 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -64,7 +64,7 @@ up-to-date and install it.
Install the required packages (needed to compile Ruby and native extensions to Ruby gems):
- sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake
+ sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libre2-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake
If you want to use Kerberos for user authentication, then install libkrb5-dev:
diff --git a/doc/integration/img/enable_trello_powerup.png b/doc/integration/img/enable_trello_powerup.png
new file mode 100644
index 00000000000..65d01f1c38c
--- /dev/null
+++ b/doc/integration/img/enable_trello_powerup.png
Binary files differ
diff --git a/doc/integration/img/trello_card_with_gitlab_powerup.png b/doc/integration/img/trello_card_with_gitlab_powerup.png
new file mode 100644
index 00000000000..2965dc35855
--- /dev/null
+++ b/doc/integration/img/trello_card_with_gitlab_powerup.png
Binary files differ
diff --git a/doc/integration/trello_power_up.md b/doc/integration/trello_power_up.md
new file mode 100644
index 00000000000..d264486a872
--- /dev/null
+++ b/doc/integration/trello_power_up.md
@@ -0,0 +1,42 @@
+# Trello Power-Up
+
+GitLab's Trello Power-Up enables you to seamlessly attach
+GitLab **merge requests** to Trello cards.
+
+![GitLab Trello PowerUp - Trello card](img/trello_card_with_gitlab_powerup.png)
+
+## Configuring the Power-Up
+
+In order to get started, you will need to configure your Power-Up.
+
+In Trello:
+
+1. Go to your Trello board
+1. Select `Power-Ups` to see a listing of all the available Power-Ups
+1. Look for a row that says `GitLab` and select the `Enable` button
+1. Select the `Settings` (gear) icon
+1. In the popup menu, select `Authorize Account`
+
+In this popup, fill in your `API URL` and `Personal Access Token`. After that, you will be able to attach any merge request to any Trello card on your selected Trello board.
+
+## What is my API URL?
+
+Your API URL should be your GitLab instance URL with `/api/v4` appended in the end of the URL.
+For example, if your GitLab instance URL is `https://gitlab.com`, your API URL would be `https://gitlab.com/api/v4`.
+If your instance's URL is `https://example.com`, your API URL will be `https://example.com/api/v4`.
+
+![configure GitLab Trello PowerUp in Trello](img/enable_trello_powerup.png)
+
+## What is my Personal Access Token?
+
+Your GitLab's personal access token will enable your GitLab account to be accessed
+from Trello.
+
+> Find it in GitLab by clicking on your avatar (upright corner), from which you access
+your user **Settings** > **Access Tokens**.
+
+Learn more about generating a personal access token in the
+[Personal Access Token Documentation][personal-access-token-documentation].
+Don't forget to check the API scope checkbox!
+
+[personal-access-token-documentation]: ../user/profile/personal_access_tokens.html
diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb
index c9b5f58c557..cdacf9839e5 100644
--- a/lib/api/access_requests.rb
+++ b/lib/api/access_requests.rb
@@ -68,6 +68,7 @@ module API
delete ":id/access_requests/:user_id" do
source = find_source(source_type, params[:id])
+ status 204
::Members::DestroyService.new(source, current_user, params)
.execute(:requesters)
end
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
index 56f19f89642..5a028fc9d0b 100644
--- a/lib/api/award_emoji.rb
+++ b/lib/api/award_emoji.rb
@@ -88,6 +88,7 @@ module API
unauthorized! unless award.user == current_user || current_user.admin?
+ status 204
award.destroy
end
end
diff --git a/lib/api/broadcast_messages.rb b/lib/api/broadcast_messages.rb
index 395c401203c..9980aec4752 100644
--- a/lib/api/broadcast_messages.rb
+++ b/lib/api/broadcast_messages.rb
@@ -91,6 +91,7 @@ module API
delete ':id' do
message = find_message
+ status 204
message.destroy
end
end
diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb
index d5c2f3d5094..42e7c1486b0 100644
--- a/lib/api/deploy_keys.rb
+++ b/lib/api/deploy_keys.rb
@@ -125,6 +125,7 @@ module API
key = user_project.deploy_keys_projects.find_by(deploy_key_id: params[:key_id])
not_found!('Deploy Key') unless key
+ status 204
key.destroy
end
end
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index 945771d46f3..c774a5c6685 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -79,6 +79,7 @@ module API
environment = user_project.environments.find(params[:environment_id])
+ status 204
environment.destroy
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index ebbaed0cbb7..49c3b2278c7 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -125,6 +125,8 @@ module API
delete ":id" do
group = find_group!(params[:id])
authorize! :admin_group, group
+
+ status 204
::Groups::DestroyService.new(group, current_user).execute
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 64be08094ed..14b26f28ebf 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -224,6 +224,7 @@ module API
not_found!('Issue') unless issue
authorize!(:destroy_issue, issue)
+ status 204
issue.destroy
end
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index 20b25529d0c..4520c98d951 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -56,6 +56,7 @@ module API
label = user_project.labels.find_by(title: params[:name])
not_found!('Label') unless label
+ status 204
label.destroy
end
diff --git a/lib/api/members.rb b/lib/api/members.rb
index c200e46a328..bb970b7cd54 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -96,6 +96,7 @@ module API
# Ensure that memeber exists
source.members.find_by!(user_id: params[:user_id])
+ status 204
::Members::DestroyService.new(source, current_user, declared_params).execute
end
end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index ac33b2b801c..6e2e13e0a24 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -137,6 +137,7 @@ module API
merge_request = find_project_merge_request(params[:merge_request_iid])
authorize!(:destroy_merge_request, merge_request)
+ status 204
merge_request.destroy
end
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 01ca62b593f..65ff89edf65 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -131,6 +131,7 @@ module API
note = user_project.notes.find(params[:note_id])
authorize! :admin_note, note
+ status 204
::Notes::DestroyService.new(user_project, current_user).execute(note)
end
end
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 7a345289617..649dd891f56 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -96,6 +96,7 @@ module API
delete ":id/hooks/:hook_id" do
hook = user_project.hooks.find(params.delete(:hook_id))
+ status 204
hook.destroy
end
end
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index 3320eadff0d..f3d905b0068 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -116,6 +116,7 @@ module API
not_found!('Snippet') unless snippet
authorize! :admin_project_snippet, snippet
+ status 204
snippet.destroy
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index c459257158d..89dda88d3f5 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -361,6 +361,7 @@ module API
authorize! :remove_fork_project, user_project
if user_project.forked?
+ status 204
user_project.forked_project_link.destroy
else
not_modified!
@@ -405,6 +406,7 @@ module API
link = user_project.project_group_links.find_by(group_id: params[:group_id])
not_found!('Group Link') unless link
+ status 204
link.destroy
end
diff --git a/lib/api/runner.rb b/lib/api/runner.rb
index 4552115b3e2..405d25ca3c1 100644
--- a/lib/api/runner.rb
+++ b/lib/api/runner.rb
@@ -45,6 +45,7 @@ module API
end
delete '/' do
authenticate_runner!
+ status 204
Ci::Runner.find_by_token(params[:token]).destroy
end
diff --git a/lib/api/runners.rb b/lib/api/runners.rb
index db6c7c59092..5bf5a18e42f 100644
--- a/lib/api/runners.rb
+++ b/lib/api/runners.rb
@@ -79,6 +79,7 @@ module API
runner = get_runner(params[:id])
authenticate_delete_runner!(runner)
+ status 204
runner.destroy!
end
end
@@ -134,6 +135,7 @@ module API
runner = runner_project.runner
forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1
+ status 204
runner_project.destroy
end
end
diff --git a/lib/api/snippets.rb b/lib/api/snippets.rb
index fd634037a77..35ece56c65c 100644
--- a/lib/api/snippets.rb
+++ b/lib/api/snippets.rb
@@ -123,6 +123,7 @@ module API
authorize! :destroy_personal_snippet, snippet
+ status 204
snippet.destroy
end
diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb
index ed7b23b474a..c0179037440 100644
--- a/lib/api/system_hooks.rb
+++ b/lib/api/system_hooks.rb
@@ -66,6 +66,7 @@ module API
hook = SystemHook.find_by(id: params[:id])
not_found!('System hook') unless hook
+ status 204
hook.destroy
end
end
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
index a9f2ca2608e..cb0619105e1 100644
--- a/lib/api/triggers.rb
+++ b/lib/api/triggers.rb
@@ -142,6 +142,7 @@ module API
trigger = user_project.triggers.find(params.delete(:trigger_id))
return not_found!('Trigger') unless trigger
+ status 204
trigger.destroy
end
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 81c68ea2658..a590f2692a2 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -235,6 +235,7 @@ module API
key = user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
+ status 204
key.destroy
end
@@ -306,6 +307,7 @@ module API
user = User.find_by(id: params[:id])
not_found!('User') unless user
+ status 204
user.delete_async(deleted_by: current_user, params: params)
end
@@ -406,6 +408,7 @@ module API
requires :impersonation_token_id, type: Integer, desc: 'The ID of the impersonation token'
end
delete ':impersonation_token_id' do
+ status 204
find_impersonation_token.revoke!
end
end
@@ -483,6 +486,7 @@ module API
key = current_user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
+ status 204
key.destroy
end
@@ -534,6 +538,7 @@ module API
email = current_user.emails.find_by(id: params[:email_id])
not_found!('Email') unless email
+ status 204
Emails::DestroyService.new(current_user, email: email.email).execute
end
diff --git a/lib/api/variables.rb b/lib/api/variables.rb
index 7fa528fb2d3..7c0fdd3d1be 100644
--- a/lib/api/variables.rb
+++ b/lib/api/variables.rb
@@ -88,6 +88,7 @@ module API
variable = user_project.variables.find_by(key: params[:key])
not_found!('Variable') unless variable
+ status 204
variable.destroy
end
end
diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb
index edd7795eef0..85e6db0a689 100644
--- a/lib/gitlab/ee_compat_check.rb
+++ b/lib/gitlab/ee_compat_check.rb
@@ -237,6 +237,10 @@ module Gitlab
branch_name.parameterize << '.patch'
end
+ def patch_url
+ "https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/#{ENV['CI_JOB_ID']}/artifacts/raw/ee_compat_check/patches/#{ce_patch_name}"
+ end
+
def step(desc, cmd = nil)
puts "\n=> #{desc}\n"
@@ -303,14 +307,11 @@ module Gitlab
2. Apply your branch's patch to EE
- # In the CE repo
- $ git fetch origin master
- $ git diff --binary origin/master...HEAD -- > #{ce_branch}.patch
-
# In the EE repo
$ git fetch origin master
$ git checkout -b #{ee_branch_prefix} origin/master
- $ git apply --3way path/to/#{ce_branch}.patch
+ $ wget #{patch_url}
+ $ git apply --3way #{ce_patch_name}
At this point you might have conflicts such as:
@@ -324,7 +325,7 @@ module Gitlab
If the patch couldn't be applied cleanly, use the following command:
# In the EE repo
- $ git apply --reject path/to/#{ce_branch}.patch
+ $ git apply --reject #{ce_patch_name}
This option makes git apply the parts of the patch that are applicable,
and leave the rejected hunks in corresponding `.rej` files.
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
index 76a562f356e..09511cc6504 100644
--- a/lib/gitlab/git/commit.rb
+++ b/lib/gitlab/git/commit.rb
@@ -98,17 +98,13 @@ module Gitlab
# Commit.between(repo, '29eda46b', 'master')
#
def between(repo, base, head)
- commits = Gitlab::GitalyClient.migrate(:commits_between) do |is_enabled|
+ Gitlab::GitalyClient.migrate(:commits_between) do |is_enabled|
if is_enabled
repo.gitaly_commit_client.between(base, head)
else
- repo.commits_between(base, head)
+ repo.commits_between(base, head).map { |c| decorate(c) }
end
end
-
- commits.map do |commit|
- decorate(commit)
- end
rescue Rugged::ReferenceError
[]
end
@@ -135,6 +131,16 @@ module Gitlab
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/326
def find_all(repo, options = {})
+ Gitlab::GitalyClient.migrate(:find_all_commits) do |is_enabled|
+ if is_enabled
+ find_all_by_gitaly(repo, options)
+ else
+ find_all_by_rugged(repo, options)
+ end
+ end
+ end
+
+ def find_all_by_rugged(repo, options = {})
actual_options = options.dup
allowed_options = [:ref, :max_count, :skip, :order]
@@ -173,6 +179,10 @@ module Gitlab
[]
end
+ def find_all_by_gitaly(repo, options = {})
+ Gitlab::GitalyClient::CommitService.new(repo).find_all_commits(options)
+ end
+
def decorate(commit, ref = nil)
Gitlab::Git::Commit.new(commit, ref)
end
@@ -214,11 +224,12 @@ module Gitlab
def initialize(raw_commit, head = nil)
raise "Nil as raw commit passed" unless raw_commit
- if raw_commit.is_a?(Hash)
+ case raw_commit
+ when Hash
init_from_hash(raw_commit)
- elsif raw_commit.is_a?(Rugged::Commit)
+ when Rugged::Commit
init_from_rugged(raw_commit)
- elsif raw_commit.is_a?(Gitaly::GitCommit)
+ when Gitlab::GitalyClient::Commit
init_from_gitaly(raw_commit)
else
raise "Invalid raw commit type: #{raw_commit.class}"
@@ -298,7 +309,14 @@ module Gitlab
end
def parents
- raw_commit.parents.map { |c| Gitlab::Git::Commit.new(c) }
+ case raw_commit
+ when Rugged::Commit
+ raw_commit.parents.map { |c| Gitlab::Git::Commit.new(c) }
+ when Gitlab::GitalyClient::Commit
+ parent_ids.map { |oid| self.class.find(raw_commit.repository, oid) }.compact
+ else
+ raise NotImplementedError, "commit source doesn't support #parents"
+ end
end
def stats
diff --git a/lib/gitlab/gitaly_client/commit.rb b/lib/gitlab/gitaly_client/commit.rb
new file mode 100644
index 00000000000..61fe462d762
--- /dev/null
+++ b/lib/gitlab/gitaly_client/commit.rb
@@ -0,0 +1,14 @@
+module Gitlab
+ module GitalyClient
+ class Commit
+ attr_reader :repository, :gitaly_commit
+
+ delegate :id, :subject, :body, :author, :committer, :parent_ids, to: :gitaly_commit
+
+ def initialize(repository, gitaly_commit)
+ @repository = repository
+ @gitaly_commit = gitaly_commit
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index 6d5673ad2bc..c6e52b530b3 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -105,6 +105,19 @@ module Gitlab
consume_commits_response(response)
end
+ def find_all_commits(opts = {})
+ request = Gitaly::FindAllCommitsRequest.new(
+ repository: @gitaly_repo,
+ revision: opts[:ref].to_s,
+ max_count: opts[:max_count].to_i,
+ skip: opts[:skip].to_i
+ )
+ request.order = opts[:order].upcase if opts[:order].present?
+
+ response = GitalyClient.call(@repository.storage, :commit_service, :find_all_commits, request)
+ consume_commits_response(response)
+ end
+
private
def commit_diff_request_params(commit, options = {})
@@ -119,7 +132,12 @@ module Gitlab
end
def consume_commits_response(response)
- response.flat_map { |r| r.commits }
+ response.flat_map do |message|
+ message.commits.map do |gitaly_commit|
+ commit = GitalyClient::Commit.new(@repository, gitaly_commit)
+ Gitlab::Git::Commit.new(commit)
+ end
+ end
end
end
end
diff --git a/lib/gitlab/untrusted_regexp.rb b/lib/gitlab/untrusted_regexp.rb
index 8b43f0053d6..925b2158a22 100644
--- a/lib/gitlab/untrusted_regexp.rb
+++ b/lib/gitlab/untrusted_regexp.rb
@@ -22,13 +22,28 @@ module Gitlab
end
def scan(text)
- scan_regexp.scan(text).map do |match|
- if regexp.number_of_capturing_groups == 0
- match.first
- else
- match
- end
+ text = text.dup # modified in-place
+ results = []
+
+ loop do
+ match = scan_regexp.match(text)
+ break unless match
+
+ # Ruby scan returns empty strings, not nil
+ groups = match.to_a.map(&:to_s)
+
+ results <<
+ if regexp.number_of_capturing_groups.zero?
+ groups[0]
+ else
+ groups[1..-1]
+ end
+
+ text.slice!(0, match.end(0) || 1)
+ break unless text.present?
end
+
+ results
end
def replace(text, rewrite)
@@ -43,7 +58,7 @@ module Gitlab
# groups, so work around it
def scan_regexp
@scan_regexp ||=
- if regexp.number_of_capturing_groups == 0
+ if regexp.number_of_capturing_groups.zero?
RE2::Regexp.new('(' + regexp.source + ')')
else
regexp
diff --git a/lib/tasks/gitlab/task_helpers.rb b/lib/tasks/gitlab/task_helpers.rb
index 964aa0fe1bc..28b2d86eed2 100644
--- a/lib/tasks/gitlab/task_helpers.rb
+++ b/lib/tasks/gitlab/task_helpers.rb
@@ -153,7 +153,6 @@ module Gitlab
clone_repo(repo, target_dir) unless Dir.exist?(target_dir)
checkout_version(version, target_dir)
- reset_to_version(version, target_dir)
end
def clone_repo(repo, target_dir)
@@ -161,12 +160,8 @@ module Gitlab
end
def checkout_version(version, target_dir)
- run_command!(%W[#{Gitlab.config.git.bin_path} -C #{target_dir} fetch --quiet])
- run_command!(%W[#{Gitlab.config.git.bin_path} -C #{target_dir} checkout --quiet #{version}])
- end
-
- def reset_to_version(version, target_dir)
- run_command!(%W[#{Gitlab.config.git.bin_path} -C #{target_dir} reset --hard #{version}])
+ run_command!(%W[#{Gitlab.config.git.bin_path} -C #{target_dir} fetch --quiet origin #{version}])
+ run_command!(%W[#{Gitlab.config.git.bin_path} -C #{target_dir} checkout -f --quiet FETCH_HEAD --])
end
end
end
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index e61cf0e5152..05173ed12c0 100644
--- a/locale/zh_TW/gitlab.po
+++ b/locale/zh_TW/gitlab.po
@@ -7,13 +7,13 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-06-28 13:32+0200\n"
+"POT-Creation-Date: 2017-07-05 08:50-0500\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2017-07-11 09:10-0400\n"
-"Last-Translator: Lin Jen-Shin <godfat@godfat.org>\n"
"Language-Team: Chinese (Taiwan) (https://translate.zanata.org/project/view/GitLab)\n"
+"PO-Revision-Date: 2017-07-20 09:50-0400\n"
+"Last-Translator: Lin Jen-Shin <godfat@godfat.org>\n"
"Language: zh-TW\n"
"X-Generator: Zanata 3.9.6\n"
"Plural-Forms: nplurals=1; plural=0\n"
@@ -624,6 +624,12 @@ msgstr "所有"
msgid "PipelineSchedules|Inactive"
msgstr "未啟用"
+msgid "PipelineSchedules|Input variable key"
+msgstr "變數名稱"
+
+msgid "PipelineSchedules|Input variable value"
+msgstr "變數值"
+
msgid "PipelineSchedules|Next Run"
msgstr "下次執行時間"
@@ -633,12 +639,18 @@ msgstr "無"
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "請簡單說明此流水線 (pipeline) "
+msgid "PipelineSchedules|Remove variable row"
+msgstr "刪除變數"
+
msgid "PipelineSchedules|Take ownership"
msgstr "取得所有權"
msgid "PipelineSchedules|Target"
msgstr "目標"
+msgid "PipelineSchedules|Variables"
+msgstr "變數"
+
msgid "PipelineSheduleIntervalPattern|Custom"
msgstr "自訂"
@@ -759,13 +771,13 @@ msgid "Revert this merge request"
msgstr "還原此合併請求 (merge request) "
msgid "Save pipeline schedule"
-msgstr "保存流水線 (pipeline) 排程"
+msgstr "儲存流水線 (pipeline) 排程"
msgid "Schedule a new pipeline"
msgstr "建立流水線 (pipeline) 排程"
msgid "Scheduling Pipelines"
-msgstr "流水線 (pipeline) 計劃"
+msgstr "流水線 (pipeline) 排程"
msgid "Search branches and tags"
msgstr "搜尋分支 (branch) 和標籤"
@@ -849,8 +861,7 @@ msgid ""
"specific branches or tags. Those scheduled pipelines will inherit limited "
"project access based on their associated user."
msgstr ""
-"在指定了特定分支 (branch) 或標籤後,此處的流水線 (pipeline) 排程會不斷地重複執行。\n"
-"流水線排程的存取權限與專案本身相同。"
+"在指定了特定分支 (branch) 或標籤後,此處的流水線 (pipeline) 排程會不斷地重複執行。流水線排程的存取權限與專案本身相同。"
msgid ""
"The planning stage shows the time from the previous step to pushing your "
@@ -1097,6 +1108,14 @@ msgid "Withdraw Access Request"
msgstr "取消權限申請"
msgid ""
+"You are going to remove %{group_name}.\n"
+"Removed groups CANNOT be restored!\n"
+"Are you ABSOLUTELY sure?"
+msgstr "即將要刪除 %{group_name}。\n"
+"被刪除的群組完全無法救回來喔!\n"
+"真的「100%確定」要這麼做嗎?"
+
+msgid ""
"You are going to remove %{project_name_with_namespace}.\n"
"Removed project CANNOT be restored!\n"
"Are you ABSOLUTELY sure?"
diff --git a/qa/qa.rb b/qa/qa.rb
index bdfb8237995..db9d8c42fde 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -48,7 +48,14 @@ module QA
module Main
autoload :Entry, 'qa/page/main/entry'
autoload :Menu, 'qa/page/main/menu'
- autoload :Groups, 'qa/page/main/groups'
+ end
+
+ module Dashboard
+ autoload :Groups, 'qa/page/dashboard/groups'
+ end
+
+ module Group
+ autoload :Show, 'qa/page/group/show'
end
module Project
diff --git a/qa/qa/page/main/groups.rb b/qa/qa/page/dashboard/groups.rb
index 169c5ebc967..3690f40dcfe 100644
--- a/qa/qa/page/main/groups.rb
+++ b/qa/qa/page/dashboard/groups.rb
@@ -1,9 +1,11 @@
module QA
module Page
- module Main
+ module Dashboard
class Groups < Page::Base
def prepare_test_namespace
- return if page.has_content?(Runtime::Namespace.name)
+ if page.has_content?(Runtime::Namespace.name)
+ return click_link(Runtime::Namespace.name)
+ end
click_on 'New group'
diff --git a/qa/qa/page/group/show.rb b/qa/qa/page/group/show.rb
new file mode 100644
index 00000000000..296c311d7c6
--- /dev/null
+++ b/qa/qa/page/group/show.rb
@@ -0,0 +1,11 @@
+module QA
+ module Page
+ module Group
+ class Show < Page::Base
+ def go_to_new_project
+ click_link 'New Project'
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index f7c2086d0dd..7ce4e9009f5 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -14,13 +14,6 @@ module QA
within_user_menu { click_link 'Admin area' }
end
- def go_to_new_project
- within_user_menu do
- find('.header-new-dropdown-toggle').click
- click_link('New project')
- end
- end
-
def sign_out
within_user_menu do
find('.header-user-dropdown-toggle').click
diff --git a/qa/qa/scenario/gitlab/project/create.rb b/qa/qa/scenario/gitlab/project/create.rb
index 99d0fc42a94..b860701c304 100644
--- a/qa/qa/scenario/gitlab/project/create.rb
+++ b/qa/qa/scenario/gitlab/project/create.rb
@@ -13,8 +13,8 @@ module QA
def perform
Page::Main::Menu.act { go_to_groups }
- Page::Main::Groups.act { prepare_test_namespace }
- Page::Main::Menu.act { go_to_new_project }
+ Page::Dashboard::Groups.act { prepare_test_namespace }
+ Page::Group::Show.act { go_to_new_project }
Page::Project::New.perform do |page|
page.choose_test_namespace
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index 2b4e8723b48..a22fd8eaf9b 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -1,9 +1,11 @@
require 'spec_helper'
describe SessionsController do
+ include DeviseHelpers
+
describe '#new' do
before do
- @request.env['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: @request)
end
context 'when auto sign-in is enabled' do
@@ -34,7 +36,7 @@ describe SessionsController do
describe '#create' do
before do
- @request.env['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: @request)
end
context 'when using standard authentications' do
@@ -257,7 +259,7 @@ describe SessionsController do
describe '#new' do
before do
- @request.env['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: @request)
end
it 'redirects correctly for referer on same host with params' do
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index b06e7e5037c..46bab3763cc 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -19,7 +19,7 @@ describe "Admin Runners" do
end
it 'has all necessary texts' do
- expect(page).to have_text "To register a new Runner"
+ expect(page).to have_text "How to setup"
expect(page).to have_text "Runners with last contact more than a minute ago: 1"
end
@@ -54,7 +54,7 @@ describe "Admin Runners" do
end
it 'has all necessary texts including no runner message' do
- expect(page).to have_text "To register a new Runner"
+ expect(page).to have_text "How to setup"
expect(page).to have_text "Runners with last contact more than a minute ago: 0"
expect(page).to have_text 'No runners found'
end
@@ -163,12 +163,11 @@ describe "Admin Runners" do
end
it 'has a registration token' do
- expect(page).to have_content("Registration token is #{token}")
- expect(page).to have_selector('#runners-token', text: token)
+ expect(page.find('#registration_token')).to have_content(token)
end
describe 'reload registration token' do
- let(:page_token) { find('#runners-token').text }
+ let(:page_token) { find('#registration_token').text }
before do
click_button 'Reset runners registration token'
diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb
index 1cd1f016674..4740402dc01 100644
--- a/spec/features/issues/user_uses_slash_commands_spec.rb
+++ b/spec/features/issues/user_uses_slash_commands_spec.rb
@@ -21,6 +21,16 @@ feature 'Issues > User uses quick actions', feature: true, js: true do
wait_for_requests
end
+ describe 'time tracking' do
+ let(:issue) { create(:issue, project: project) }
+
+ before do
+ visit project_issue_path(project, issue)
+ end
+
+ it_behaves_like 'issuable time tracker'
+ end
+
describe 'adding a due date from note' do
let(:issue) { create(:issue, project: project) }
@@ -99,32 +109,6 @@ feature 'Issues > User uses quick actions', feature: true, js: true do
end
end
- describe 'Issuable time tracking' do
- let(:issue) { create(:issue, project: project) }
-
- before do
- project.team << [user, :developer]
- end
-
- context 'Issue' do
- before do
- visit project_issue_path(project, issue)
- end
-
- it_behaves_like 'issuable time tracker'
- end
-
- context 'Merge Request' do
- let(:merge_request) { create(:merge_request, source_project: project) }
-
- before do
- visit project_merge_request_path(project, merge_request)
- end
-
- it_behaves_like 'issuable time tracker'
- end
- end
-
describe 'toggling the WIP prefix from the title from note' do
let(:issue) { create(:issue, project: project) }
diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
index 434f5a7c0ac..b2187e01bdb 100644
--- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb
+++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
@@ -24,6 +24,14 @@ feature 'Merge Requests > User uses quick actions', feature: true, js: true do
wait_for_requests
end
+ describe 'time tracking' do
+ before do
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it_behaves_like 'issuable time tracker'
+ end
+
describe 'toggling the WIP prefix in the title from note' do
context 'when the current user can toggle the WIP prefix' do
it 'adds the WIP: prefix to the title' do
diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb
index 42764e808e6..0064c9ef25e 100644
--- a/spec/features/oauth_login_spec.rb
+++ b/spec/features/oauth_login_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
feature 'OAuth Login', js: true do
+ include DeviseHelpers
+
def enter_code(code)
fill_in 'user_otp_attempt', with: code
click_button 'Verify code'
@@ -8,7 +10,7 @@ feature 'OAuth Login', js: true do
def stub_omniauth_config(provider)
OmniAuth.config.add_mock(provider, OmniAuth::AuthHash.new(provider: provider.to_s, uid: "12345"))
- Rails.application.env_config['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: Rails.application)
Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[provider]
end
diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb
index 033ccf06124..de6dd8fc8a6 100644
--- a/spec/features/projects/pipeline_schedules_spec.rb
+++ b/spec/features/projects/pipeline_schedules_spec.rb
@@ -70,6 +70,17 @@ feature 'Pipeline Schedules', :feature, js: true do
expect(first('.branch-name-cell').text).to eq('')
end
end
+
+ context 'when ref is empty' do
+ before do
+ pipeline_schedule.update_attribute(:ref, '')
+ visit_pipelines_schedules
+ end
+
+ it 'shows a list of the pipeline schedules with empty ref column' do
+ expect(first('.branch-name-cell').text).to eq('')
+ end
+ end
end
describe 'POST /projects/pipeline_schedules/new' do
@@ -128,6 +139,19 @@ feature 'Pipeline Schedules', :feature, js: true do
end
end
end
+
+ context 'when ref is empty' do
+ before do
+ pipeline_schedule.update_attribute(:ref, '')
+ edit_pipeline_schedule
+ end
+
+ it 'shows the pipeline schedule with default ref' do
+ page.within('.js-target-branch-dropdown') do
+ expect(first('.dropdown-toggle-text').text).to eq('master')
+ end
+ end
+ end
end
context 'when user creates a new pipeline schedule with variables' do
diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb
index 584d3ed8f42..3319b0fedf3 100644
--- a/spec/features/projects/services/mattermost_slash_command_spec.rb
+++ b/spec/features/projects/services/mattermost_slash_command_spec.rb
@@ -159,7 +159,7 @@ feature 'Setup Mattermost slash commands', :feature, :js do
it 'shows the correct trigger url' do
value = find_field('request_url').value
- expect(value).to match("api/v3/projects/#{project.id}/services/mattermost_slash_commands/trigger")
+ expect(value).to match("api/v4/projects/#{project.id}/services/mattermost_slash_commands/trigger")
end
it 'shows a token placeholder' do
diff --git a/spec/features/projects/services/slack_slash_command_spec.rb b/spec/features/projects/services/slack_slash_command_spec.rb
index 4efe484262a..71f5a8d7a4e 100644
--- a/spec/features/projects/services/slack_slash_command_spec.rb
+++ b/spec/features/projects/services/slack_slash_command_spec.rb
@@ -40,6 +40,6 @@ feature 'Slack slash commands', feature: true do
it 'shows the correct trigger url' do
value = find_field('url').value
- expect(value).to match("api/v3/projects/#{project.id}/services/slack_slash_commands/trigger")
+ expect(value).to match("api/v4/projects/#{project.id}/services/slack_slash_commands/trigger")
end
end
diff --git a/spec/javascripts/filtered_search/dropdown_user_spec.js b/spec/javascripts/filtered_search/dropdown_user_spec.js
index 0132f4b7c93..b3c9bca64cc 100644
--- a/spec/javascripts/filtered_search/dropdown_user_spec.js
+++ b/spec/javascripts/filtered_search/dropdown_user_spec.js
@@ -12,7 +12,9 @@ describe('Dropdown User', () => {
spyOn(gl.DropdownUser.prototype, 'getProjectId').and.callFake(() => {});
spyOn(gl.DropdownUtils, 'getSearchInput').and.callFake(() => {});
- dropdownUser = new gl.DropdownUser(null, null, null, gl.FilteredSearchTokenKeys);
+ dropdownUser = new gl.DropdownUser({
+ tokenKeys: gl.FilteredSearchTokenKeys,
+ });
});
it('should not return the double quote found in value', () => {
@@ -78,7 +80,10 @@ describe('Dropdown User', () => {
loadFixtures(fixtureTemplate);
authorFilterDropdownElement = document.querySelector('#js-dropdown-author');
const dummyInput = document.createElement('div');
- dropdown = new gl.DropdownUser(null, authorFilterDropdownElement, dummyInput);
+ dropdown = new gl.DropdownUser({
+ dropdown: authorFilterDropdownElement,
+ input: dummyInput,
+ });
});
const findCurrentUserElement = () => authorFilterDropdownElement.querySelector('.js-current-user');
diff --git a/spec/javascripts/fixtures/u2f.rb b/spec/javascripts/fixtures/u2f.rb
index c9c0b891237..e3d7986f2cf 100644
--- a/spec/javascripts/fixtures/u2f.rb
+++ b/spec/javascripts/fixtures/u2f.rb
@@ -10,10 +10,12 @@ context 'U2F' do
end
describe SessionsController, '(JavaScript fixtures)', type: :controller do
+ include DeviseHelpers
+
render_views
before do
- @request.env['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: @request)
end
it 'u2f/authenticate.html.raw' do |example|
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 60de91324f0..730fdb112d9 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -91,7 +91,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
committer: committer
)
end
- let(:commit) { described_class.new(gitaly_commit) }
+ let(:commit) { described_class.new(Gitlab::GitalyClient::Commit.new(repository, gitaly_commit)) }
it { expect(commit.short_id).to eq(id[0..10]) }
it { expect(commit.id).to eq(id) }
@@ -290,69 +290,85 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
describe '.find_all' do
- it 'should return a return a collection of commits' do
- commits = described_class.find_all(repository)
+ shared_examples 'finding all commits' do
+ it 'should return a return a collection of commits' do
+ commits = described_class.find_all(repository)
- expect(commits).not_to be_empty
- expect(commits).to all( be_a_kind_of(Gitlab::Git::Commit) )
- end
-
- context 'while applying a sort order based on the `order` option' do
- it "allows ordering topologically (no parents shown before their children)" do
- expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_TOPO)
-
- described_class.find_all(repository, order: :topo)
+ expect(commits).to all( be_a_kind_of(Gitlab::Git::Commit) )
end
- it "allows ordering by date" do
- expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_DATE | Rugged::SORT_TOPO)
-
- described_class.find_all(repository, order: :date)
+ context 'max_count' do
+ subject do
+ commits = Gitlab::Git::Commit.find_all(
+ repository,
+ max_count: 50
+ )
+
+ commits.map(&:id)
+ end
+
+ it 'has 33 elements' do
+ expect(subject.size).to eq(33)
+ end
+
+ it 'includes the expected commits' do
+ expect(subject).to include(
+ SeedRepo::Commit::ID,
+ SeedRepo::Commit::PARENT_ID,
+ SeedRepo::FirstCommit::ID
+ )
+ end
end
- it "applies no sorting by default" do
- expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_NONE)
-
- described_class.find_all(repository)
+ context 'ref + max_count + skip' do
+ subject do
+ commits = Gitlab::Git::Commit.find_all(
+ repository,
+ ref: 'master',
+ max_count: 50,
+ skip: 1
+ )
+
+ commits.map(&:id)
+ end
+
+ it 'has 24 elements' do
+ expect(subject.size).to eq(24)
+ end
+
+ it 'includes the expected commits' do
+ expect(subject).to include(SeedRepo::Commit::ID, SeedRepo::FirstCommit::ID)
+ expect(subject).not_to include(SeedRepo::LastCommit::ID)
+ end
end
end
- context 'max_count' do
- subject do
- commits = Gitlab::Git::Commit.find_all(
- repository,
- max_count: 50
- )
+ context 'when Gitaly find_all_commits feature is enabled' do
+ it_behaves_like 'finding all commits'
+ end
- commits.map { |c| c.id }
- end
+ context 'when Gitaly find_all_commits feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'finding all commits'
- it 'has 31 elements' do
- expect(subject.size).to eq(33)
- end
- it { is_expected.to include(SeedRepo::Commit::ID) }
- it { is_expected.to include(SeedRepo::Commit::PARENT_ID) }
- it { is_expected.to include(SeedRepo::FirstCommit::ID) }
- end
+ context 'while applying a sort order based on the `order` option' do
+ it "allows ordering topologically (no parents shown before their children)" do
+ expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_TOPO)
- context 'ref + max_count + skip' do
- subject do
- commits = Gitlab::Git::Commit.find_all(
- repository,
- ref: 'master',
- max_count: 50,
- skip: 1
- )
+ described_class.find_all(repository, order: :topo)
+ end
- commits.map { |c| c.id }
- end
+ it "allows ordering by date" do
+ expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_DATE | Rugged::SORT_TOPO)
+
+ described_class.find_all(repository, order: :date)
+ end
+
+ it "applies no sorting by default" do
+ expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_NONE)
- it 'has 23 elements' do
- expect(subject.size).to eq(24)
+ described_class.find_all(repository)
+ end
end
- it { is_expected.to include(SeedRepo::Commit::ID) }
- it { is_expected.to include(SeedRepo::FirstCommit::ID) }
- it { is_expected.not_to include(SeedRepo::LastCommit::ID) }
end
end
end
diff --git a/spec/lib/gitlab/untrusted_regexp_spec.rb b/spec/lib/gitlab/untrusted_regexp_spec.rb
index 66045917cb3..a2ef2a27e4c 100644
--- a/spec/lib/gitlab/untrusted_regexp_spec.rb
+++ b/spec/lib/gitlab/untrusted_regexp_spec.rb
@@ -46,10 +46,28 @@ describe Gitlab::UntrustedRegexp do
context 'malicious regexp' do
let(:text) { malicious_text }
let(:regexp) { malicious_regexp }
-
+
include_examples 'malicious regexp'
end
+ context 'empty regexp' do
+ let(:regexp) { '' }
+ let(:text) { 'foo' }
+
+ it 'returns an array of empty matches' do
+ is_expected.to eq(['', '', ''])
+ end
+ end
+
+ context 'empty capture group regexp' do
+ let(:regexp) { '()' }
+ let(:text) { 'foo' }
+
+ it 'returns arrays of empty matches in an array' do
+ is_expected.to eq([[''], [''], ['']])
+ end
+ end
+
context 'no capture group' do
let(:regexp) { '.+' }
let(:text) { 'foo' }
diff --git a/spec/support/devise_helpers.rb b/spec/support/devise_helpers.rb
new file mode 100644
index 00000000000..890a2d9d287
--- /dev/null
+++ b/spec/support/devise_helpers.rb
@@ -0,0 +1,14 @@
+module DeviseHelpers
+ # explicitly tells Devise which mapping to use
+ # this is needed when we are testing a Devise controller bypassing the router
+ def set_devise_mapping(context:)
+ env =
+ if context.respond_to?(:env_config)
+ context.env_config
+ elsif context.respond_to?(:env)
+ context.env
+ end
+
+ env['devise.mapping'] = Devise.mappings[:user] if env
+ end
+end
diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb
index b410a652126..701de9c8c19 100644
--- a/spec/support/login_helpers.rb
+++ b/spec/support/login_helpers.rb
@@ -1,4 +1,6 @@
module LoginHelpers
+ include DeviseHelpers
+
# Internal: Log in as a specific user or a new user of a specific role
#
# user_or_role - User object, or a role to create (e.g., :admin, :user)
@@ -106,7 +108,7 @@ module LoginHelpers
end
def stub_omniauth_saml_config(messages)
- Rails.application.env_config['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: Rails.application)
Rails.application.routes.disable_clear_and_finalize = true
Rails.application.routes.draw do
post '/users/auth/saml' => 'omniauth_callbacks#saml'
diff --git a/spec/support/shared_examples/features/protected_branches_access_control_ce.rb b/spec/support/shared_examples/features/protected_branches_access_control_ce.rb
index 66e598e2691..d5bc12f3bc5 100644
--- a/spec/support/shared_examples/features/protected_branches_access_control_ce.rb
+++ b/spec/support/shared_examples/features/protected_branches_access_control_ce.rb
@@ -5,7 +5,7 @@ shared_examples "protected branches > access control > CE" do
set_protected_branch_name('master')
- within('.new_protected_branch') do
+ within('.js-new-protected-branch') do
allowed_to_push_button = find(".js-allowed-to-push")
unless allowed_to_push_button.text == access_type_name
@@ -50,7 +50,7 @@ shared_examples "protected branches > access control > CE" do
set_protected_branch_name('master')
- within('.new_protected_branch') do
+ within('.js-new-protected-branch') do
allowed_to_merge_button = find(".js-allowed-to-merge")
unless allowed_to_merge_button.text == access_type_name
diff --git a/spec/tasks/gitlab/task_helpers_spec.rb b/spec/tasks/gitlab/task_helpers_spec.rb
index 91cc684d032..d34617be474 100644
--- a/spec/tasks/gitlab/task_helpers_spec.rb
+++ b/spec/tasks/gitlab/task_helpers_spec.rb
@@ -20,7 +20,6 @@ describe Gitlab::TaskHelpers do
it 'checkout the version and reset to it' do
expect(subject).to receive(:checkout_version).with(tag, clone_path)
- expect(subject).to receive(:reset_to_version).with(tag, clone_path)
subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path)
end
@@ -31,7 +30,6 @@ describe Gitlab::TaskHelpers do
it 'checkout the version and reset to it with a branch name' do
expect(subject).to receive(:checkout_version).with(branch, clone_path)
- expect(subject).to receive(:reset_to_version).with(branch, clone_path)
subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path)
end
@@ -70,20 +68,11 @@ describe Gitlab::TaskHelpers do
describe '#checkout_version' do
it 'clones the repo in the target dir' do
expect(subject)
- .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} fetch --quiet])
+ .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} fetch --quiet origin #{tag}])
expect(subject)
- .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} checkout --quiet #{tag}])
+ .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} checkout -f --quiet FETCH_HEAD --])
subject.checkout_version(tag, clone_path)
end
end
-
- describe '#reset_to_version' do
- it 'resets --hard to the given version' do
- expect(subject)
- .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} reset --hard #{tag}])
-
- subject.reset_to_version(tag, clone_path)
- end
- end
end