summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock18
-rw-r--r--app/assets/javascripts/dispatcher.js7
-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_nav.scss18
-rw-r--r--app/assets/stylesheets/pages/projects.scss3
-rw-r--r--app/helpers/triggers_helper.rb2
-rw-r--r--app/views/devise/shared/_omniauth_box.html.haml4
-rw-r--r--app/views/layouts/header/_new.html.haml4
-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/shared/_logo_type.svg1
-rw-r--r--changelogs/unreleased/34549-extract-devise-mappings-into-helper.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/webpack.config.js2
-rw-r--r--doc/administration/auth/ldap.md2
-rw-r--r--doc/development/background_migrations.md36
-rw-r--r--doc/development/sidekiq_style_guide.md7
-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/ci/trace/stream.rb1
-rw-r--r--lib/gitlab/ee_compat_check.rb13
-rw-r--r--lib/gitlab/git/commit.rb38
-rw-r--r--lib/gitlab/git/tree.rb59
-rw-r--r--lib/gitlab/gitaly_client/commit.rb14
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb45
-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/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/fixtures/u2f.rb4
-rw-r--r--spec/lib/gitlab/ci/trace/stream_spec.rb7
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb116
-rw-r--r--spec/lib/gitlab/git/tree_spec.rb23
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb32
-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.rb6
-rw-r--r--spec/support/shared_examples/features/protected_branches_access_control_ce.rb4
-rw-r--r--spec/tasks/gitlab/task_helpers_spec.rb15
82 files changed, 732 insertions, 398 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 084febe175e..adde3400107 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -538,6 +538,8 @@ lint:javascript:report:
<<: *except-docs
<<: *pull-cache
stage: post-test
+ dependencies:
+ - setup-test-env
before_script: []
script:
- find app/ spec/ -name '*.js' -exec sed --in-place 's|/\* eslint-disable .*\*/||' {} \; # run report over all files
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 21574090598..ca222b7cf39 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0.22.0
+0.23.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/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_nav.scss b/app/assets/stylesheets/new_nav.scss
index e1873506bec..9f3e278ebfc 100644
--- a/app/assets/stylesheets/new_nav.scss
+++ b/app/assets/stylesheets/new_nav.scss
@@ -41,10 +41,22 @@ header.navbar-gitlab-new {
}
}
+ .logo-text {
+ line-height: initial;
+
+ svg {
+ width: 55px;
+ height: 15px;
+ margin: 0;
+ fill: $white-light;
+ }
+ }
+
&:hover,
&:focus {
- color: $tanuki-yellow;
- text-decoration: none;
+ .logo-text svg {
+ fill: $tanuki-yellow;
+ }
}
}
}
@@ -274,7 +286,7 @@ header.navbar-gitlab-new {
.breadcrumbs {
display: flex;
- min-height: 60px;
+ min-height: 61px;
color: $gl-text-color;
border-bottom: 1px solid $border-color;
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/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml
index e80d10dc8f1..bfd7dd25a7d 100644
--- a/app/views/devise/shared/_omniauth_box.html.haml
+++ b/app/views/devise/shared/_omniauth_box.html.haml
@@ -7,6 +7,6 @@
%span.light
- has_icon = provider_has_icon?(provider)
= link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: 'oauth-login' + (has_icon ? ' oauth-image-link' : ' btn'), id: "oauth-login-#{provider}"
- %fieldset
+ %fieldset.prepend-top-10
= check_box_tag :remember_me
- = label_tag :remember_me, 'Remember Me'
+ = label_tag :remember_me, 'Remember me'
diff --git a/app/views/layouts/header/_new.html.haml b/app/views/layouts/header/_new.html.haml
index 4697d91724b..76367bd9734 100644
--- a/app/views/layouts/header/_new.html.haml
+++ b/app/views/layouts/header/_new.html.haml
@@ -6,8 +6,8 @@
%h1.title
= link_to root_path, title: 'Dashboard' do
= brand_header_logo
- %span.hidden-xs
- GitLab
+ %span.logo-text.hidden-xs
+ = render 'shared/logo_type.svg'
- if current_user
= render "layouts/nav/new_dashboard"
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/shared/_logo_type.svg b/app/views/shared/_logo_type.svg
new file mode 100644
index 00000000000..7e9276a0a83
--- /dev/null
+++ b/app/views/shared/_logo_type.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 617 169" enable-background="new 0 0 617 169"><path d="m315.26 2.969h-21.8l.1 162.5h88.3v-20.1h-66.5l-.1-142.4"/><path d="m-511.44-6.331c-5.5 5.7-14.6 11.4-27 11.4-16.6 0-23.3-8.2-23.3-18.9 0-16.1 11.2-23.8 35-23.8 4.5 0 11.7.5 15.4 1.2v30.1h-.1m-22.6-98.5c-17.6 0-33.8 6.2-46.4 16.7l7.7 13.4c8.9-5.2 19.8-10.4 35.5-10.4 17.9 0 25.8 9.2 25.8 24.6v7.9c-3.5-.7-10.7-1.2-15.1-1.2-38.2 0-57.6 13.4-57.6 41.4 0 25.1 15.4 37.7 38.7 37.7 15.7 0 30.8-7.2 36-18.9l4 15.9h15.4v-83.2c-.1-26.3-11.5-43.9-44-43.9" transform="translate(977.33 143.28)"/><path d="m-542.14 5.969c-8.2 0-15.4-1-20.8-3.5v-67.3-7.8c7.4-6.2 16.6-10.7 28.3-10.7 21.1 0 29.2 14.9 29.2 39 0 34.2-13.1 50.3-36.7 50.3m9.2-110.6c-19.5 0-30 13.3-30 13.3v-21l-.1-27.8h-9.8-11.5l.1 158.5c10.7 4.5 25.3 6.9 41.2 6.9 40.7 0 60.3-26 60.3-70.9-.1-35.5-18.2-59-50.2-59" transform="translate(1099.77 143.13)"/><path d="m-506.14-123.03c19.3 0 31.8 6.4 39.9 12.9l9.4-16.3c-12.7-11.2-29.9-17.2-48.3-17.2-46.4 0-78.9 28.3-78.9 85.4 0 59.8 35.1 83.1 75.2 83.1 20.1 0 37.2-4.7 48.4-9.4l-.5-63.9v-7.5-12.6h-59.5v20.1h38l.5 48.5c-5 2.5-13.6 4.5-25.3 4.5-32.2 0-53.8-20.3-53.8-63-.1-43.5 22.2-64.6 54.9-64.6" transform="translate(584.04 143.63)"/><path d="m-562.14-139.63h-21.3l.1 27.3v11.2 6.5 11.4 65 .2c0 26.3 11.4 43.9 43.9 43.9 4.5 0 8.9-.4 13.1-1.2v-19.1c-3.1.5-6.4.7-9.9.7-17.9 0-25.8-9.2-25.8-24.6v-65h35.7v-17.8h-35.7l-.1-38.5" transform="translate(793.57 142.58)"/><path d="m155.96 165.47h21.3v-124h-21.3v124"/><path d="m155.96 24.369h21.3v-21.3h-21.3v21.3"/></svg>
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/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/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/administration/auth/ldap.md b/doc/administration/auth/ldap.md
index c8987dea5e2..3449f9e15ce 100644
--- a/doc/administration/auth/ldap.md
+++ b/doc/administration/auth/ldap.md
@@ -228,7 +228,7 @@ Tip: If you want to limit access to the nested members of an Active Directory
group you can use the following syntax:
```
-(memberOf:1.2.840.113556.1.4.1941=CN=My Group,DC=Example,DC=com)
+(memberOf:1.2.840.113556.1.4.1941:=CN=My Group,DC=Example,DC=com)
```
Find more information about this "LDAP_MATCHING_RULE_IN_CHAIN" filter at
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/development/sidekiq_style_guide.md b/doc/development/sidekiq_style_guide.md
index e3a20f29a09..1e9fdbc65e2 100644
--- a/doc/development/sidekiq_style_guide.md
+++ b/doc/development/sidekiq_style_guide.md
@@ -36,3 +36,10 @@ slow jobs blocking work (even for different jobs) on the shared queue.
Each Sidekiq worker must be tested using RSpec, just like any other class. These
tests should be placed in `spec/workers`.
+
+## Removing or renaming queues
+
+Try to avoid renaming or removing queues in minor and patch releases.
+During online update instance can have pending jobs and removing the queue can
+lead to those jobs being stuck forever. If you can't write migration for those
+Sidekiq jobs, please consider doing rename or remove queue in major release only. \ No newline at end of file
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/ci/trace/stream.rb b/lib/gitlab/ci/trace/stream.rb
index 5d6977106d6..aaba034474c 100644
--- a/lib/gitlab/ci/trace/stream.rb
+++ b/lib/gitlab/ci/trace/stream.rb
@@ -74,6 +74,7 @@ module Gitlab
match = ""
reverse_line do |line|
+ line.chomp!
matches = regex.scan(line)
next unless matches.is_a?(Array)
next if matches.empty?
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/git/tree.rb b/lib/gitlab/git/tree.rb
index 8122ff0e81f..8e959c57c7c 100644
--- a/lib/gitlab/git/tree.rb
+++ b/lib/gitlab/git/tree.rb
@@ -17,30 +17,13 @@ module Gitlab
def where(repository, sha, path = nil)
path = nil if path == '' || path == '/'
- commit = repository.lookup(sha)
- root_tree = commit.tree
-
- tree = if path
- id = find_id_by_path(repository, root_tree.oid, path)
- if id
- repository.lookup(id)
- else
- []
- end
- else
- root_tree
- end
-
- tree.map do |entry|
- new(
- id: entry[:oid],
- root_id: root_tree.oid,
- name: entry[:name],
- type: entry[:type],
- mode: entry[:filemode].to_s(8),
- path: path ? File.join(path, entry[:name]) : entry[:name],
- commit_id: sha
- )
+ Gitlab::GitalyClient.migrate(:tree_entries) do |is_enabled|
+ if is_enabled
+ client = Gitlab::GitalyClient::CommitService.new(repository)
+ client.tree_entries(repository, sha, path)
+ else
+ tree_entries_from_rugged(repository, sha, path)
+ end
end
end
@@ -74,6 +57,34 @@ module Gitlab
entry[:oid]
end
end
+
+ def tree_entries_from_rugged(repository, sha, path)
+ commit = repository.lookup(sha)
+ root_tree = commit.tree
+
+ tree = if path
+ id = find_id_by_path(repository, root_tree.oid, path)
+ if id
+ repository.lookup(id)
+ else
+ []
+ end
+ else
+ root_tree
+ end
+
+ tree.map do |entry|
+ new(
+ id: entry[:oid],
+ root_id: root_tree.oid,
+ name: entry[:name],
+ type: entry[:type],
+ mode: entry[:filemode].to_s(8),
+ path: path ? File.join(path, entry[:name]) : entry[:name],
+ commit_id: sha
+ )
+ end
+ end
end
def initialize(options)
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 b749955cddc..c6e52b530b3 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -60,6 +60,31 @@ module Gitlab
entry
end
+ def tree_entries(repository, revision, path)
+ request = Gitaly::GetTreeEntriesRequest.new(
+ repository: @gitaly_repo,
+ revision: revision,
+ path: path.presence || '.'
+ )
+
+ response = GitalyClient.call(@repository.storage, :commit_service, :get_tree_entries, request)
+
+ response.flat_map do |message|
+ message.entries.map do |gitaly_tree_entry|
+ entry_path = gitaly_tree_entry.path.dup
+ Gitlab::Git::Tree.new(
+ id: gitaly_tree_entry.oid,
+ root_id: gitaly_tree_entry.root_oid,
+ type: gitaly_tree_entry.type.downcase,
+ mode: gitaly_tree_entry.mode.to_s(8),
+ name: File.basename(entry_path),
+ path: entry_path,
+ commit_id: gitaly_tree_entry.commit_oid
+ )
+ end
+ end
+ end
+
def commit_count(ref)
request = Gitaly::CountCommitsRequest.new(
repository: @gitaly_repo,
@@ -80,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 = {})
@@ -94,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/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/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/ci/trace/stream_spec.rb b/spec/lib/gitlab/ci/trace/stream_spec.rb
index 13f0338b6aa..3a132fb9989 100644
--- a/spec/lib/gitlab/ci/trace/stream_spec.rb
+++ b/spec/lib/gitlab/ci/trace/stream_spec.rb
@@ -300,5 +300,12 @@ describe Gitlab::Ci::Trace::Stream do
include_examples 'malicious regexp'
end
+
+ context 'multi-line data with rooted regexp' do
+ let(:data) { "\n65%\n" }
+ let(:regex) { '^(\d+)\%$' }
+
+ it { is_expected.to eq('65') }
+ end
end
end
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/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb
index 4b76a43e6b5..98ddd3c3664 100644
--- a/spec/lib/gitlab/git/tree_spec.rb
+++ b/spec/lib/gitlab/git/tree_spec.rb
@@ -1,8 +1,9 @@
require "spec_helper"
describe Gitlab::Git::Tree, seed_helper: true do
+ let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
+
context :repo do
- let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
let(:tree) { Gitlab::Git::Tree.where(repository, SeedRepo::Commit::ID) }
it { expect(tree).to be_kind_of Array }
@@ -74,4 +75,24 @@ describe Gitlab::Git::Tree, seed_helper: true do
it { expect(submodule.name).to eq('gitlab-shell') }
end
end
+
+ describe '#where' do
+ context 'with gitaly disabled' do
+ before do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false)
+ end
+
+ it 'calls #tree_entries_from_rugged' do
+ expect(described_class).to receive(:tree_entries_from_rugged)
+
+ described_class.where(repository, SeedRepo::Commit::ID, '/')
+ end
+ end
+
+ it 'gets the tree entries from GitalyClient' do
+ expect_any_instance_of(Gitlab::GitalyClient::CommitService).to receive(:tree_entries)
+
+ described_class.where(repository, SeedRepo::Commit::ID, '/')
+ end
+ end
end
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index b3b4a1e2218..0868c793a33 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -2,9 +2,13 @@ require 'spec_helper'
describe Gitlab::GitalyClient::CommitService do
let(:project) { create(:project, :repository) }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.path_with_namespace + '.git' }
let(:repository) { project.repository }
let(:repository_message) { repository.gitaly_repository }
- let(:commit) { project.commit('913c66a37b4a45b9769037c55c2d238bd0942d2e') }
+ let(:revision) { '913c66a37b4a45b9769037c55c2d238bd0942d2e' }
+ let(:commit) { project.commit(revision) }
+ let(:client) { described_class.new(repository) }
describe '#diff_from_parent' do
context 'when a commit has a parent' do
@@ -20,7 +24,7 @@ describe Gitlab::GitalyClient::CommitService do
expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_diff).with(request, kind_of(Hash))
- described_class.new(repository).diff_from_parent(commit)
+ client.diff_from_parent(commit)
end
end
@@ -38,12 +42,12 @@ describe Gitlab::GitalyClient::CommitService do
expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_diff).with(request, kind_of(Hash))
- described_class.new(repository).diff_from_parent(initial_commit)
+ client.diff_from_parent(initial_commit)
end
end
it 'returns a Gitlab::Git::DiffCollection' do
- ret = described_class.new(repository).diff_from_parent(commit)
+ ret = client.diff_from_parent(commit)
expect(ret).to be_kind_of(Gitlab::Git::DiffCollection)
end
@@ -53,7 +57,7 @@ describe Gitlab::GitalyClient::CommitService do
expect(Gitlab::Git::DiffCollection).to receive(:new).with(kind_of(Enumerable), options)
- described_class.new(repository).diff_from_parent(commit, options)
+ client.diff_from_parent(commit, options)
end
end
@@ -68,7 +72,7 @@ describe Gitlab::GitalyClient::CommitService do
expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_delta).with(request, kind_of(Hash)).and_return([])
- described_class.new(repository).commit_deltas(commit)
+ client.commit_deltas(commit)
end
end
@@ -83,7 +87,7 @@ describe Gitlab::GitalyClient::CommitService do
expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_delta).with(request, kind_of(Hash)).and_return([])
- described_class.new(repository).commit_deltas(initial_commit)
+ client.commit_deltas(initial_commit)
end
end
end
@@ -91,6 +95,7 @@ describe Gitlab::GitalyClient::CommitService do
describe '#between' do
let(:from) { 'master' }
let(:to) { '4b825dc642cb6eb9a060e54bf8d69288fbee4904' }
+
it 'sends an RPC request' do
request = Gitaly::CommitsBetweenRequest.new(
repository: repository_message, from: from, to: to
@@ -102,4 +107,17 @@ describe Gitlab::GitalyClient::CommitService do
described_class.new(repository).between(from, to)
end
end
+
+ describe '#tree_entries' do
+ let(:path) { '/' }
+
+ it 'sends a get_tree_entries message' do
+ expect_any_instance_of(Gitaly::CommitService::Stub)
+ .to receive(:get_tree_entries)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return([])
+
+ client.tree_entries(repository, revision, path)
+ 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..c714d1b08a6 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)
@@ -62,7 +64,7 @@ module LoginHelpers
visit new_user_session_path
expect(page).to have_content('Sign in with')
- check 'Remember Me' if remember_me
+ check 'remember_me' if remember_me
click_link "oauth-login-#{provider}"
end
@@ -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