Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-21 18:09:44 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-21 18:09:44 +0300
commitb85aae44f96c152c62952f4d3051223cdf0692be (patch)
tree8ce4385b899e0f55b58368c8d5d15b430a8af205
parent79850719759d6fe1b0682fd27573d479c9013f03 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/commons/index.js1
-rw-r--r--app/assets/javascripts/commons/jquery.js4
-rw-r--r--app/assets/javascripts/confirm_danger_modal.js10
-rw-r--r--app/assets/javascripts/lib/utils/csrf.js8
-rw-r--r--app/assets/javascripts/lib/utils/rails_ujs.js20
-rw-r--r--app/assets/javascripts/main.js3
-rw-r--r--app/assets/javascripts/members.js4
-rw-r--r--app/assets/javascripts/monitoring/components/group_empty_state.vue8
-rw-r--r--app/assets/javascripts/namespaces/leave_by_url.js3
-rw-r--r--app/assets/javascripts/notes/components/note_body.vue3
-rw-r--r--app/assets/javascripts/notes/stores/getters.js3
-rw-r--r--app/assets/javascripts/notifications_dropdown.js7
-rw-r--r--app/assets/javascripts/related_issues/components/add_issuable_form.vue3
-rw-r--r--app/assets/javascripts/related_issues/components/related_issuable_input.vue3
-rw-r--r--app/assets/javascripts/releases/components/release_block_assets.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestions.vue9
-rw-r--r--app/helpers/groups/group_members_helper.rb19
-rw-r--r--app/models/clusters/applications/runner.rb2
-rw-r--r--app/models/commit.rb32
-rw-r--r--app/models/merge_request.rb2
-rw-r--r--app/models/merge_request_diff.rb2
-rw-r--r--app/models/note.rb2
-rw-r--r--app/models/service.rb3
-rw-r--r--app/serializers/group_group_link_entity.rb20
-rw-r--r--app/services/ci/update_build_state_service.rb10
-rw-r--r--app/views/projects/diffs/_text_file.html.haml2
-rw-r--r--changelogs/unreleased/display-contributor-and-author-badges-on-notes.yml5
-rw-r--r--changelogs/unreleased/nfriend-fix-release-asset-link-length.yml5
-rw-r--r--changelogs/unreleased/ph-224141-hideBatchSuggestionsWithOnlyOneSuggestion.yml5
-rw-r--r--changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-21-0.yml5
-rw-r--r--config/feature_flags/development/increased_diff_limits.yml (renamed from config/feature_flags/development/show_contributor_on_note.yml)8
-rw-r--r--doc/api/repositories.md3
-rw-r--r--doc/ci/examples/authenticating-with-hashicorp-vault/index.md17
-rw-r--r--doc/development/fe_guide/architecture.md4
-rw-r--r--doc/development/fe_guide/icons.md28
-rw-r--r--doc/development/fe_guide/tooling.md5
-rw-r--r--doc/development/fe_guide/vuex.md5
-rw-r--r--doc/development/new_fe_guide/development/accessibility.md2
-rw-r--r--doc/development/secure_coding_guidelines.md3
-rw-r--r--doc/ssh/README.md2
-rw-r--r--lib/api/ci/runner.rb1
-rw-r--r--lib/gitlab/ci/runner/backoff.rb75
-rw-r--r--lib/gitlab/diff/file_collection/merge_request_diff_base.rb7
-rw-r--r--lib/gitlab/git/diff_collection.rb16
-rw-r--r--lib/gitlab/git/diff_stats_collection.rb4
-rw-r--r--locale/gitlab.pot15
-rw-r--r--package.json2
-rw-r--r--qa/qa/page/project/issue/show.rb6
-rw-r--r--qa/qa/support/wait_for_requests.rb10
-rw-r--r--qa/spec/support/wait_for_requests_spec.rb1
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb1
-rw-r--r--spec/features/merge_request/user_expands_diff_spec.rb1
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb2
-rw-r--r--spec/features/projects/show/user_manages_notifications_spec.rb8
-rw-r--r--spec/fixtures/api/schemas/entities/group_group_link.json4
-rw-r--r--spec/fixtures/api/schemas/group_member.json13
-rw-r--r--spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap174
-rw-r--r--spec/frontend/monitoring/components/group_empty_state_spec.js33
-rw-r--r--spec/frontend/test_setup.js3
-rw-r--r--spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap1
-rw-r--r--spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js8
-rw-r--r--spec/helpers/groups/group_members_helper_spec.rb15
-rw-r--r--spec/lib/gitlab/ci/runner/backoff_spec.rb96
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb17
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb4
-rw-r--r--spec/requests/api/ci/runner/jobs_put_spec.rb29
-rw-r--r--spec/requests/api/merge_requests_spec.rb2
-rw-r--r--spec/requests/api/repositories_spec.rb4
-rw-r--r--spec/serializers/group_group_link_entity_spec.rb22
-rw-r--r--spec/services/ci/update_build_state_service_spec.rb12
-rw-r--r--spec/support/helpers/wait_for_requests.rb11
-rw-r--r--yarn.lock14
75 files changed, 686 insertions, 227 deletions
diff --git a/app/assets/javascripts/commons/index.js b/app/assets/javascripts/commons/index.js
index e0d012cef23..77c85d85e27 100644
--- a/app/assets/javascripts/commons/index.js
+++ b/app/assets/javascripts/commons/index.js
@@ -1,5 +1,4 @@
import './polyfills';
-import './jquery';
import './bootstrap';
import './vue';
import '../lib/utils/axios_utils';
diff --git a/app/assets/javascripts/commons/jquery.js b/app/assets/javascripts/commons/jquery.js
deleted file mode 100644
index 334f95bb27f..00000000000
--- a/app/assets/javascripts/commons/jquery.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import 'jquery';
-
-// common jQuery plugins
-import 'jquery-ujs';
diff --git a/app/assets/javascripts/confirm_danger_modal.js b/app/assets/javascripts/confirm_danger_modal.js
index 262d501bfba..7321e4d18cc 100644
--- a/app/assets/javascripts/confirm_danger_modal.js
+++ b/app/assets/javascripts/confirm_danger_modal.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { Rails } from '~/lib/utils/rails_ujs';
import { rstrip } from './lib/utils/common_utils';
function openConfirmDangerModal($form, $modal, text) {
@@ -21,9 +22,16 @@ function openConfirmDangerModal($form, $modal, text) {
$submit.disable();
}
});
+
$('.js-confirm-danger-submit', $modal)
.off('click')
- .on('click', () => $form.submit());
+ .on('click', () => {
+ if ($form.data('remote')) {
+ Rails.fire($form[0], 'submit');
+ } else {
+ $form.submit();
+ }
+ });
}
function getModal($btn) {
diff --git a/app/assets/javascripts/lib/utils/csrf.js b/app/assets/javascripts/lib/utils/csrf.js
index ca9828c4682..3114a2a0dfb 100644
--- a/app/assets/javascripts/lib/utils/csrf.js
+++ b/app/assets/javascripts/lib/utils/csrf.js
@@ -1,5 +1,3 @@
-import $ from 'jquery';
-
/*
This module provides easy access to the CSRF token and caches
it for re-use. It also exposes some values commonly used in relation
@@ -20,7 +18,6 @@ If you need to compose a headers object, use the spread operator:
see also http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf
and https://github.com/rails/jquery-rails/blob/v4.3.1/vendor/assets/javascripts/jquery_ujs.js#L59-L62
*/
-
const csrf = {
init() {
const tokenEl = document.querySelector('meta[name=csrf-token]');
@@ -52,9 +49,4 @@ const csrf = {
csrf.init();
-// use our cached token for any $.rails-generated AJAX requests
-if ($.rails) {
- $.rails.csrfToken = () => csrf.token;
-}
-
export default csrf;
diff --git a/app/assets/javascripts/lib/utils/rails_ujs.js b/app/assets/javascripts/lib/utils/rails_ujs.js
new file mode 100644
index 00000000000..8b40cc7bd11
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/rails_ujs.js
@@ -0,0 +1,20 @@
+import Rails from '@rails/ujs';
+
+export const initRails = () => {
+ // eslint-disable-next-line no-underscore-dangle
+ if (!window._rails_loaded) {
+ Rails.start();
+
+ // Count XHR requests for tests. See spec/support/helpers/wait_for_requests.rb
+ window.pendingRailsUJSRequests = 0;
+ document.body.addEventListener('ajax:complete', () => {
+ window.pendingRailsUJSRequests -= 1;
+ });
+
+ document.body.addEventListener('ajax:beforeSend', () => {
+ window.pendingRailsUJSRequests += 1;
+ });
+ }
+};
+
+export { Rails };
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 9fcf881a1ac..f4882f3994f 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -11,6 +11,7 @@ import './behaviors';
// lib/utils
import applyGitLabUIConfig from '@gitlab/ui/dist/config';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+import { initRails } from '~/lib/utils/rails_ujs';
import {
handleLocationHash,
addSelectOnFocusBehaviour,
@@ -169,6 +170,8 @@ function deferredInitialisation() {
// Adding a helper class to activate animations only after all is rendered
setTimeout(() => $body.addClass('page-initialised'), 1000);
+
+ initRails();
}
document.addEventListener('DOMContentLoaded', () => {
diff --git a/app/assets/javascripts/members.js b/app/assets/javascripts/members.js
index c3fbb5d6acf..68fca706ce5 100644
--- a/app/assets/javascripts/members.js
+++ b/app/assets/javascripts/members.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { Rails } from '~/lib/utils/rails_ujs';
import { disableButtonIfEmptyField } from '~/lib/utils/common_utils';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
@@ -54,8 +55,9 @@ export default class Members {
formSubmit(e, $el = null) {
const $this = e ? $(e.currentTarget) : $el;
const { $toggle, $dateInput } = this.getMemberListItems($this);
+ const formEl = $this.closest('form').get(0);
- $this.closest('form').trigger('submit.rails');
+ Rails.fire(formEl, 'submit');
$toggle.disable();
$dateInput.disable();
diff --git a/app/assets/javascripts/monitoring/components/group_empty_state.vue b/app/assets/javascripts/monitoring/components/group_empty_state.vue
index 499823fae3f..0365fc66331 100644
--- a/app/assets/javascripts/monitoring/components/group_empty_state.vue
+++ b/app/assets/javascripts/monitoring/components/group_empty_state.vue
@@ -1,6 +1,5 @@
<script>
-/* eslint-disable vue/no-v-html */
-import { GlEmptyState } from '@gitlab/ui';
+import { GlEmptyState, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import { metricStates } from '../constants';
@@ -8,6 +7,9 @@ export default {
components: {
GlEmptyState,
},
+ directives: {
+ SafeHtml,
+ },
props: {
documentationPath: {
type: String,
@@ -100,7 +102,7 @@ export default {
:compact="true"
>
<template v-if="currentState.slottedDescription" #description>
- <div v-html="currentState.slottedDescription"></div>
+ <div v-safe-html="currentState.slottedDescription"></div>
</template>
</gl-empty-state>
</template>
diff --git a/app/assets/javascripts/namespaces/leave_by_url.js b/app/assets/javascripts/namespaces/leave_by_url.js
index bf77617d516..7b15253d872 100644
--- a/app/assets/javascripts/namespaces/leave_by_url.js
+++ b/app/assets/javascripts/namespaces/leave_by_url.js
@@ -1,3 +1,4 @@
+import { initRails } from '~/lib/utils/rails_ujs';
import { deprecatedCreateFlash as Flash } from '~/flash';
import { __, sprintf } from '~/locale';
import { getParameterByName } from '~/lib/utils/common_utils';
@@ -11,6 +12,8 @@ export default function leaveByUrl(namespaceType) {
const param = getParameterByName(PARAMETER_NAME);
if (!param) return;
+ initRails();
+
const leaveLink = document.querySelector(LEAVE_LINK_SELECTOR);
if (leaveLink) {
leaveLink.click();
diff --git a/app/assets/javascripts/notes/components/note_body.vue b/app/assets/javascripts/notes/components/note_body.vue
index 314fa762768..65b89b94eaa 100644
--- a/app/assets/javascripts/notes/components/note_body.vue
+++ b/app/assets/javascripts/notes/components/note_body.vue
@@ -45,7 +45,7 @@ export default {
},
},
computed: {
- ...mapGetters(['getDiscussion']),
+ ...mapGetters(['getDiscussion', 'suggestionsCount']),
discussion() {
if (!this.note.isDraft) return {};
@@ -125,6 +125,7 @@ export default {
<suggestions
v-if="hasSuggestion && !isEditing"
:suggestions="note.suggestions"
+ :suggestions-count="suggestionsCount"
:batch-suggestions-info="batchSuggestionsInfo"
:note-html="note.note_html"
:line-type="lineType"
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index 7d60fbffb10..fbdb71925ea 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -231,3 +231,6 @@ export const getDiscussion = state => discussionId =>
state.discussions.find(discussion => discussion.id === discussionId);
export const commentsDisabled = state => state.commentsDisabled;
+
+export const suggestionsCount = (state, getters) =>
+ Object.values(getters.notesById).filter(n => n.suggestions.length).length;
diff --git a/app/assets/javascripts/notifications_dropdown.js b/app/assets/javascripts/notifications_dropdown.js
index 47fb5b271d1..ae992dd5dc5 100644
--- a/app/assets/javascripts/notifications_dropdown.js
+++ b/app/assets/javascripts/notifications_dropdown.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { Rails } from '~/lib/utils/rails_ujs';
import { deprecatedCreateFlash as Flash } from './flash';
import { __ } from '~/locale';
@@ -21,10 +22,12 @@ export default function notificationsDropdown() {
form.find('.js-notifications-icon').toggleClass('hidden');
}
form.find('#notification_setting_level').val(notificationLevel);
- form.submit();
+ Rails.fire(form[0], 'submit');
});
- $(document).on('ajax:success', '.notification-form', (e, data) => {
+ $(document).on('ajax:success', '.notification-form', e => {
+ const data = e.detail[0];
+
if (data.saved) {
$(e.currentTarget)
.closest('.js-notification-dropdown')
diff --git a/app/assets/javascripts/related_issues/components/add_issuable_form.vue b/app/assets/javascripts/related_issues/components/add_issuable_form.vue
index 63d61989cba..6fbae95094a 100644
--- a/app/assets/javascripts/related_issues/components/add_issuable_form.vue
+++ b/app/assets/javascripts/related_issues/components/add_issuable_form.vue
@@ -195,7 +195,8 @@ export default {
:disabled="isSubmitButtonDisabled"
:loading="isSubmitting"
type="submit"
- class="js-add-issuable-form-add-button float-left qa-add-issue-button"
+ class="js-add-issuable-form-add-button float-left"
+ data-qa-selector="add_issue_button"
>
{{ __('Add') }}
</gl-button>
diff --git a/app/assets/javascripts/related_issues/components/related_issuable_input.vue b/app/assets/javascripts/related_issues/components/related_issuable_input.vue
index 1931cfb2c00..9809b228308 100644
--- a/app/assets/javascripts/related_issues/components/related_issuable_input.vue
+++ b/app/assets/javascripts/related_issues/components/related_issuable_input.vue
@@ -219,7 +219,8 @@ export default {
:value="inputValue"
:placeholder="inputPlaceholder"
type="text"
- class="js-add-issuable-form-input add-issuable-form-input qa-add-issue-input"
+ class="js-add-issuable-form-input add-issuable-form-input"
+ data-qa-selector="add_issue_field"
@input="onInput"
@focus="onFocus"
@blur="onBlur"
diff --git a/app/assets/javascripts/releases/components/release_block_assets.vue b/app/assets/javascripts/releases/components/release_block_assets.vue
index 8824cbefd7e..60d2b3adfc9 100644
--- a/app/assets/javascripts/releases/components/release_block_assets.vue
+++ b/app/assets/javascripts/releases/components/release_block_assets.vue
@@ -119,7 +119,7 @@ export default {
{{ section.title }}
</h5>
<ul :key="`section-body-${index}`" class="list-unstyled gl-m-0">
- <li v-for="link in section.links" :key="link.url">
+ <li v-for="link in section.links" :key="link.url" class="gl-display-flex">
<gl-link
:href="link.directAssetUrl || link.url"
class="gl-display-flex gl-align-items-center gl-line-height-24"
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
index 05ad7b4ea3e..406677941b7 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
@@ -26,11 +26,14 @@ export default {
methods: {
listenForQuickActions() {
$(document).on('ajax:success', '.gfm-form', this.quickActionListened);
+
eventHub.$on('timeTrackingUpdated', data => {
- this.quickActionListened(null, data);
+ this.quickActionListened({ detail: [data] });
});
},
- quickActionListened(e, data) {
+ quickActionListened(e) {
+ const data = e.detail[0];
+
const subscribedCommands = ['spend_time', 'time_estimate'];
let changedCommands;
if (data !== undefined) {
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue
index 13c42d35b04..13ec7a6ada9 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue
@@ -27,6 +27,11 @@ export default {
type: String,
required: true,
},
+ suggestionsCount: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
computed: {
batchSuggestionsCount() {
@@ -62,6 +67,7 @@ export default {
<div class="md-suggestion">
<suggestion-diff-header
class="qa-suggestion-diff-header js-suggestion-diff-header"
+ :suggestions-count="suggestionsCount"
:can-apply="suggestion.appliable && suggestion.current_user.can_apply && !disabled"
:is-applied="suggestion.applied"
:is-batched="isBatched"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
index 1fc54d2f52e..fb9636ba734 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
@@ -42,6 +42,11 @@ export default {
required: false,
default: null,
},
+ suggestionsCount: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
data() {
return {
@@ -127,7 +132,7 @@ export default {
</div>
<div v-else class="d-flex align-items-center">
<gl-button
- v-if="canBeBatched && !isDisableButton"
+ v-if="suggestionsCount > 1 && canBeBatched && !isDisableButton"
class="btn-inverted js-add-to-batch-btn btn-grouped"
:disabled="isDisableButton"
@click="addSuggestionToBatch"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
index 083f581af05..927a93487e6 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
@@ -38,6 +38,11 @@ export default {
type: String,
required: true,
},
+ suggestionsCount: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
data() {
return {
@@ -77,12 +82,12 @@ export default {
this.isRendered = true;
},
generateDiff(suggestionIndex) {
- const { suggestions, disabled, batchSuggestionsInfo, helpPagePath } = this;
+ const { suggestions, disabled, batchSuggestionsInfo, helpPagePath, suggestionsCount } = this;
const suggestion =
suggestions && suggestions[suggestionIndex] ? suggestions[suggestionIndex] : {};
const SuggestionDiffComponent = Vue.extend(SuggestionDiff);
const suggestionDiff = new SuggestionDiffComponent({
- propsData: { disabled, suggestion, batchSuggestionsInfo, helpPagePath },
+ propsData: { disabled, suggestion, batchSuggestionsInfo, helpPagePath, suggestionsCount },
});
suggestionDiff.$on('apply', ({ suggestionId, callback }) => {
diff --git a/app/helpers/groups/group_members_helper.rb b/app/helpers/groups/group_members_helper.rb
index dcff2be34da..ba7385973e7 100644
--- a/app/helpers/groups/group_members_helper.rb
+++ b/app/helpers/groups/group_members_helper.rb
@@ -14,7 +14,7 @@ module Groups::GroupMembersHelper
end
def linked_groups_data_json(group_links)
- GroupGroupLinkSerializer.new.represent(group_links).to_json
+ GroupGroupLinkSerializer.new.represent(group_links, { current_user: current_user }).to_json
end
def members_data_json(group, members)
@@ -47,10 +47,10 @@ module Groups::GroupMembersHelper
}
}.merge(member_created_by_data(member.created_by))
- if user.present?
- data[:user] = member_user_data(user)
- else
+ if member.invite?
data[:invite] = member_invite_data(member)
+ elsif user.present?
+ data[:user] = member_user_data(user)
end
data
@@ -77,6 +77,17 @@ module Groups::GroupMembersHelper
avatar_url: avatar_icon_for_user(user, AVATAR_SIZE),
blocked: user.blocked?,
two_factor_enabled: user.two_factor_enabled?
+ }.merge(member_user_status_data(user.status))
+ end
+
+ def member_user_status_data(status)
+ return {} unless status.present?
+
+ {
+ status: {
+ emoji: status.emoji,
+ message_html: status.message_html
+ }
}
end
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index 4983de83800..f35d938c10f 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -3,7 +3,7 @@
module Clusters
module Applications
class Runner < ApplicationRecord
- VERSION = '0.20.1'
+ VERSION = '0.21.0'
self.table_name = 'clusters_applications_runners'
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 5e0fceb23a4..5fe1b451ccd 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -29,12 +29,6 @@ class Commit
delegate :repository, to: :container
delegate :project, to: :repository, allow_nil: true
- DIFF_SAFE_LINES = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines]
-
- # Commits above this size will not be rendered in HTML
- DIFF_HARD_LIMIT_FILES = 1000
- DIFF_HARD_LIMIT_LINES = 50000
-
MIN_SHA_LENGTH = Gitlab::Git::Commit::MIN_SHA_LENGTH
COMMIT_SHA_PATTERN = /\h{#{MIN_SHA_LENGTH},40}/.freeze
EXACT_COMMIT_SHA_PATTERN = /\A#{COMMIT_SHA_PATTERN}\z/.freeze
@@ -80,10 +74,30 @@ class Commit
sha[0..MIN_SHA_LENGTH]
end
- def max_diff_options
+ def diff_safe_lines
+ Gitlab::Git::DiffCollection.default_limits[:max_lines]
+ end
+
+ def diff_hard_limit_files(project: nil)
+ if Feature.enabled?(:increased_diff_limits, project)
+ 2000
+ else
+ 1000
+ end
+ end
+
+ def diff_hard_limit_lines(project: nil)
+ if Feature.enabled?(:increased_diff_limits, project)
+ 75000
+ else
+ 50000
+ end
+ end
+
+ def max_diff_options(project: nil)
{
- max_files: DIFF_HARD_LIMIT_FILES,
- max_lines: DIFF_HARD_LIMIT_LINES
+ max_files: diff_hard_limit_files(project: project),
+ max_lines: diff_hard_limit_lines(project: project)
}
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 639df749774..43baa1cb5cd 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -631,7 +631,7 @@ class MergeRequest < ApplicationRecord
def diff_size
# Calling `merge_request_diff.diffs.real_size` will also perform
# highlighting, which we don't need here.
- merge_request_diff&.real_size || diff_stats&.real_size || diffs.real_size
+ merge_request_diff&.real_size || diff_stats&.real_size(project: project) || diffs.real_size
end
def modified_paths(past_merge_request_diff: nil, fallback_on_overflow: false)
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 880e3cc1ba5..1e02724db9d 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -651,7 +651,7 @@ class MergeRequestDiff < ApplicationRecord
if compare.commits.empty?
new_attributes[:state] = :empty
else
- diff_collection = compare.diffs(Commit.max_diff_options)
+ diff_collection = compare.diffs(Commit.max_diff_options(project: merge_request.project))
new_attributes[:real_size] = diff_collection.real_size
if diff_collection.any?
diff --git a/app/models/note.rb b/app/models/note.rb
index 812d77d5f86..954843505d4 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -322,8 +322,6 @@ class Note < ApplicationRecord
end
def contributor?
- return false unless ::Feature.enabled?(:show_contributor_on_note, project)
-
project&.team&.contributor?(self.author_id)
end
diff --git a/app/models/service.rb b/app/models/service.rb
index c96566612b6..af31cf4a335 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -7,11 +7,8 @@ class Service < ApplicationRecord
include Importable
include ProjectServicesLoggable
include DataFields
- include IgnorableColumns
include FromUnion
- ignore_columns %i[default], remove_with: '13.5', remove_after: '2020-10-22'
-
SERVICE_NAMES = %w[
alerts asana assembla bamboo bugzilla buildkite campfire confluence custom_issue_tracker discord
drone_ci emails_on_push ewm external_wiki flowdock hangouts_chat hipchat irker jira
diff --git a/app/serializers/group_group_link_entity.rb b/app/serializers/group_group_link_entity.rb
index 7a51e1a9316..491c672233d 100644
--- a/app/serializers/group_group_link_entity.rb
+++ b/app/serializers/group_group_link_entity.rb
@@ -1,12 +1,22 @@
# frozen_string_literal: true
class GroupGroupLinkEntity < Grape::Entity
+ include RequestAwareEntity
+
expose :id
expose :created_at
expose :expires_at do |group_link|
group_link.expires_at&.to_time
end
+ expose :can_update do |group_link|
+ can_manage?(group_link)
+ end
+
+ expose :can_remove do |group_link|
+ can_manage?(group_link)
+ end
+
expose :access_level do
expose :human_access, as: :string_value
expose :group_access, as: :integer_value
@@ -23,4 +33,14 @@ class GroupGroupLinkEntity < Grape::Entity
expose :shared_with_group, merge: true, using: GroupBasicEntity
end
+
+ private
+
+ def current_user
+ options[:current_user]
+ end
+
+ def can_manage?(group_link)
+ can?(current_user, :admin_group_member, group_link.shared_group)
+ end
end
diff --git a/app/services/ci/update_build_state_service.rb b/app/services/ci/update_build_state_service.rb
index 61e4c77c1e5..b73d2708b14 100644
--- a/app/services/ci/update_build_state_service.rb
+++ b/app/services/ci/update_build_state_service.rb
@@ -2,7 +2,7 @@
module Ci
class UpdateBuildStateService
- Result = Struct.new(:status, keyword_init: true)
+ Result = Struct.new(:status, :backoff, keyword_init: true)
ACCEPT_TIMEOUT = 5.minutes.freeze
@@ -28,7 +28,9 @@ module Ci
private
def accept_build_state!
- if Time.current - ensure_pending_state.created_at > ACCEPT_TIMEOUT
+ state_created = ensure_pending_state.created_at
+
+ if Time.current - state_created > ACCEPT_TIMEOUT
metrics.increment_trace_operation(operation: :discarded)
return update_build_state!
@@ -40,7 +42,9 @@ module Ci
metrics.increment_trace_operation(operation: :accepted)
- Result.new(status: 202)
+ ::Gitlab::Ci::Runner::Backoff.new(state_created).then do |backoff|
+ Result.new(status: 202, backoff: backoff.to_seconds)
+ end
end
def overwrite_trace!
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index 641a0689c26..a945ff5aedf 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -1,4 +1,4 @@
-- too_big = diff_file.diff_lines.count > Commit::DIFF_SAFE_LINES
+- too_big = diff_file.diff_lines.count > Commit.diff_safe_lines
- if too_big
.suppressed-container
%a.show-suppressed-diff.cursor-pointer.js-show-suppressed-diff= _("Changes suppressed. Click to show.")
diff --git a/changelogs/unreleased/display-contributor-and-author-badges-on-notes.yml b/changelogs/unreleased/display-contributor-and-author-badges-on-notes.yml
new file mode 100644
index 00000000000..163053c1b70
--- /dev/null
+++ b/changelogs/unreleased/display-contributor-and-author-badges-on-notes.yml
@@ -0,0 +1,5 @@
+---
+title: Display Contributor badges on notes
+merge_request: 42576
+author: Mycroft Kang @TaehyeokKang
+type: added
diff --git a/changelogs/unreleased/nfriend-fix-release-asset-link-length.yml b/changelogs/unreleased/nfriend-fix-release-asset-link-length.yml
new file mode 100644
index 00000000000..435929e247c
--- /dev/null
+++ b/changelogs/unreleased/nfriend-fix-release-asset-link-length.yml
@@ -0,0 +1,5 @@
+---
+title: Fix clickable width of release asset links
+merge_request: 42757
+author:
+type: fixed
diff --git a/changelogs/unreleased/ph-224141-hideBatchSuggestionsWithOnlyOneSuggestion.yml b/changelogs/unreleased/ph-224141-hideBatchSuggestionsWithOnlyOneSuggestion.yml
new file mode 100644
index 00000000000..bdd30e0e946
--- /dev/null
+++ b/changelogs/unreleased/ph-224141-hideBatchSuggestionsWithOnlyOneSuggestion.yml
@@ -0,0 +1,5 @@
+---
+title: Hides batch suggestions button if there is only 1 suggestion
+merge_request: 42681
+author:
+type: fixed
diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-21-0.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-21-0.yml
new file mode 100644
index 00000000000..0b4b92717e7
--- /dev/null
+++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-21-0.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Runner Helm Chart to 0.21.0
+merge_request: 42844
+author:
+type: other
diff --git a/config/feature_flags/development/show_contributor_on_note.yml b/config/feature_flags/development/increased_diff_limits.yml
index 89533037244..aeff8e3533d 100644
--- a/config/feature_flags/development/show_contributor_on_note.yml
+++ b/config/feature_flags/development/increased_diff_limits.yml
@@ -1,7 +1,7 @@
---
-name: show_contributor_on_note
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40198
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249179
-group: group::project management
+name: increased_diff_limits
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40357
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/241185
+group: group::source_code
type: development
default_enabled: false \ No newline at end of file
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 305216f853a..7e94ff7b7f2 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -24,7 +24,8 @@ Parameters:
- `path` (optional) - The path inside repository. Used to get content of subdirectories
- `ref` (optional) - The name of a repository branch or tag or if not given the default branch
- `recursive` (optional) - Boolean value used to get a recursive tree (false by default)
-- `per_page` (optional) - Number of results to show per page. If not specified, defaults to `20`
+- `per_page` (optional) - Number of results to show per page. If not specified, defaults to `20`.
+ Read more on [pagination](README.md#pagination).
```json
[
diff --git a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
index 73896547675..4a0ff2fa6ac 100644
--- a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
+++ b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
@@ -41,15 +41,14 @@ The JWT's payload looks like this:
"nbf": 1585798372, # Not valid before
"exp": 1585713886, # Expire at
"sub": "job_1212", # Subject (job id)
- "namespace_id": "1",
- "namespace_path": "mygroup",
- "project_id": "22",
- "project_path": "mygroup/myproject",
- "user_id": "42",
- "user_login": "myuser",
- "user_email": "myuser@example.com",
- "pipeline_id": "1212",
- "job_id": "1212",
+ "namespace_id": "1", # Use this to scope to group or user level namespace by id
+ "namespace_path": "mygroup", # Use this to scope to group or user level namespace by path
+ "project_id": "22", #
+ "project_path": "mygroup/myproject", #
+ "user_id": "42", # Id of the user executing the job
+ "user_email": "myuser@example.com", # Email of the user executing the job
+ "pipeline_id": "1212", #
+ "job_id": "1212", #
"ref": "auto-deploy-2020-04-01", # Git ref for this job
"ref_type": "branch", # Git ref type, branch or tag
"ref_protected": "true" # true if this git ref is protected, false otherwise
diff --git a/doc/development/fe_guide/architecture.md b/doc/development/fe_guide/architecture.md
index 3d27f67a8a6..c7e1ba59f23 100644
--- a/doc/development/fe_guide/architecture.md
+++ b/doc/development/fe_guide/architecture.md
@@ -15,5 +15,5 @@ You can find the Frontend Architecture experts on the [team page](https://about.
## Examples
-You can find documentation about the desired architecture for a new feature
-built with Vue.js [here](vue.md).
+You can find [documentation about the desired architecture](vue.md) for a new
+feature built with Vue.js.
diff --git a/doc/development/fe_guide/icons.md b/doc/development/fe_guide/icons.md
index b539293e9cf..67add5709d9 100644
--- a/doc/development/fe_guide/icons.md
+++ b/doc/development/fe_guide/icons.md
@@ -1,9 +1,10 @@
# Icons and SVG Illustrations
-We manage our own Icon and Illustration library in the [`gitlab-svgs`](https://gitlab.com/gitlab-org/gitlab-svgs) repository.
-This repository is published on [npm](https://www.npmjs.com/package/@gitlab/svgs) and managed as a dependency via yarn.
-You can browse all available Icons and Illustrations [here](https://gitlab-org.gitlab.io/gitlab-svgs).
-To upgrade to a new version run `yarn upgrade @gitlab/svgs`.
+We manage our own icon and illustration library in the [`gitlab-svgs`](https://gitlab.com/gitlab-org/gitlab-svgs)
+repository. This repository is published on [npm](https://www.npmjs.com/package/@gitlab/svgs),
+and is managed as a dependency with yarn. You can browse all available
+[icons and illustrations](https://gitlab-org.gitlab.io/gitlab-svgs). To upgrade
+to a new version run `yarn upgrade @gitlab/svgs`.
## Icons
@@ -21,10 +22,11 @@ To use a sprite Icon in HAML or Rails we use a specific helper function :
sprite_icon(icon_name, size: nil, css_class: '')
```
-- **icon_name** Use the icon_name that you can find in the SVG Sprite
- ([Overview is available here](https://gitlab-org.gitlab.io/gitlab-svgs)).
-- **size (optional)** Use one of the following sizes : 16, 24, 32, 48, 72 (this will be translated into a `s16` class)
-- **css_class (optional)** If you want to add additional CSS classes
+- **icon_name**: Use the icon_name for the SVG sprite in the list of
+ ([GitLab SVGs](https://gitlab-org.gitlab.io/gitlab-svgs)).
+- **size (optional)**: Use one of the following sizes : 16, 24, 32, 48, 72 (this
+ will be translated into a `s16` class)
+- **css_class (optional)**: If you want to add additional CSS classes.
**Example**
@@ -66,10 +68,12 @@ export default {
</template>
```
-- **name** Name of the Icon in the SVG Sprite ([Overview is available here](https://gitlab-org.gitlab.io/gitlab-svgs)).
-- **size (optional)** Number value for the size which is then mapped to a specific CSS class
- (Available Sizes: 8, 12, 16, 18, 24, 32, 48, 72 are mapped to `sXX` CSS classes)
-- **class (optional)** Additional CSS Classes to add to the SVG tag.
+- **name**: Name of the icon of the SVG sprite, as listed in the
+ ([GitLab SVG Previewer](https://gitlab-org.gitlab.io/gitlab-svgs)).
+- **size: (optional)** Number value for the size which is then mapped to a
+ specific CSS class (Available sizes: 8, 12, 16, 18, 24, 32, 48, 72 are mapped
+ to `sXX` CSS classes)
+- **class (optional)**: Additional CSS classes to add to the SVG tag.
### Usage in HTML/JS
diff --git a/doc/development/fe_guide/tooling.md b/doc/development/fe_guide/tooling.md
index 5685ac5abcd..b93c0a9736b 100644
--- a/doc/development/fe_guide/tooling.md
+++ b/doc/development/fe_guide/tooling.md
@@ -101,7 +101,10 @@ Our code is automatically formatted with [Prettier](https://prettier.io) to foll
### Editor
-The easiest way to include prettier in your workflow is by setting up your preferred editor (all major editors are supported) accordingly. We suggest setting up prettier to run automatically when each file is saved. Find [here](https://prettier.io/docs/en/editors.html) the best way to set it up in your preferred editor.
+The recommended method to include Prettier in your workflow is to set up your
+preferred editor (all major editors are supported) accordingly. We suggest
+setting up Prettier to run when each file is saved. For instructions about using
+Prettier in your preferred editor, see the [Prettier documentation](https://prettier.io/docs/en/editors.html).
Please take care that you only let Prettier format the same file types as the global Yarn script does (`.js`, `.vue`, `.graphql`, and `.scss`). In VSCode by example you can easily exclude file formats in your settings file:
diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md
index 4badf3f0845..528dcb3b7f4 100644
--- a/doc/development/fe_guide/vuex.md
+++ b/doc/development/fe_guide/vuex.md
@@ -32,8 +32,9 @@ When using Vuex at GitLab, separate these concerns into different files to impro
└── mutation_types.js # mutation types
```
-The following example shows an application that lists and adds users to the state.
-(For a more complex example implementation take a look at the security applications store in [here](https://gitlab.com/gitlab-org/gitlab/tree/master/ee/app/assets/javascripts/vue_shared/security_reports/store))
+The following example shows an application that lists and adds users to the
+state. (For a more complex example implementation, review the security
+applications stored in this [repository](https://gitlab.com/gitlab-org/gitlab/tree/master/ee/app/assets/javascripts/vue_shared/security_reports/store)).
### `index.js`
diff --git a/doc/development/new_fe_guide/development/accessibility.md b/doc/development/new_fe_guide/development/accessibility.md
index b9ee5c3a549..9c63ccad6e1 100644
--- a/doc/development/new_fe_guide/development/accessibility.md
+++ b/doc/development/new_fe_guide/development/accessibility.md
@@ -12,7 +12,7 @@ WAI-ARIA (the Accessible Rich Internet Applications specification) defines a way
The `role` attribute describes the role the element plays in the context of the document.
-Check the list of WAI-ARIA roles [here](https://www.w3.org/TR/wai-aria-1.1/#landmark_roles)
+Review the list of [WAI-ARIA roles](https://www.w3.org/TR/wai-aria-1.1/#landmark_roles).
## Icons
diff --git a/doc/development/secure_coding_guidelines.md b/doc/development/secure_coding_guidelines.md
index 1961d1dcc34..8e7cc1ec9f2 100644
--- a/doc/development/secure_coding_guidelines.md
+++ b/doc/development/secure_coding_guidelines.md
@@ -82,7 +82,8 @@ This Ruby Regex specialty can have security impact, as often regular expressions
#### Examples
-GitLab specific examples can be found [here](https://gitlab.com/gitlab-org/gitlab/-/issues/36029#note_251262187) and [there](https://gitlab.com/gitlab-org/gitlab/-/issues/33569).
+GitLab-specific examples can be found in the following [path traversal](https://gitlab.com/gitlab-org/gitlab/-/issues/36029#note_251262187)
+and [open redirect](https://gitlab.com/gitlab-org/gitlab/-/issues/33569) issues.
Another example would be this fictional Ruby on Rails controller:
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index 1c5654ae96c..6a4dc5426f8 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -24,7 +24,7 @@ connections to GitLab repositories.
## Requirements
To support SSH, GitLab requires the installation of the OpenSSH client, which
-comes pre-installed on GNU/Linux and macOS, but not on Windows.
+comes pre-installed on GNU/Linux and macOS, as well as on Windows 10.
Make sure that your system includes SSH version 6.5 or newer, as that excludes
the now insecure MD5 signature scheme. The following command returns the version of
diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb
index 08903dce3dc..e293c299d75 100644
--- a/lib/api/ci/runner.rb
+++ b/lib/api/ci/runner.rb
@@ -181,6 +181,7 @@ module API
.new(job, declared_params(include_missing: false))
service.execute.then do |result|
+ header 'X-GitLab-Trace-Update-Interval', result.backoff
status result.status
end
end
diff --git a/lib/gitlab/ci/runner/backoff.rb b/lib/gitlab/ci/runner/backoff.rb
new file mode 100644
index 00000000000..14bbf18941d
--- /dev/null
+++ b/lib/gitlab/ci/runner/backoff.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Runner
+ ##
+ # Runner Backoff class is an implementation of an exponential backoff
+ # used when a runner communicates with GitLab. We typically use it when a
+ # runner retries sending a build status after we created a build pending
+ # state.
+ #
+ # Backoff is calculated based on the backoff slot which is always a power
+ # of 2:
+ #
+ # 0s - 3s duration -> 1 second backoff
+ # 4s - 7s duration -> 2 seconds backoff
+ # 8s - 15s duration -> 4 seconds backoff
+ # 16s - 31s duration -> 8 seconds backoff
+ # 32s - 63s duration -> 16 seconds backoff
+ # 64s - 127s duration -> 32 seconds backoff
+ # 127s - 256s+ duration -> 64 seconds backoff
+ #
+ # It means that first 15 requests made by a runner will need to respect
+ # following backoffs:
+ #
+ # 0s -> 1 second backoff (backoff started, slot 0, 2^0 backoff)
+ # 1s -> 1 second backoff
+ # 2s -> 1 second backoff
+ # 3s -> 1 seconds backoff
+ # (slot 1 - 2^1 backoff)
+ # 4s -> 2 seconds backoff
+ # 6s -> 2 seconds backoff
+ # (slot 2 - 2^2 backoff)
+ # 8s -> 4 seconds backoff
+ # 12s -> 4 seconds backoff
+ # (slot 3 - 2^3 backoff)
+ # 16s -> 8 seconds backoff
+ # 24s -> 8 seconds backoff
+ # (slot 4 - 2^4 backoff)
+ # 32s -> 16 seconds backoff
+ # 48s -> 16 seconds backoff
+ # (slot 5 - 2^5 backoff)
+ # 64s -> 32 seconds backoff
+ # 96s -> 32 seconds backoff
+ # (slot 6 - 2^6 backoff)
+ # 128s -> 64 seconds backoff
+ #
+ # There is a cap on the backoff - it will never exceed 64 seconds.
+ #
+ class Backoff
+ def initialize(started)
+ @started = started
+
+ if duration < 0
+ raise ArgumentError, 'backoff duration negative'
+ end
+ end
+
+ def duration
+ Time.current - @started
+ end
+
+ def slot
+ return 0 if duration <= 1
+
+ Math.log(duration, 2).floor - 1
+ end
+
+ def to_seconds
+ 2**[slot, 6].min
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/file_collection/merge_request_diff_base.rb b/lib/gitlab/diff/file_collection/merge_request_diff_base.rb
index d54e1aad19a..341572f9c94 100644
--- a/lib/gitlab/diff/file_collection/merge_request_diff_base.rb
+++ b/lib/gitlab/diff/file_collection/merge_request_diff_base.rb
@@ -11,7 +11,7 @@ module Gitlab
super(merge_request_diff,
project: merge_request_diff.project,
- diff_options: diff_options,
+ diff_options: merged_diff_options(diff_options),
diff_refs: merge_request_diff.diff_refs,
fallback_diff_refs: merge_request_diff.fallback_diff_refs)
end
@@ -64,6 +64,11 @@ module Gitlab
diff_stats_cache.read || super
end
end
+
+ def merged_diff_options(diff_options)
+ max_diff_options = ::Commit.max_diff_options(project: @merge_request_diff.project)
+ diff_options.present? ? diff_options.merge(max_diff_options) : max_diff_options
+ end
end
end
end
diff --git a/lib/gitlab/git/diff_collection.rb b/lib/gitlab/git/diff_collection.rb
index e6121d688ba..2fa88973bae 100644
--- a/lib/gitlab/git/diff_collection.rb
+++ b/lib/gitlab/git/diff_collection.rb
@@ -7,19 +7,23 @@ module Gitlab
class DiffCollection
include Enumerable
- DEFAULT_LIMITS = { max_files: 100, max_lines: 5000 }.freeze
-
attr_reader :limits
delegate :max_files, :max_lines, :max_bytes, :safe_max_files, :safe_max_lines, :safe_max_bytes, to: :limits
+ def self.default_limits
+ { max_files: 100, max_lines: 5000 }
+ end
+
def self.limits(options = {})
limits = {}
- limits[:max_files] = options.fetch(:max_files, DEFAULT_LIMITS[:max_files])
- limits[:max_lines] = options.fetch(:max_lines, DEFAULT_LIMITS[:max_lines])
+ defaults = default_limits
+ limits[:max_files] = options.fetch(:max_files, defaults[:max_files])
+ limits[:max_lines] = options.fetch(:max_lines, defaults[:max_lines])
limits[:max_bytes] = limits[:max_files] * 5.kilobytes # Average 5 KB per file
- limits[:safe_max_files] = [limits[:max_files], DEFAULT_LIMITS[:max_files]].min
- limits[:safe_max_lines] = [limits[:max_lines], DEFAULT_LIMITS[:max_lines]].min
+
+ limits[:safe_max_files] = [limits[:max_files], defaults[:max_files]].min
+ limits[:safe_max_lines] = [limits[:max_lines], defaults[:max_lines]].min
limits[:safe_max_bytes] = limits[:safe_max_files] * 5.kilobytes # Average 5 KB per file
limits[:max_patch_bytes] = Gitlab::Git::Diff.patch_hard_limit_bytes
diff --git a/lib/gitlab/git/diff_stats_collection.rb b/lib/gitlab/git/diff_stats_collection.rb
index 7e49d79676e..e30ec836a49 100644
--- a/lib/gitlab/git/diff_stats_collection.rb
+++ b/lib/gitlab/git/diff_stats_collection.rb
@@ -22,8 +22,8 @@ module Gitlab
@collection.map(&:path)
end
- def real_size
- max_files = ::Commit.max_diff_options[:max_files]
+ def real_size(project: nil)
+ max_files = ::Commit.max_diff_options(project: project)[:max_files]
if paths.size > max_files
"#{max_files}+"
else
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 1d9c44cfb71..d91a10cae95 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -21061,9 +21061,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -22424,6 +22421,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22457,6 +22457,9 @@ msgstr ""
msgid "SecurityConfiguration|Not enabled"
msgstr ""
+msgid "SecurityConfiguration|SAST Analyzers"
+msgstr ""
+
msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
@@ -26822,6 +26825,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -28329,6 +28335,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
diff --git a/package.json b/package.json
index 307c24c80ce..b9fa6212dc5 100644
--- a/package.json
+++ b/package.json
@@ -46,6 +46,7 @@
"@gitlab/ui": "21.4.2",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-1",
+ "@rails/ujs": "^6.0.3-2",
"@sentry/browser": "^5.22.3",
"@sourcegraph/code-host-integration": "0.0.50",
"@toast-ui/editor": "^2.4.0",
@@ -99,7 +100,6 @@
"jed": "^1.1.1",
"jest-transform-graphql": "^2.1.0",
"jquery": "^3.5.0",
- "jquery-ujs": "1.2.2",
"jquery.caret": "^0.3.1",
"jquery.waitforimages": "^2.2.0",
"js-cookie": "^2.2.1",
diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb
index 826acaa2e0a..6e5d176b812 100644
--- a/qa/qa/page/project/issue/show.rb
+++ b/qa/qa/page/project/issue/show.rb
@@ -43,7 +43,7 @@ module QA
end
view 'app/assets/javascripts/related_issues/components/related_issuable_input.vue' do
- element :add_issue_input
+ element :add_issue_field
end
view 'app/assets/javascripts/related_issues/components/related_issues_block.vue' do
@@ -57,8 +57,8 @@ module QA
def relate_issue(issue)
click_element(:related_issues_plus_button)
- fill_element(:add_issue_input, issue.web_url)
- send_keys_to_element(:add_issue_input, :enter)
+ fill_element(:add_issue_field, issue.web_url)
+ send_keys_to_element(:add_issue_field, :enter)
end
def related_issuable_item
diff --git a/qa/qa/support/wait_for_requests.rb b/qa/qa/support/wait_for_requests.rb
index 2a72f833edc..ebc473a7d86 100644
--- a/qa/qa/support/wait_for_requests.rb
+++ b/qa/qa/support/wait_for_requests.rb
@@ -9,20 +9,14 @@ module QA
def wait_for_requests(skip_finished_loading_check: false)
Waiter.wait_until(log: false) do
- finished_all_ajax_requests? && finished_all_axios_requests? && (!skip_finished_loading_check ? finished_loading?(wait: 1) : true)
+ finished_all_ajax_requests? && (!skip_finished_loading_check ? finished_loading?(wait: 1) : true)
end
rescue Repeater::WaitExceededError
raise $!, 'Page did not fully load. This could be due to an unending async request or loading icon.'
end
- def finished_all_axios_requests?
- Capybara.page.evaluate_script('window.pendingRequests || 0').zero? # rubocop:disable Style/NumericPredicate
- end
-
def finished_all_ajax_requests?
- return true if Capybara.page.evaluate_script('typeof jQuery === "undefined"')
-
- Capybara.page.evaluate_script('jQuery.active').zero? # rubocop:disable Style/NumericPredicate
+ Capybara.page.evaluate_script('window.pendingRequests || window.pendingRailsUJSRequests || 0').zero? # rubocop:disable Style/NumericPredicate
end
def finished_loading?(wait: DEFAULT_MAX_WAIT_TIME)
diff --git a/qa/spec/support/wait_for_requests_spec.rb b/qa/spec/support/wait_for_requests_spec.rb
index 79ee3eb5099..26c4951d198 100644
--- a/qa/spec/support/wait_for_requests_spec.rb
+++ b/qa/spec/support/wait_for_requests_spec.rb
@@ -3,7 +3,6 @@
describe QA::Support::WaitForRequests do
describe '.wait_for_requests' do
before do
- allow(subject).to receive(:finished_all_axios_requests?).and_return(true)
allow(subject).to receive(:finished_all_ajax_requests?).and_return(true)
allow(subject).to receive(:finished_loading?).and_return(true)
end
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index e705f2916da..49343cc7a57 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Expand and collapse diffs', :js do
let(:project) { create(:project, :repository) }
before do
+ stub_feature_flags(increased_diff_limits: false)
sign_in(create(:admin))
# Ensure that undiffable.md is in .gitattributes
diff --git a/spec/features/merge_request/user_expands_diff_spec.rb b/spec/features/merge_request/user_expands_diff_spec.rb
index 0e39cce13a1..a857e6b0ddb 100644
--- a/spec/features/merge_request/user_expands_diff_spec.rb
+++ b/spec/features/merge_request/user_expands_diff_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'User expands diff', :js do
let(:merge_request) { create(:merge_request, source_branch: 'expand-collapse-files', source_project: project, target_project: project) }
before do
+ stub_feature_flags(increased_diff_limits: false)
visit(diffs_project_merge_request_path(project, merge_request))
wait_for_requests
diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
index 39495832547..fe3307c0ceb 100644
--- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
+++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
@@ -130,7 +130,9 @@ RSpec.describe 'User comments on a diff', :js do
wait_for_requests
end
end
+ end
+ files.each_with_index do |file, index|
page.within("[id='#{file[:hash]}']") do
expect(page).not_to have_content('Applied')
diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb
index 9d9a75c22be..d444ea27d35 100644
--- a/spec/features/projects/show/user_manages_notifications_spec.rb
+++ b/spec/features/projects/show/user_manages_notifications_spec.rb
@@ -18,7 +18,9 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do
click_notifications_button
click_link 'On mention'
- wait_for_requests
+ page.within('.notification-dropdown') do
+ expect(page).not_to have_css('.gl-spinner')
+ end
click_notifications_button
expect(find('.update-notification.is-active')).to have_content('On mention')
@@ -30,7 +32,9 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do
click_notifications_button
click_link 'Disabled'
- wait_for_requests
+ page.within('.notification-dropdown') do
+ expect(page).not_to have_css('.gl-spinner')
+ end
expect(page).to have_css('.notifications-icon[data-testid="notifications-off-icon"]')
end
diff --git a/spec/fixtures/api/schemas/entities/group_group_link.json b/spec/fixtures/api/schemas/entities/group_group_link.json
index 4c9aae140d2..dda94dc3362 100644
--- a/spec/fixtures/api/schemas/entities/group_group_link.json
+++ b/spec/fixtures/api/schemas/entities/group_group_link.json
@@ -1,10 +1,12 @@
{
"type": "object",
- "required": ["id", "created_at", "expires_at", "access_level"],
+ "required": ["id", "created_at", "expires_at", "can_update", "can_remove", "access_level"],
"properties": {
"id": { "type": "integer" },
"created_at": { "type": "date-time" },
"expires_at": { "type": ["date-time", "null"] },
+ "can_update": { "type": "boolean" },
+ "can_remove": { "type": "boolean" },
"access_level": {
"type": "object",
"required": ["integer_value", "string_value"],
diff --git a/spec/fixtures/api/schemas/group_member.json b/spec/fixtures/api/schemas/group_member.json
index 035c862d229..eefd4aeb219 100644
--- a/spec/fixtures/api/schemas/group_member.json
+++ b/spec/fixtures/api/schemas/group_member.json
@@ -62,7 +62,18 @@
"avatar_url": { "type": ["string", "null"] },
"web_url": { "type": "string" },
"blocked": { "type": "boolean" },
- "two_factor_enabled": { "type": "boolean" }
+ "two_factor_enabled": { "type": "boolean" },
+ "status": {
+ "type": "object",
+ "required": [
+ "emoji",
+ "message_html"
+ ],
+ "properties": {
+ "emoji": { "type": "string" },
+ "message_html": { "type": "string" }
+ }
+ }
}
},
"invite": {
diff --git a/spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap b/spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap
index c30fb572826..00fcc3323f5 100644
--- a/spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap
+++ b/spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap
@@ -1,79 +1,139 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`GroupEmptyState Renders an empty state for BAD_QUERY 1`] = `
-<gl-empty-state-stub
- compact="true"
- primarybuttonlink="/path/to/settings"
- primarybuttontext="Verify configuration"
- svgpath="/path/to/empty-group-illustration.svg"
- title="Query cannot be processed"
-/>
+exports[`GroupEmptyState given state BAD_QUERY passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": null,
+ "primaryButtonLink": "/path/to/settings",
+ "primaryButtonText": "Verify configuration",
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "Query cannot be processed",
+}
`;
-exports[`GroupEmptyState Renders an empty state for BAD_QUERY 2`] = `"The Prometheus server responded with \\"bad request\\". Please check your queries are correct and are supported in your Prometheus version. <a href=\\"/path/to/docs\\">More information</a>"`;
+exports[`GroupEmptyState given state BAD_QUERY renders the slotted content 1`] = `
+<div>
+ <div>
+ The Prometheus server responded with "bad request". Please check your queries are correct and are supported in your Prometheus version.
+ <a
+ href="/path/to/docs"
+ >
+ More information
+ </a>
+ </div>
+</div>
+`;
-exports[`GroupEmptyState Renders an empty state for CONNECTION_FAILED 1`] = `
-<gl-empty-state-stub
- compact="true"
- description="We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
- primarybuttonlink="/path/to/settings"
- primarybuttontext="Verify configuration"
- svgpath="/path/to/empty-group-illustration.svg"
- title="Connection failed"
-/>
+exports[`GroupEmptyState given state CONNECTION_FAILED passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating.",
+ "primaryButtonLink": "/path/to/settings",
+ "primaryButtonText": "Verify configuration",
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "Connection failed",
+}
`;
-exports[`GroupEmptyState Renders an empty state for CONNECTION_FAILED 2`] = `undefined`;
+exports[`GroupEmptyState given state CONNECTION_FAILED renders the slotted content 1`] = `<div />`;
-exports[`GroupEmptyState Renders an empty state for FOO STATE 1`] = `
-<gl-empty-state-stub
- compact="true"
- description="An error occurred while loading the data. Please try again."
- svgpath="/path/to/empty-group-illustration.svg"
- title="An error has occurred"
-/>
+exports[`GroupEmptyState given state FOO STATE passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": "An error occurred while loading the data. Please try again.",
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "An error has occurred",
+}
`;
-exports[`GroupEmptyState Renders an empty state for FOO STATE 2`] = `undefined`;
+exports[`GroupEmptyState given state FOO STATE renders the slotted content 1`] = `<div />`;
-exports[`GroupEmptyState Renders an empty state for LOADING 1`] = `
-<gl-empty-state-stub
- compact="true"
- description="Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
- svgpath="/path/to/empty-group-illustration.svg"
- title="Waiting for performance data"
-/>
+exports[`GroupEmptyState given state LOADING passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available.",
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "Waiting for performance data",
+}
`;
-exports[`GroupEmptyState Renders an empty state for LOADING 2`] = `undefined`;
+exports[`GroupEmptyState given state LOADING renders the slotted content 1`] = `<div />`;
-exports[`GroupEmptyState Renders an empty state for NO_DATA 1`] = `
-<gl-empty-state-stub
- compact="true"
- svgpath="/path/to/empty-group-illustration.svg"
- title="No data to display"
-/>
+exports[`GroupEmptyState given state NO_DATA passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": null,
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "No data to display",
+}
`;
-exports[`GroupEmptyState Renders an empty state for NO_DATA 2`] = `"The data source is connected, but there is no data to display. <a href=\\"/path/to/docs\\">More information</a>"`;
+exports[`GroupEmptyState given state NO_DATA renders the slotted content 1`] = `
+<div>
+ <div>
+ The data source is connected, but there is no data to display.
+ <a
+ href="/path/to/docs"
+ >
+ More information
+ </a>
+ </div>
+</div>
+`;
-exports[`GroupEmptyState Renders an empty state for TIMEOUT 1`] = `
-<gl-empty-state-stub
- compact="true"
- svgpath="/path/to/empty-group-illustration.svg"
- title="Connection timed out"
-/>
+exports[`GroupEmptyState given state TIMEOUT passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": null,
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "Connection timed out",
+}
`;
-exports[`GroupEmptyState Renders an empty state for TIMEOUT 2`] = `"Charts can't be displayed as the request for data has timed out. <a href=\\"/path/to/docs\\">More information</a>"`;
+exports[`GroupEmptyState given state TIMEOUT renders the slotted content 1`] = `
+<div>
+ <div>
+ Charts can't be displayed as the request for data has timed out.
+ <a
+ href="/path/to/docs"
+ >
+ More information
+ </a>
+ </div>
+</div>
+`;
-exports[`GroupEmptyState Renders an empty state for UNKNOWN_ERROR 1`] = `
-<gl-empty-state-stub
- compact="true"
- description="An error occurred while loading the data. Please try again."
- svgpath="/path/to/empty-group-illustration.svg"
- title="An error has occurred"
-/>
+exports[`GroupEmptyState given state UNKNOWN_ERROR passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": "An error occurred while loading the data. Please try again.",
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "An error has occurred",
+}
`;
-exports[`GroupEmptyState Renders an empty state for UNKNOWN_ERROR 2`] = `undefined`;
+exports[`GroupEmptyState given state UNKNOWN_ERROR renders the slotted content 1`] = `<div />`;
diff --git a/spec/frontend/monitoring/components/group_empty_state_spec.js b/spec/frontend/monitoring/components/group_empty_state_spec.js
index 90bd6f67196..3b94c4c6806 100644
--- a/spec/frontend/monitoring/components/group_empty_state_spec.js
+++ b/spec/frontend/monitoring/components/group_empty_state_spec.js
@@ -1,7 +1,13 @@
+import { GlEmptyState } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import GroupEmptyState from '~/monitoring/components/group_empty_state.vue';
import { metricStates } from '~/monitoring/constants';
+const MockGlEmptyState = {
+ props: GlEmptyState.props,
+ template: '<div><slot name="description"></slot></div>',
+};
+
function createComponent(props) {
return shallowMount(GroupEmptyState, {
propsData: {
@@ -10,11 +16,20 @@ function createComponent(props) {
settingsPath: '/path/to/settings',
svgPath: '/path/to/empty-group-illustration.svg',
},
+ stubs: {
+ GlEmptyState: MockGlEmptyState,
+ },
});
}
describe('GroupEmptyState', () => {
- const supportedStates = [
+ let wrapper;
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe.each([
metricStates.NO_DATA,
metricStates.TIMEOUT,
metricStates.CONNECTION_FAILED,
@@ -22,13 +37,17 @@ describe('GroupEmptyState', () => {
metricStates.LOADING,
metricStates.UNKNOWN_ERROR,
'FOO STATE', // does not fail with unknown states
- ];
+ ])('given state %s', selectedState => {
+ beforeEach(() => {
+ wrapper = createComponent({ selectedState });
+ });
- it.each(supportedStates)('Renders an empty state for %s', selectedState => {
- const wrapper = createComponent({ selectedState });
+ it('renders the slotted content', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
- expect(wrapper.element).toMatchSnapshot();
- // slot is not rendered by the stub, test it separately
- expect(wrapper.vm.currentState.slottedDescription).toMatchSnapshot();
+ it('passes the expected props to GlEmptyState', () => {
+ expect(wrapper.find(MockGlEmptyState).props()).toMatchSnapshot();
+ });
});
});
diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js
index 544c19da57b..eebec7de9d4 100644
--- a/spec/frontend/test_setup.js
+++ b/spec/frontend/test_setup.js
@@ -1,4 +1,6 @@
import Vue from 'vue';
+import 'jquery';
+
import * as jqueryMatchers from 'custom-jquery-matchers';
import { config as testUtilsConfig } from '@vue/test-utils';
import Translate from '~/vue_shared/translate';
@@ -9,7 +11,6 @@ import customMatchers from './matchers';
import './helpers/dom_shims';
import './helpers/jquery';
-import '~/commons/jquery';
import '~/commons/bootstrap';
process.on('unhandledRejection', global.promiseRejectionHandler);
diff --git a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap
index cdd7a3ccaf0..b8a9143bc79 100644
--- a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap
+++ b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap
@@ -10,6 +10,7 @@ exports[`Suggestion Diff component matches snapshot 1`] = `
helppagepath="path_to_docs"
isapplyingbatch="true"
isbatched="true"
+ suggestionscount="0"
/>
<table
diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
index a521668b15c..b19e74b5b11 100644
--- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
@@ -57,7 +57,9 @@ describe('Suggestion Diff component', () => {
});
it('renders apply suggestion and add to batch buttons', () => {
- createComponent();
+ createComponent({
+ suggestionsCount: 2,
+ });
const applyBtn = findApplyButton();
const addToBatchBtn = findAddToBatchButton();
@@ -104,7 +106,9 @@ describe('Suggestion Diff component', () => {
describe('when add to batch is clicked', () => {
it('emits addToBatch', () => {
- createComponent();
+ createComponent({
+ suggestionsCount: 2,
+ });
findAddToBatchButton().vm.$emit('click');
diff --git a/spec/helpers/groups/group_members_helper_spec.rb b/spec/helpers/groups/group_members_helper_spec.rb
index a25bf1c4157..abf621aee10 100644
--- a/spec/helpers/groups/group_members_helper_spec.rb
+++ b/spec/helpers/groups/group_members_helper_spec.rb
@@ -5,6 +5,8 @@ require "spec_helper"
RSpec.describe Groups::GroupMembersHelper do
include MembersPresentation
+ let_it_be(:current_user) { create(:user) }
+
describe '.group_member_select_options' do
let(:group) { create(:group) }
@@ -20,6 +22,10 @@ RSpec.describe Groups::GroupMembersHelper do
describe '#linked_groups_data_json' do
include_context 'group_group_link'
+ before do
+ allow(helper).to receive(:current_user).and_return(current_user)
+ end
+
it 'matches json schema' do
json = helper.linked_groups_data_json(shared_group.shared_with_group_links)
@@ -28,7 +34,6 @@ RSpec.describe Groups::GroupMembersHelper do
end
describe '#members_data_json' do
- let(:current_user) { create(:user) }
let(:group) { create(:group) }
before do
@@ -48,6 +53,14 @@ RSpec.describe Groups::GroupMembersHelper do
let(:group_member) { create(:group_member, group: group, created_by: current_user) }
it_behaves_like 'group_members.json'
+
+ context 'with user status set' do
+ let(:user) { create(:user) }
+ let!(:status) { create(:user_status, user: user) }
+ let(:group_member) { create(:group_member, group: group, user: user, created_by: current_user) }
+
+ it_behaves_like 'group_members.json'
+ end
end
context 'for an invited group member' do
diff --git a/spec/lib/gitlab/ci/runner/backoff_spec.rb b/spec/lib/gitlab/ci/runner/backoff_spec.rb
new file mode 100644
index 00000000000..13455ccd692
--- /dev/null
+++ b/spec/lib/gitlab/ci/runner/backoff_spec.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+require 'active_support/testing/time_helpers'
+
+RSpec.describe Gitlab::Ci::Runner::Backoff do
+ include ActiveSupport::Testing::TimeHelpers
+
+ describe '#duration' do
+ it 'returns backoff duration from start' do
+ freeze_time do
+ described_class.new(5.minutes.ago).then do |backoff|
+ expect(backoff.duration).to eq 5.minutes
+ end
+ end
+ end
+ end
+
+ describe '#slot' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:started, :slot) do
+ 1 | 0
+ 2 | 0
+ 3 | 0
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 | 1
+ 8 | 2
+ 9 | 2
+ 10 | 2
+ 15 | 2
+ 16 | 3
+ 31 | 3
+ 32 | 4
+ 63 | 4
+ 64 | 5
+ 127 | 5
+ 128 | 6
+ 250 | 6
+ 310 | 7
+ 520 | 8
+ 999 | 8
+ end
+
+ with_them do
+ it 'falls into an appropaite backoff slot' do
+ freeze_time do
+ backoff = described_class.new(started.seconds.ago)
+ expect(backoff.slot).to eq slot
+ end
+ end
+ end
+ end
+
+ describe '#to_seconds' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:started, :backoff) do
+ 1 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 2
+ 5 | 2
+ 6 | 2
+ 7 | 2
+ 8 | 4
+ 9 | 4
+ 10 | 4
+ 15 | 4
+ 16 | 8
+ 31 | 8
+ 32 | 16
+ 63 | 16
+ 64 | 32
+ 127 | 32
+ 128 | 64
+ 250 | 64
+ 310 | 64
+ 520 | 64
+ 999 | 64
+ end
+
+ with_them do
+ it 'calculates backoff based on an appropriate slot' do
+ freeze_time do
+ described_class.new(started.seconds.ago).then do |delay|
+ expect(delay.to_seconds).to eq backoff
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index b202015464f..8198c2651a7 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -531,7 +531,9 @@ RSpec.describe Gitlab::Git::DiffCollection, :seed_helper do
let(:iterator) { [fake_diff(1, 1)] * 4 }
before do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: 2, max_lines: max_lines })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: 2, max_lines: max_lines })
end
it 'prunes diffs by default even little ones' do
@@ -556,7 +558,9 @@ RSpec.describe Gitlab::Git::DiffCollection, :seed_helper do
end
before do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: max_files, max_lines: 80 })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: max_files, max_lines: 80 })
end
it 'prunes diffs by default even little ones' do
@@ -581,7 +585,9 @@ RSpec.describe Gitlab::Git::DiffCollection, :seed_helper do
end
before do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: max_files, max_lines: 80 })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: max_files, max_lines: 80 })
end
it 'prunes diffs by default even little ones' do
@@ -665,8 +671,9 @@ RSpec.describe Gitlab::Git::DiffCollection, :seed_helper do
end
before do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS',
- { max_files: max_files, max_lines: 80 })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: max_files, max_lines: 80 })
end
it 'considers size of diffs before the offset for prunning' do
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index 9581b017839..f977fe1638f 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -13,6 +13,10 @@ RSpec.describe Gitlab::GitalyClient::CommitService do
let(:client) { described_class.new(repository) }
describe '#diff_from_parent' do
+ before do
+ stub_feature_flags(increased_diff_limits: false)
+ end
+
context 'when a commit has a parent' do
it 'sends an RPC request with the parent ID as left commit' do
request = Gitaly::CommitDiffRequest.new(
diff --git a/spec/requests/api/ci/runner/jobs_put_spec.rb b/spec/requests/api/ci/runner/jobs_put_spec.rb
index 183a3b26e00..4feb65aa3cf 100644
--- a/spec/requests/api/ci/runner/jobs_put_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_put_spec.rb
@@ -46,64 +46,59 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
context 'when status is given' do
- it 'mark job as succeeded' do
+ it 'marks job as succeeded' do
update_job(state: 'success')
- job.reload
- expect(job).to be_success
+ expect(job.reload).to be_success
+ expect(response.header).not_to have_key('X-GitLab-Trace-Update-Interval')
end
- it 'mark job as failed' do
+ it 'marks job as failed' do
update_job(state: 'failed')
- job.reload
- expect(job).to be_failed
+ expect(job.reload).to be_failed
expect(job).to be_unknown_failure
+ expect(response.header).not_to have_key('X-GitLab-Trace-Update-Interval')
end
context 'when failure_reason is script_failure' do
before do
update_job(state: 'failed', failure_reason: 'script_failure')
- job.reload
end
- it { expect(job).to be_script_failure }
+ it { expect(job.reload).to be_script_failure }
end
context 'when failure_reason is runner_system_failure' do
before do
update_job(state: 'failed', failure_reason: 'runner_system_failure')
- job.reload
end
- it { expect(job).to be_runner_system_failure }
+ it { expect(job.reload).to be_runner_system_failure }
end
context 'when failure_reason is unrecognized value' do
before do
update_job(state: 'failed', failure_reason: 'what_is_this')
- job.reload
end
- it { expect(job).to be_unknown_failure }
+ it { expect(job.reload).to be_unknown_failure }
end
context 'when failure_reason is job_execution_timeout' do
before do
update_job(state: 'failed', failure_reason: 'job_execution_timeout')
- job.reload
end
- it { expect(job).to be_job_execution_timeout }
+ it { expect(job.reload).to be_job_execution_timeout }
end
context 'when failure_reason is unmet_prerequisites' do
before do
update_job(state: 'failed', failure_reason: 'unmet_prerequisites')
- job.reload
end
- it { expect(job).to be_unmet_prerequisites }
+ it { expect(job.reload).to be_unmet_prerequisites }
end
context 'when unmigrated live trace chunks exist' do
@@ -119,6 +114,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(job.pending_state).to be_present
expect(response).to have_gitlab_http_status(:accepted)
+ expect(response.header['X-GitLab-Trace-Update-Interval']).to be > 0
end
end
@@ -151,6 +147,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(job.reload).to be_success
expect(job.pending_state).not_to be_present
expect(response).to have_gitlab_http_status(:ok)
+ expect(response.header).not_to have_key('X-GitLab-Trace-Update-Interval')
end
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 2757c56e0fe..0e5fa24ad66 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -1140,7 +1140,7 @@ RSpec.describe API::MergeRequests do
context 'when a merge request has more than the changes limit' do
it "returns a string indicating that more changes were made" do
- stub_const('Commit::DIFF_HARD_LIMIT_FILES', 5)
+ allow(Commit).to receive(:diff_hard_limit_files).and_return(5)
merge_request_overflow = create(:merge_request, :simple,
author: user,
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 36707f32d04..45bce8c8a5c 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -402,7 +402,9 @@ RSpec.describe API::Repositories do
end
it "returns an empty string when the diff overflows" do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: 2, max_lines: 2 })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: 2, max_lines: 2 })
get api(route, current_user), params: { from: 'master', to: 'feature' }
diff --git a/spec/serializers/group_group_link_entity_spec.rb b/spec/serializers/group_group_link_entity_spec.rb
index 8384563e3e6..9affe4af381 100644
--- a/spec/serializers/group_group_link_entity_spec.rb
+++ b/spec/serializers/group_group_link_entity_spec.rb
@@ -5,9 +5,27 @@ require 'spec_helper'
RSpec.describe GroupGroupLinkEntity do
include_context 'group_group_link'
- subject(:json) { described_class.new(group_group_link).to_json }
+ let_it_be(:current_user) { create(:user) }
+ let(:entity) { described_class.new(group_group_link) }
+
+ before do
+ allow(entity).to receive(:current_user).and_return(current_user)
+ end
it 'matches json schema' do
- expect(json).to match_schema('entities/group_group_link')
+ expect(entity.to_json).to match_schema('entities/group_group_link')
+ end
+
+ context 'a user with :admin_group_member permissions' do
+ before do
+ allow(entity).to receive(:can?).with(current_user, :admin_group_member, shared_group).and_return(true)
+ end
+
+ it 'sets `can_update` and `can_remove` to `true`' do
+ json = entity.as_json
+
+ expect(json[:can_update]).to be true
+ expect(json[:can_remove]).to be true
+ end
end
end
diff --git a/spec/services/ci/update_build_state_service_spec.rb b/spec/services/ci/update_build_state_service_spec.rb
index f5ad732bf7e..333231cbd83 100644
--- a/spec/services/ci/update_build_state_service_spec.rb
+++ b/spec/services/ci/update_build_state_service_spec.rb
@@ -100,6 +100,12 @@ RSpec.describe Ci::UpdateBuildStateService do
expect(result.status).to eq 200
end
+ it 'does not set a backoff value' do
+ result = subject.execute
+
+ expect(result.backoff).to be_nil
+ end
+
it 'increments trace finalized operation metric' do
execute_with_stubbed_metrics!
@@ -126,6 +132,12 @@ RSpec.describe Ci::UpdateBuildStateService do
expect(result.status).to eq 202
end
+ it 'sets a request backoff value' do
+ result = subject.execute
+
+ expect(result.backoff.to_i).to be > 0
+ end
+
it 'schedules live chunks for migration' do
expect(Ci::BuildTraceChunkFlushWorker)
.to receive(:perform_async)
diff --git a/spec/support/helpers/wait_for_requests.rb b/spec/support/helpers/wait_for_requests.rb
index 2cfd47634ca..43060e571a9 100644
--- a/spec/support/helpers/wait_for_requests.rb
+++ b/spec/support/helpers/wait_for_requests.rb
@@ -48,17 +48,10 @@ module WaitForRequests
def finished_all_js_requests?
return true unless javascript_test?
- finished_all_ajax_requests? &&
- finished_all_axios_requests?
- end
-
- def finished_all_axios_requests?
- Capybara.page.evaluate_script('window.pendingRequests || 0').zero? # rubocop:disable Style/NumericPredicate
+ finished_all_ajax_requests?
end
def finished_all_ajax_requests?
- return true if Capybara.page.evaluate_script('typeof jQuery === "undefined"')
-
- Capybara.page.evaluate_script('jQuery.active').zero? # rubocop:disable Style/NumericPredicate
+ Capybara.page.evaluate_script('window.pendingRequests || window.pendingRailsUJSRequests || 0').zero? # rubocop:disable Style/NumericPredicate
end
end
diff --git a/yarn.lock b/yarn.lock
index d9967c03d4e..0752825b270 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1076,6 +1076,11 @@
resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.0.3-1.tgz#9b9eb8858a6507162911007d355d9a206e1c5caa"
integrity sha512-szFhWD+V5TAxVNVIG16klgq+ypqA5k5AecLarTTrXgOG8cawVbQdOAwLbCmzkwiQ60rGSxAFoC1u2LrzxSK2Aw==
+"@rails/ujs@^6.0.3-2":
+ version "6.0.3-2"
+ resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-6.0.3-2.tgz#e14c1f29086858215ce7ccd9ad6d8888c458b4a3"
+ integrity sha512-WcpIEftNCfGDEgk6KerOugiet75Mir5q/HT1yt3dDhpBI91BaZ15lfSQIsZwMw2nyeDz9A9QBz8dAFAd4gXIzg==
+
"@sentry/browser@^5.22.3":
version "5.22.3"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.22.3.tgz#7a64bd1cf01bf393741a3e4bf35f82aa927f5b4e"
@@ -7068,13 +7073,6 @@ jmespath@0.15.0:
resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217"
integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=
-jquery-ujs@1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/jquery-ujs/-/jquery-ujs-1.2.2.tgz#6a8ef1020e6b6dda385b90a4bddc128c21c56397"
- integrity sha1-ao7xAg5rbdo4W5CkvdwSjCHFY5c=
- dependencies:
- jquery ">=1.8.0"
-
jquery.caret@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/jquery.caret/-/jquery.caret-0.3.1.tgz#9c093318faf327eff322e826ca9f3241368bc7b8"
@@ -7085,7 +7083,7 @@ jquery.waitforimages@^2.2.0:
resolved "https://registry.yarnpkg.com/jquery.waitforimages/-/jquery.waitforimages-2.2.0.tgz#63f23131055a1b060dc913e6d874bcc9b9e6b16b"
integrity sha1-Y/IxMQVaGwYNyRPm2HS8ybnmsWs=
-"jquery@>= 1.9.1", jquery@>=1.8.0, jquery@^3.5.0:
+"jquery@>= 1.9.1", jquery@^3.5.0:
version "3.5.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5"
integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==