summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-02-01 21:12:02 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-02-01 21:12:02 +0000
commit71722304bef22d1b162207e3e25e4109b0d0f8c1 (patch)
treea80189974f400946831c047ca5d4f018b9bacccc
parent143a33345cf3607ad35ec31130cec4922bc1113c (diff)
downloadgitlab-ce-71722304bef22d1b162207e3e25e4109b0d0f8c1.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop.yml1
-rw-r--r--app/assets/images/auth_buttons/auth0_64.pngbin1815 -> 2873 bytes
-rw-r--r--app/assets/javascripts/activities.js4
-rw-r--r--app/assets/javascripts/awards_handler.js8
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js14
-rw-r--r--app/assets/javascripts/blob/pipeline_tour_success_modal.vue6
-rw-r--r--app/assets/javascripts/broadcast_notification.js4
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue6
-rw-r--r--app/assets/javascripts/contextual_sidebar.js7
-rw-r--r--app/assets/javascripts/cycle_analytics/components/base.vue6
-rw-r--r--app/assets/javascripts/deprecated_notes.js6
-rw-r--r--app/assets/javascripts/design_management/components/design_sidebar.vue8
-rw-r--r--app/assets/javascripts/diffs/index.js12
-rw-r--r--app/assets/javascripts/diffs/store/actions.js13
-rw-r--r--app/assets/javascripts/diffs/store/getters.js4
-rw-r--r--app/assets/javascripts/diffs/store/modules/diff_state.js4
-rw-r--r--app/assets/javascripts/emoji/components/utils.js8
-rw-r--r--app/assets/javascripts/files_comment_button.js4
-rw-r--r--app/assets/javascripts/groups/landing.js7
-rw-r--r--app/assets/javascripts/issuable/issuable_context.js4
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js5
-rw-r--r--app/assets/javascripts/merge_conflicts/store/actions.js4
-rw-r--r--app/assets/javascripts/merge_conflicts/store/state.js4
-rw-r--r--app/assets/javascripts/merge_request_tabs.js17
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue8
-rw-r--r--app/assets/javascripts/pages/projects/project.js8
-rw-r--r--app/assets/javascripts/pages/users/index.js4
-rw-r--r--app/assets/javascripts/right_sidebar.js4
-rw-r--r--app/assets/javascripts/serverless/survey_banner.vue7
-rw-r--r--app/assets/javascripts/user_callout.js6
-rw-r--r--app/assets/javascripts/vue_alerts.js6
-rw-r--r--app/assets/javascripts/vue_shared/issuable/sidebar/components/issuable_sidebar_root.vue8
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss3
-rw-r--r--app/controllers/graphql_controller.rb6
-rw-r--r--app/finders/users_finder.rb6
-rw-r--r--app/helpers/projects_helper.rb18
-rw-r--r--config/feature_flags/development/jobs_tab_vue.yml2
-rw-r--r--config/feature_flags/development/usage_data_i_code_review_user_jetbrains_api_request.yml8
-rw-r--r--config/initializers_before_autoloader/004_zeitwerk.rb1
-rw-r--r--config/metrics/aggregates/code_review.yml2
-rw-r--r--config/metrics/counts_28d/20220121140644_user_jetbrains_api_request_monthly.yml26
-rw-r--r--config/metrics/counts_7d/20220121140634_user_jetbrains_api_request_weekly.yml26
-rw-r--r--db/post_migrate/20220201173212_add_user_details_provisioning_index.rb18
-rw-r--r--db/schema_migrations/202202011732121
-rw-r--r--db/structure.sql4
-rw-r--r--doc/administration/packages/container_registry.md40
-rw-r--r--doc/api/groups.md72
-rw-r--r--doc/ci/runners/configure_runners.md4
-rw-r--r--lib/api/api.rb4
-rw-r--r--lib/gitlab/gon_helper.rb1
-rw-r--r--lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb28
-rw-r--r--lib/gitlab/usage_data_counters/known_events/code_review_events.yml5
-rw-r--r--qa/qa.rb3
-rw-r--r--qa/qa/tools/reliable_report.rb2
-rw-r--r--qa/spec/tools/reliable_report_spec.rb2
-rw-r--r--spec/controllers/graphql_controller_spec.rb20
-rw-r--r--spec/frontend/broadcast_notification_spec.js1
-rw-r--r--spec/frontend/code_quality_walkthrough/components/step_spec.js2
-rw-r--r--spec/frontend/design_management/components/design_sidebar_spec.js5
-rw-r--r--spec/frontend/emoji/components/utils_spec.js3
-rw-r--r--spec/frontend/groups/landing_spec.js5
-rw-r--r--spec/frontend/merge_conflicts/store/actions_spec.js5
-rw-r--r--spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js1
-rw-r--r--spec/frontend/serverless/survey_banner_spec.js5
-rw-r--r--spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js5
-rw-r--r--spec/lib/gitlab/gon_helper_spec.rb32
-rw-r--r--spec/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter_spec.rb63
-rw-r--r--spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb56
68 files changed, 543 insertions, 149 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index bea2cf66efd..5757a273926 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -168,6 +168,7 @@ Naming/FileName:
- GitLab
- JavaScript
- VSCode
+ - JetBrains
# default ones:
- CLI
- DSL
diff --git a/app/assets/images/auth_buttons/auth0_64.png b/app/assets/images/auth_buttons/auth0_64.png
index 5ad59659380..3b2d8562d9d 100644
--- a/app/assets/images/auth_buttons/auth0_64.png
+++ b/app/assets/images/auth_buttons/auth0_64.png
Binary files differ
diff --git a/app/assets/javascripts/activities.js b/app/assets/javascripts/activities.js
index f45af5fe08e..74e0e1b6225 100644
--- a/app/assets/javascripts/activities.js
+++ b/app/assets/javascripts/activities.js
@@ -1,7 +1,7 @@
/* eslint-disable class-methods-use-this */
import $ from 'jquery';
-import Cookies from 'js-cookie';
+import { setCookie } from '~/lib/utils/common_utils';
import createFlash from '~/flash';
import { s__ } from '~/locale';
import { localTimeAgo } from './lib/utils/datetime_utility';
@@ -55,7 +55,7 @@ export default class Activities {
const filter = $sender.attr('id').split('_')[0];
$('.event-filter .active').removeClass('active');
- Cookies.set('event_filter', filter);
+ setCookie('event_filter', filter);
$sender.closest('li').toggleClass('active');
}
diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js
index 43ca5b5cf89..aa735df7da5 100644
--- a/app/assets/javascripts/awards_handler.js
+++ b/app/assets/javascripts/awards_handler.js
@@ -2,10 +2,10 @@
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import $ from 'jquery';
-import Cookies from 'js-cookie';
import { uniq } from 'lodash';
+import { getCookie, setCookie, scrollToElement } from '~/lib/utils/common_utils';
import * as Emoji from '~/emoji';
-import { scrollToElement } from '~/lib/utils/common_utils';
+
import { dispose, fixTitle } from '~/tooltips';
import createFlash from './flash';
import axios from './lib/utils/axios_utils';
@@ -506,7 +506,7 @@ export class AwardsHandler {
addEmojiToFrequentlyUsedList(emoji) {
if (this.emoji.isEmojiNameValid(emoji)) {
this.frequentlyUsedEmojis = uniq(this.getFrequentlyUsedEmojis().concat(emoji));
- Cookies.set('frequently_used_emojis', this.frequentlyUsedEmojis.join(','), { expires: 365 });
+ setCookie('frequently_used_emojis', this.frequentlyUsedEmojis.join(','));
}
}
@@ -514,7 +514,7 @@ export class AwardsHandler {
return (
this.frequentlyUsedEmojis ||
(() => {
- const frequentlyUsedEmojis = uniq((Cookies.get('frequently_used_emojis') || '').split(','));
+ const frequentlyUsedEmojis = uniq((getCookie('frequently_used_emojis') || '').split(','));
this.frequentlyUsedEmojis = frequentlyUsedEmojis.filter((inputName) =>
this.emoji.isEmojiNameValid(inputName),
);
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index acb2355852d..9297b14aac9 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -1,9 +1,9 @@
import $ from 'jquery';
-import Cookies from 'js-cookie';
import { flatten } from 'lodash';
import Mousetrap from 'mousetrap';
import Vue from 'vue';
-import { parseBoolean } from '~/lib/utils/common_utils';
+import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';
+
import findAndFollowLink from '~/lib/utils/navigation_utility';
import { refreshCurrentPage, visitUrl } from '~/lib/utils/url_utility';
import {
@@ -161,10 +161,10 @@ export default class Shortcuts {
static onTogglePerfBar(e) {
e.preventDefault();
const performanceBarCookieName = 'perf_bar_enabled';
- if (parseBoolean(Cookies.get(performanceBarCookieName))) {
- Cookies.set(performanceBarCookieName, 'false', { expires: 365, path: '/' });
+ if (parseBoolean(getCookie(performanceBarCookieName))) {
+ setCookie(performanceBarCookieName, 'false', { path: '/' });
} else {
- Cookies.set(performanceBarCookieName, 'true', { expires: 365, path: '/' });
+ setCookie(performanceBarCookieName, 'true', { path: '/' });
}
refreshCurrentPage();
}
@@ -172,8 +172,8 @@ export default class Shortcuts {
static onToggleCanary(e) {
e.preventDefault();
const canaryCookieName = 'gitlab_canary';
- const currentValue = parseBoolean(Cookies.get(canaryCookieName));
- Cookies.set(canaryCookieName, (!currentValue).toString(), {
+ const currentValue = parseBoolean(getCookie(canaryCookieName));
+ setCookie(canaryCookieName, (!currentValue).toString(), {
expires: 365,
path: '/',
// next.gitlab.com uses a leading period. See https://gitlab.com/gitlab-org/gitlab/-/issues/350186
diff --git a/app/assets/javascripts/blob/pipeline_tour_success_modal.vue b/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
index 47a0c4ba2d1..b4ca29114cb 100644
--- a/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
+++ b/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
@@ -1,6 +1,6 @@
<script>
import { GlModal, GlSprintf, GlLink, GlButton } from '@gitlab/ui';
-import Cookies from 'js-cookie';
+import { getCookie, removeCookie } from '~/lib/utils/common_utils';
import { __, s__ } from '~/locale';
import Tracking from '~/tracking';
@@ -62,7 +62,7 @@ export default {
return this.commitCookiePath || this.projectMergeRequestsPath;
},
commitCookiePath() {
- const cookieVal = Cookies.get(this.commitCookie);
+ const cookieVal = getCookie(this.commitCookie);
if (cookieVal !== 'true') return cookieVal;
return '';
@@ -85,7 +85,7 @@ export default {
},
methods: {
disableModalFromRenderingAgain() {
- Cookies.remove(this.commitCookie);
+ removeCookie(this.commitCookie);
},
},
};
diff --git a/app/assets/javascripts/broadcast_notification.js b/app/assets/javascripts/broadcast_notification.js
index 2cf2e922f68..34282c6932e 100644
--- a/app/assets/javascripts/broadcast_notification.js
+++ b/app/assets/javascripts/broadcast_notification.js
@@ -1,4 +1,4 @@
-import Cookies from 'js-cookie';
+import { setCookie } from '~/lib/utils/common_utils';
const handleOnDismiss = ({ currentTarget }) => {
currentTarget.removeEventListener('click', handleOnDismiss);
@@ -6,7 +6,7 @@ const handleOnDismiss = ({ currentTarget }) => {
dataset: { id, expireDate },
} = currentTarget;
- Cookies.set(`hide_broadcast_message_${id}`, true, { expires: new Date(expireDate) });
+ setCookie(`hide_broadcast_message_${id}`, true, { expires: new Date(expireDate) });
const notification = document.querySelector(`.js-broadcast-notification-${id}`);
notification.parentNode.removeChild(notification);
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
index e630ce71bd3..2e198c59926 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
@@ -14,8 +14,8 @@ import {
GlModal,
GlSprintf,
} from '@gitlab/ui';
-import Cookies from 'js-cookie';
import { mapActions, mapState } from 'vuex';
+import { getCookie, setCookie } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import Tracking from '~/tracking';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -59,7 +59,7 @@ export default {
mixins: [glFeatureFlagsMixin(), trackingMixin],
data() {
return {
- isTipDismissed: Cookies.get(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true',
+ isTipDismissed: getCookie(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true',
validationErrorEventProperty: '',
};
},
@@ -176,7 +176,7 @@ export default {
'setVariableProtected',
]),
dismissTip() {
- Cookies.set(AWS_TIP_DISMISSED_COOKIE_NAME, 'true', { expires: 90 });
+ setCookie(AWS_TIP_DISMISSED_COOKIE_NAME, 'true', { expires: 90 });
this.isTipDismissed = true;
},
deleteVarAndClose() {
diff --git a/app/assets/javascripts/contextual_sidebar.js b/app/assets/javascripts/contextual_sidebar.js
index 08942374120..d1a68e80608 100644
--- a/app/assets/javascripts/contextual_sidebar.js
+++ b/app/assets/javascripts/contextual_sidebar.js
@@ -1,10 +1,9 @@
import { GlBreakpointInstance as bp, breakpoints } from '@gitlab/ui/dist/utils';
import $ from 'jquery';
-import Cookies from 'js-cookie';
import { debounce } from 'lodash';
+import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
-import { parseBoolean } from '~/lib/utils/common_utils';
export const SIDEBAR_COLLAPSED_CLASS = 'js-sidebar-collapsed';
@@ -59,7 +58,7 @@ export default class ContextualSidebar {
if (!ContextualSidebar.isDesktopBreakpoint()) {
return;
}
- Cookies.set('sidebar_collapsed', value, { expires: 365 * 10 });
+ setCookie('sidebar_collapsed', value, { expires: 365 * 10 });
}
toggleSidebarNav(show) {
@@ -111,7 +110,7 @@ export default class ContextualSidebar {
if (!ContextualSidebar.isDesktopBreakpoint()) {
this.toggleSidebarNav(false);
} else {
- const collapse = parseBoolean(Cookies.get('sidebar_collapsed'));
+ const collapse = parseBoolean(getCookie('sidebar_collapsed'));
this.toggleCollapsedSidebar(collapse, true);
}
diff --git a/app/assets/javascripts/cycle_analytics/components/base.vue b/app/assets/javascripts/cycle_analytics/components/base.vue
index bdfabb8e846..210e76115a2 100644
--- a/app/assets/javascripts/cycle_analytics/components/base.vue
+++ b/app/assets/javascripts/cycle_analytics/components/base.vue
@@ -1,7 +1,7 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
-import Cookies from 'js-cookie';
import { mapActions, mapState, mapGetters } from 'vuex';
+import { getCookie, setCookie } from '~/lib/utils/common_utils';
import { toYmd } from '~/analytics/shared/utils';
import PathNavigation from '~/cycle_analytics/components/path_navigation.vue';
import StageTable from '~/cycle_analytics/components/stage_table.vue';
@@ -35,7 +35,7 @@ export default {
},
data() {
return {
- isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE),
+ isOverviewDialogDismissed: getCookie(OVERVIEW_DIALOG_COOKIE),
};
},
computed: {
@@ -134,7 +134,7 @@ export default {
},
dismissOverviewDialog() {
this.isOverviewDialogDismissed = true;
- Cookies.set(OVERVIEW_DIALOG_COOKIE, '1', { expires: 365 });
+ setCookie(OVERVIEW_DIALOG_COOKIE, '1');
},
isUserAllowed(id) {
const { permissions } = this;
diff --git a/app/assets/javascripts/deprecated_notes.js b/app/assets/javascripts/deprecated_notes.js
index 4ab3f140b61..ab57cbbc7c0 100644
--- a/app/assets/javascripts/deprecated_notes.js
+++ b/app/assets/javascripts/deprecated_notes.js
@@ -13,7 +13,6 @@ deprecated_notes_spec.js is the spec for the legacy, jQuery notes application. I
import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
import Autosize from 'autosize';
import $ from 'jquery';
-import Cookies from 'js-cookie';
import { escape, uniqueId } from 'lodash';
import Vue from 'vue';
import '~/lib/utils/jquery_at_who';
@@ -28,6 +27,7 @@ import { defaultAutocompleteConfig } from './gfm_auto_complete';
import GLForm from './gl_form';
import axios from './lib/utils/axios_utils';
import {
+ getCookie,
isInViewport,
getPagePath,
scrollToElement,
@@ -121,7 +121,7 @@ export default class Notes {
}
setViewType(view) {
- this.view = Cookies.get('diff_view') || view;
+ this.view = getCookie('diff_view') || view;
}
addBinding() {
@@ -473,7 +473,7 @@ export default class Notes {
}
isParallelView() {
- return Cookies.get('diff_view') === 'parallel';
+ return getCookie('diff_view') === 'parallel';
}
/**
diff --git a/app/assets/javascripts/design_management/components/design_sidebar.vue b/app/assets/javascripts/design_management/components/design_sidebar.vue
index 6d0ed3b08a3..81d0b6d0df4 100644
--- a/app/assets/javascripts/design_management/components/design_sidebar.vue
+++ b/app/assets/javascripts/design_management/components/design_sidebar.vue
@@ -1,7 +1,7 @@
<script>
import { GlCollapse, GlButton, GlPopover } from '@gitlab/ui';
-import Cookies from 'js-cookie';
-import { parseBoolean, isLoggedIn } from '~/lib/utils/common_utils';
+import { getCookie, setCookie, parseBoolean, isLoggedIn } from '~/lib/utils/common_utils';
+
import { s__ } from '~/locale';
import Participants from '~/sidebar/components/participants/participants.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -53,7 +53,7 @@ export default {
},
data() {
return {
- isResolvedCommentsPopoverHidden: parseBoolean(Cookies.get(this.$options.cookieKey)),
+ isResolvedCommentsPopoverHidden: parseBoolean(getCookie(this.$options.cookieKey)),
discussionWithOpenForm: '',
isLoggedIn: isLoggedIn(),
};
@@ -96,7 +96,7 @@ export default {
methods: {
handleSidebarClick() {
this.isResolvedCommentsPopoverHidden = true;
- Cookies.set(this.$options.cookieKey, 'true', { expires: 365 * 10 });
+ setCookie(this.$options.cookieKey, 'true', { expires: 365 * 10 });
this.updateActiveDiscussion();
},
updateActiveDiscussion(id) {
diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js
index 260ebdf2141..dfe29e767c9 100644
--- a/app/assets/javascripts/diffs/index.js
+++ b/app/assets/javascripts/diffs/index.js
@@ -1,7 +1,7 @@
-import Cookies from 'js-cookie';
import Vue from 'vue';
import { mapActions, mapState, mapGetters } from 'vuex';
-import { parseBoolean } from '~/lib/utils/common_utils';
+import { getCookie, setCookie, parseBoolean, removeCookie } from '~/lib/utils/common_utils';
+
import { getParameterValues } from '~/lib/utils/url_utility';
import eventHub from '../notes/event_hub';
import diffsApp from './components/app.vue';
@@ -58,14 +58,14 @@ export default function initDiffsApp(store) {
// Check for cookie and save that setting for future use.
// Then delete the cookie as we are phasing it out and using the database as SSOT.
// NOTE: This can/should be removed later
- if (Cookies.get(DIFF_WHITESPACE_COOKIE_NAME)) {
- const hideWhitespace = Cookies.get(DIFF_WHITESPACE_COOKIE_NAME);
+ if (getCookie(DIFF_WHITESPACE_COOKIE_NAME)) {
+ const hideWhitespace = getCookie(DIFF_WHITESPACE_COOKIE_NAME);
this.setShowWhitespace({
url: this.endpointUpdateUser,
showWhitespace: hideWhitespace !== '1',
trackClick: false,
});
- Cookies.remove(DIFF_WHITESPACE_COOKIE_NAME);
+ removeCookie(DIFF_WHITESPACE_COOKIE_NAME);
} else {
// This is only to set the the user preference in Vuex for use later
this.setShowWhitespace({
@@ -77,7 +77,7 @@ export default function initDiffsApp(store) {
const vScrollingParam = getParameterValues('virtual_scrolling')[0];
if (vScrollingParam === 'false' || vScrollingParam === 'true') {
- Cookies.set('diffs_virtual_scrolling', vScrollingParam);
+ setCookie('diffs_virtual_scrolling', vScrollingParam);
}
},
methods: {
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 692cb913a57..572949e585a 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -1,9 +1,14 @@
-import Cookies from 'js-cookie';
import Vue from 'vue';
+import {
+ setCookie,
+ handleLocationHash,
+ historyPushState,
+ scrollToElement,
+} from '~/lib/utils/common_utils';
import createFlash from '~/flash';
import { diffViewerModes } from '~/ide/constants';
import axios from '~/lib/utils/axios_utils';
-import { handleLocationHash, historyPushState, scrollToElement } from '~/lib/utils/common_utils';
+
import httpStatusCodes from '~/lib/utils/http_status';
import Poll from '~/lib/utils/poll';
import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility';
@@ -369,7 +374,7 @@ export const setRenderIt = ({ commit }, file) => commit(types.RENDER_FILE, file)
export const setInlineDiffViewType = ({ commit }) => {
commit(types.SET_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE);
- Cookies.set(DIFF_VIEW_COOKIE_NAME, INLINE_DIFF_VIEW_TYPE);
+ setCookie(DIFF_VIEW_COOKIE_NAME, INLINE_DIFF_VIEW_TYPE);
const url = mergeUrlParams({ view: INLINE_DIFF_VIEW_TYPE }, window.location.href);
historyPushState(url);
@@ -381,7 +386,7 @@ export const setInlineDiffViewType = ({ commit }) => {
export const setParallelDiffViewType = ({ commit }) => {
commit(types.SET_DIFF_VIEW_TYPE, PARALLEL_DIFF_VIEW_TYPE);
- Cookies.set(DIFF_VIEW_COOKIE_NAME, PARALLEL_DIFF_VIEW_TYPE);
+ setCookie(DIFF_VIEW_COOKIE_NAME, PARALLEL_DIFF_VIEW_TYPE);
const url = mergeUrlParams({ view: PARALLEL_DIFF_VIEW_TYPE }, window.location.href);
historyPushState(url);
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index ca85be5d829..83c7f8c814b 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -1,4 +1,4 @@
-import Cookies from 'js-cookie';
+import { getCookie } from '~/lib/utils/common_utils';
import { getParameterValues } from '~/lib/utils/url_utility';
import { __, n__ } from '~/locale';
import {
@@ -175,7 +175,7 @@ export function suggestionCommitMessage(state, _, rootState) {
}
export const isVirtualScrollingEnabled = (state) => {
- const vSrollerCookie = Cookies.get('diffs_virtual_scrolling');
+ const vSrollerCookie = getCookie('diffs_virtual_scrolling');
if (state.disableVirtualScroller) {
return false;
diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js
index 5f66360a040..329db1fe2cf 100644
--- a/app/assets/javascripts/diffs/store/modules/diff_state.js
+++ b/app/assets/javascripts/diffs/store/modules/diff_state.js
@@ -1,10 +1,10 @@
-import Cookies from 'js-cookie';
+import { getCookie } from '~/lib/utils/common_utils';
import { getParameterValues } from '~/lib/utils/url_utility';
import { INLINE_DIFF_VIEW_TYPE, DIFF_VIEW_COOKIE_NAME } from '../../constants';
const getViewTypeFromQueryString = () => getParameterValues('view')[0];
-const viewTypeFromCookie = Cookies.get(DIFF_VIEW_COOKIE_NAME);
+const viewTypeFromCookie = getCookie(DIFF_VIEW_COOKIE_NAME);
const defaultViewType = INLINE_DIFF_VIEW_TYPE;
export default () => ({
diff --git a/app/assets/javascripts/emoji/components/utils.js b/app/assets/javascripts/emoji/components/utils.js
index 3465a8ae7e6..5eec0992896 100644
--- a/app/assets/javascripts/emoji/components/utils.js
+++ b/app/assets/javascripts/emoji/components/utils.js
@@ -1,5 +1,5 @@
-import Cookies from 'js-cookie';
import { chunk, memoize, uniq } from 'lodash';
+import { getCookie, setCookie } from '~/lib/utils/common_utils';
import { initEmojiMap, getEmojiCategoryMap } from '~/emoji';
import {
EMOJIS_PER_ROW,
@@ -13,7 +13,7 @@ export const generateCategoryHeight = (emojisLength) =>
emojisLength * EMOJI_ROW_HEIGHT + CATEGORY_ROW_HEIGHT;
export const getFrequentlyUsedEmojis = () => {
- const savedEmojis = Cookies.get(FREQUENTLY_USED_COOKIE_KEY);
+ const savedEmojis = getCookie(FREQUENTLY_USED_COOKIE_KEY);
if (!savedEmojis) return null;
@@ -30,13 +30,13 @@ export const getFrequentlyUsedEmojis = () => {
export const addToFrequentlyUsed = (emoji) => {
const frequentlyUsedEmojis = uniq(
- (Cookies.get(FREQUENTLY_USED_COOKIE_KEY) || '')
+ (getCookie(FREQUENTLY_USED_COOKIE_KEY) || '')
.split(',')
.filter((e) => e)
.concat(emoji),
);
- Cookies.set(FREQUENTLY_USED_COOKIE_KEY, frequentlyUsedEmojis.join(','), { expires: 365 });
+ setCookie(FREQUENTLY_USED_COOKIE_KEY, frequentlyUsedEmojis.join(','));
};
export const hasFrequentlyUsedEmojis = () => getFrequentlyUsedEmojis() !== null;
diff --git a/app/assets/javascripts/files_comment_button.js b/app/assets/javascripts/files_comment_button.js
index 0d7a475eb8e..071c95b8f0a 100644
--- a/app/assets/javascripts/files_comment_button.js
+++ b/app/assets/javascripts/files_comment_button.js
@@ -4,7 +4,7 @@
* causes reflows, visit https://gist.github.com/paulirish/5d52fb081b3570c81e3a
*/
-import Cookies from 'js-cookie';
+import { getCookie } from '~/lib/utils/common_utils';
const LINE_NUMBER_CLASS = 'diff-line-num';
const UNFOLDABLE_LINE_CLASS = 'js-unfold';
@@ -29,7 +29,7 @@ export default {
$diffFile.closest(DIFF_CONTAINER_SELECTOR).data('canCreateNote') === '';
}
- this.isParallelView = Cookies.get('diff_view') === 'parallel';
+ this.isParallelView = getCookie('diff_view') === 'parallel';
if (this.userCanCreateNote) {
$diffFile
diff --git a/app/assets/javascripts/groups/landing.js b/app/assets/javascripts/groups/landing.js
index bfb4d9ce67b..ed76bebf843 100644
--- a/app/assets/javascripts/groups/landing.js
+++ b/app/assets/javascripts/groups/landing.js
@@ -1,5 +1,4 @@
-import Cookies from 'js-cookie';
-import { parseBoolean } from '~/lib/utils/common_utils';
+import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';
class Landing {
constructor(landingElement, dismissButton, cookieName) {
@@ -27,11 +26,11 @@ class Landing {
dismissLanding() {
this.landingElement.classList.add('hidden');
- Cookies.set(this.cookieName, 'true', { expires: 365 });
+ setCookie(this.cookieName, 'true');
}
isDismissed() {
- return parseBoolean(Cookies.get(this.cookieName));
+ return parseBoolean(getCookie(this.cookieName));
}
}
diff --git a/app/assets/javascripts/issuable/issuable_context.js b/app/assets/javascripts/issuable/issuable_context.js
index 453305dd6e0..37001d00a27 100644
--- a/app/assets/javascripts/issuable/issuable_context.js
+++ b/app/assets/javascripts/issuable/issuable_context.js
@@ -1,6 +1,6 @@
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import $ from 'jquery';
-import Cookies from 'js-cookie';
+import { setCookie } from '~/lib/utils/common_utils';
import { loadCSSFile } from '~/lib/utils/css_utils';
import UsersSelect from '~/users_select';
@@ -62,7 +62,7 @@ export default class IssuableContext {
const supportedSizes = ['xs', 'sm', 'md'];
if (supportedSizes.includes(bpBreakpoint)) {
- Cookies.set('collapsed_gutter', true);
+ setCookie('collapsed_gutter', true);
}
});
}
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index eff00dff7a7..cf6ce2c4889 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -705,7 +705,10 @@ export const scopedLabelKey = ({ title = '' }) => {
};
// Methods to set and get Cookie
-export const setCookie = (name, value) => Cookies.set(name, value, { expires: 365 });
+export const setCookie = (name, value, attributes) => {
+ const defaults = { expires: 365, secure: Boolean(window.gon?.secure) };
+ Cookies.set(name, value, { ...defaults, ...attributes });
+};
export const getCookie = (name) => Cookies.get(name);
diff --git a/app/assets/javascripts/merge_conflicts/store/actions.js b/app/assets/javascripts/merge_conflicts/store/actions.js
index df515c4ac1a..9c101da52f5 100644
--- a/app/assets/javascripts/merge_conflicts/store/actions.js
+++ b/app/assets/javascripts/merge_conflicts/store/actions.js
@@ -1,4 +1,4 @@
-import Cookies from 'js-cookie';
+import { setCookie } from '~/lib/utils/common_utils';
import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -51,7 +51,7 @@ export const setFailedRequest = ({ commit }, message) => {
export const setViewType = ({ commit }, viewType) => {
commit(types.SET_VIEW_TYPE, viewType);
- Cookies.set('diff_view', viewType);
+ setCookie('diff_view', viewType);
};
export const setSubmitState = ({ commit }, isSubmitting) => {
diff --git a/app/assets/javascripts/merge_conflicts/store/state.js b/app/assets/javascripts/merge_conflicts/store/state.js
index 8f700f58e54..7a2e28183a7 100644
--- a/app/assets/javascripts/merge_conflicts/store/state.js
+++ b/app/assets/javascripts/merge_conflicts/store/state.js
@@ -1,7 +1,7 @@
-import Cookies from 'js-cookie';
+import { getCookie } from '~/lib/utils/common_utils';
import { VIEW_TYPES } from '../constants';
-const diffViewType = Cookies.get('diff_view');
+const diffViewType = getCookie('diff_view');
export default () => ({
isLoading: true,
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index a40caea1223..ad0117844cd 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -1,20 +1,21 @@
/* eslint-disable no-new, class-methods-use-this */
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import $ from 'jquery';
-import Cookies from 'js-cookie';
import Vue from 'vue';
+import {
+ getCookie,
+ parseUrlPathname,
+ isMetaClick,
+ parseBoolean,
+ scrollToElement,
+} from '~/lib/utils/common_utils';
import createEventHub from '~/helpers/event_hub_factory';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import Diff from './diff';
import createFlash from './flash';
import { initDiffStatsDropdown } from './init_diff_stats_dropdown';
import axios from './lib/utils/axios_utils';
-import {
- parseUrlPathname,
- isMetaClick,
- parseBoolean,
- scrollToElement,
-} from './lib/utils/common_utils';
+
import { localTimeAgo } from './lib/utils/datetime_utility';
import { isInVueNoteablePage } from './lib/utils/dom_utils';
import { __ } from './locale';
@@ -514,7 +515,7 @@ export default class MergeRequestTabs {
// Expand the issuable sidebar unless the user explicitly collapsed it
expandView() {
- if (parseBoolean(Cookies.get('collapsed_gutter'))) {
+ if (parseBoolean(getCookie('collapsed_gutter'))) {
return;
}
const $gutterBtn = $('.js-sidebar-toggle');
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
index 42b08bcaa7b..ee70ff858be 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
@@ -1,8 +1,8 @@
<script>
import { GlButton } from '@gitlab/ui';
-import Cookies from 'js-cookie';
import Vue from 'vue';
-import { parseBoolean } from '~/lib/utils/common_utils';
+import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';
+
import Translate from '../../../../../vue_shared/translate';
Vue.use(Translate);
@@ -17,13 +17,13 @@ export default {
inject: ['docsUrl', 'illustrationUrl'],
data() {
return {
- calloutDismissed: parseBoolean(Cookies.get(cookieKey)),
+ calloutDismissed: parseBoolean(getCookie(cookieKey)),
};
},
methods: {
dismissCallout() {
this.calloutDismissed = true;
- Cookies.set(cookieKey, this.calloutDismissed, { expires: 365 });
+ setCookie(cookieKey, this.calloutDismissed);
},
},
};
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index a26aeeb6db4..0c17bf2f344 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -1,7 +1,7 @@
/* eslint-disable func-names, no-return-assign */
import $ from 'jquery';
-import Cookies from 'js-cookie';
+import { setCookie } from '~/lib/utils/common_utils';
import initClonePanel from '~/clone_panel';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
import createFlash from '~/flash';
@@ -24,19 +24,19 @@ export default class Project {
}
$('.js-hide-no-ssh-message').on('click', function (e) {
- Cookies.set('hide_no_ssh_message', 'false');
+ setCookie('hide_no_ssh_message', 'false');
$(this).parents('.js-no-ssh-key-message').remove();
return e.preventDefault();
});
$('.js-hide-no-password-message').on('click', function (e) {
- Cookies.set('hide_no_password_message', 'false');
+ setCookie('hide_no_password_message', 'false');
$(this).parents('.js-no-password-message').remove();
return e.preventDefault();
});
$('.hide-auto-devops-implicitly-enabled-banner').on('click', function (e) {
const projectId = $(this).data('project-id');
const cookieKey = `hide_auto_devops_implicitly_enabled_banner_${projectId}`;
- Cookies.set(cookieKey, 'false');
+ setCookie(cookieKey, 'false');
$(this).parents('.auto-devops-implicitly-enabled-banner').remove();
return e.preventDefault();
});
diff --git a/app/assets/javascripts/pages/users/index.js b/app/assets/javascripts/pages/users/index.js
index 58ceb524360..5cbb7a06bc1 100644
--- a/app/assets/javascripts/pages/users/index.js
+++ b/app/assets/javascripts/pages/users/index.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import Cookies from 'js-cookie';
+import { setCookie } from '~/lib/utils/common_utils';
import UserCallout from '~/user_callout';
import UserTabs from './user_tabs';
@@ -10,7 +10,7 @@ function initUserProfile(action) {
// hide project limit message
$('.hide-project-limit-message').on('click', (e) => {
e.preventDefault();
- Cookies.set('hide_project_limit_message', 'false');
+ setCookie('hide_project_limit_message', 'false');
$(this).parents('.project-limit-message').remove();
});
}
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index ee9533bbec3..009afe03ea6 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -1,7 +1,7 @@
/* eslint-disable func-names, consistent-return, no-param-reassign */
import $ from 'jquery';
-import Cookies from 'js-cookie';
+import { setCookie } from '~/lib/utils/common_utils';
import { hide, fixTitle } from '~/tooltips';
import createFlash from './flash';
import axios from './lib/utils/axios_utils';
@@ -80,7 +80,7 @@ Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
hide($this);
if (!triggered) {
- Cookies.set('collapsed_gutter', $('.right-sidebar').hasClass('right-sidebar-collapsed'));
+ setCookie('collapsed_gutter', $('.right-sidebar').hasClass('right-sidebar-collapsed'));
}
};
diff --git a/app/assets/javascripts/serverless/survey_banner.vue b/app/assets/javascripts/serverless/survey_banner.vue
index c48c294c0f7..1a49277efa7 100644
--- a/app/assets/javascripts/serverless/survey_banner.vue
+++ b/app/assets/javascripts/serverless/survey_banner.vue
@@ -1,7 +1,6 @@
<script>
import { GlBanner } from '@gitlab/ui';
-import Cookies from 'js-cookie';
-import { parseBoolean } from '~/lib/utils/common_utils';
+import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';
export default {
components: {
@@ -19,13 +18,13 @@ export default {
};
},
created() {
- if (parseBoolean(Cookies.get('hide_serverless_survey'))) {
+ if (parseBoolean(getCookie('hide_serverless_survey'))) {
this.visible = false;
}
},
methods: {
handleClose() {
- Cookies.set('hide_serverless_survey', 'true', { expires: 365 * 10 });
+ setCookie('hide_serverless_survey', 'true', { expires: 365 * 10 });
this.visible = false;
},
},
diff --git a/app/assets/javascripts/user_callout.js b/app/assets/javascripts/user_callout.js
index 44e54c85f3c..ee23f8c5a0c 100644
--- a/app/assets/javascripts/user_callout.js
+++ b/app/assets/javascripts/user_callout.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import Cookies from 'js-cookie';
+import { getCookie, setCookie } from '~/lib/utils/common_utils';
export default class UserCallout {
constructor(options = {}) {
@@ -9,7 +9,7 @@ export default class UserCallout {
this.userCalloutBody = $(`.${className}`);
this.cookieName = this.userCalloutBody.data('uid');
- this.isCalloutDismissed = Cookies.get(this.cookieName);
+ this.isCalloutDismissed = getCookie(this.cookieName);
this.init();
}
@@ -30,7 +30,7 @@ export default class UserCallout {
cookieOptions.path = this.userCalloutBody.data('projectPath');
}
- Cookies.set(this.cookieName, 'true', cookieOptions);
+ setCookie(this.cookieName, 'true', cookieOptions);
if ($currentTarget.hasClass('close') || $currentTarget.hasClass('js-close')) {
this.userCalloutBody.remove();
diff --git a/app/assets/javascripts/vue_alerts.js b/app/assets/javascripts/vue_alerts.js
index b44f787cf30..f3bf121c0f8 100644
--- a/app/assets/javascripts/vue_alerts.js
+++ b/app/assets/javascripts/vue_alerts.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
-import Cookies from 'js-cookie';
-import { parseBoolean } from '~/lib/utils/common_utils';
+import { setCookie, parseBoolean } from '~/lib/utils/common_utils';
+
import DismissibleAlert from '~/vue_shared/components/dismissible_alert.vue';
const getCookieExpirationPeriod = (expirationPeriod) => {
@@ -33,7 +33,7 @@ const mountVueAlert = (el) => {
if (!dismissCookieName) {
return;
}
- Cookies.set(dismissCookieName, true, {
+ setCookie(dismissCookieName, true, {
expires: getCookieExpirationPeriod(dismissCookieExpire),
});
},
diff --git a/app/assets/javascripts/vue_shared/issuable/sidebar/components/issuable_sidebar_root.vue b/app/assets/javascripts/vue_shared/issuable/sidebar/components/issuable_sidebar_root.vue
index 99dcccd12ed..774267639fc 100644
--- a/app/assets/javascripts/vue_shared/issuable/sidebar/components/issuable_sidebar_root.vue
+++ b/app/assets/javascripts/vue_shared/issuable/sidebar/components/issuable_sidebar_root.vue
@@ -1,8 +1,8 @@
<script>
import { GlIcon } from '@gitlab/ui';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
-import Cookies from 'js-cookie';
-import { parseBoolean } from '~/lib/utils/common_utils';
+import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';
+
import { USER_COLLAPSED_GUTTER_COOKIE } from '../constants';
export default {
@@ -10,7 +10,7 @@ export default {
GlIcon,
},
data() {
- const userExpanded = !parseBoolean(Cookies.get(USER_COLLAPSED_GUTTER_COOKIE));
+ const userExpanded = !parseBoolean(getCookie(USER_COLLAPSED_GUTTER_COOKIE));
// We're deliberately keeping two different props for sidebar status;
// 1. userExpanded reflects value based on cookie `collapsed_gutter`.
@@ -46,7 +46,7 @@ export default {
this.isExpanded = !this.isExpanded;
this.userExpanded = this.isExpanded;
- Cookies.set(USER_COLLAPSED_GUTTER_COOKIE, !this.userExpanded);
+ setCookie(USER_COLLAPSED_GUTTER_COOKIE, !this.userExpanded);
this.updatePageContainerClass();
},
},
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 10026e290e8..b858d457969 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -259,10 +259,9 @@ $tabs-holder-z-index: 250;
> span {
display: inline-block;
max-width: 12.5em;
- margin-bottom: -3px;
+ margin-bottom: -6px;
white-space: nowrap;
text-overflow: ellipsis;
- line-height: 14px;
overflow: hidden;
}
}
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 689ca32f6d9..ef229a2abec 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -31,6 +31,7 @@ class GraphqlController < ApplicationController
before_action :authorize_access_api!
before_action :set_user_last_activity
before_action :track_vs_code_usage
+ before_action :track_jetbrains_usage
before_action :disable_query_limiting
before_action :limit_query_size
@@ -137,6 +138,11 @@ class GraphqlController < ApplicationController
.track_api_request_when_trackable(user_agent: request.user_agent, user: current_user)
end
+ def track_jetbrains_usage
+ Gitlab::UsageDataCounters::JetBrainsPluginActivityUniqueCounter
+ .track_api_request_when_trackable(user_agent: request.user_agent, user: current_user)
+ end
+
def execute_multiplex
GitlabSchema.multiplex(multiplex_queries, context: context)
end
diff --git a/app/finders/users_finder.rb b/app/finders/users_finder.rb
index 8054ecbd502..50b9c312292 100644
--- a/app/finders/users_finder.rb
+++ b/app/finders/users_finder.rb
@@ -32,7 +32,7 @@ class UsersFinder
end
def execute
- users = User.all.order_id_desc
+ users = base_scope
users = by_username(users)
users = by_id(users)
users = by_admins(users)
@@ -53,6 +53,10 @@ class UsersFinder
private
+ def base_scope
+ User.all.order_id_desc
+ end
+
def by_username(users)
return users unless params[:username]
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 89b32a61e2e..c9966d87b68 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -62,23 +62,29 @@ module ProjectsHelper
name: author.name
}
- author_html = []
+ inject_classes = ["author-link"]
+
+ if opts[:name]
+ inject_classes.concat(["js-user-link", opts[:extra_class], opts[:mobile_classes]])
+ else
+ inject_classes.append( "has-tooltip" )
+ end
+ inject_classes = inject_classes.compact.join(" ")
+
+ author_html = []
# Build avatar image tag
author_html << link_to_member_avatar(author, opts) if opts[:avatar]
-
# Build name span tag
author_html << author_content_tag(author, opts) if opts[:name]
-
author_html << capture(&block) if block
-
author_html = author_html.join.html_safe
if opts[:name]
- link_to(author_html, user_path(author), class: "author-link js-user-link #{"#{opts[:extra_class]}" if opts[:extra_class]} #{"#{opts[:mobile_classes]}" if opts[:mobile_classes]}", data: data_attrs).html_safe
+ link_to(author_html, user_path(author), class: inject_classes, data: data_attrs).html_safe
else
title = opts[:title].sub(":name", sanitize(author.name))
- link_to(author_html, user_path(author), class: "author-link has-tooltip", title: title, data: { container: 'body', qa_selector: 'assignee_link' }).html_safe
+ link_to(author_html, user_path(author), class: inject_classes, title: title, data: { container: 'body', qa_selector: 'assignee_link' }).html_safe
end
end
diff --git a/config/feature_flags/development/jobs_tab_vue.yml b/config/feature_flags/development/jobs_tab_vue.yml
index 2958532922a..d6e797f66a5 100644
--- a/config/feature_flags/development/jobs_tab_vue.yml
+++ b/config/feature_flags/development/jobs_tab_vue.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347371
milestone: '14.6'
type: development
group: group::pipeline execution
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_i_code_review_user_jetbrains_api_request.yml b/config/feature_flags/development/usage_data_i_code_review_user_jetbrains_api_request.yml
new file mode 100644
index 00000000000..3ab01c78a28
--- /dev/null
+++ b/config/feature_flags/development/usage_data_i_code_review_user_jetbrains_api_request.yml
@@ -0,0 +1,8 @@
+---
+name: usage_data_i_code_review_user_jetbrains_api_request
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78713
+rollout_issue_url:
+milestone: '14.8'
+type: development
+group: group::code review
+default_enabled: true
diff --git a/config/initializers_before_autoloader/004_zeitwerk.rb b/config/initializers_before_autoloader/004_zeitwerk.rb
index 4d8dcf4de6b..cb05bf1abb2 100644
--- a/config/initializers_before_autoloader/004_zeitwerk.rb
+++ b/config/initializers_before_autoloader/004_zeitwerk.rb
@@ -39,6 +39,7 @@ Rails.autoloaders.each do |autoloader|
'hangouts_chat_http_override' => 'HangoutsChatHTTPOverride',
'chunked_io' => 'ChunkedIO',
'http_io' => 'HttpIO',
+ 'jetbrains_plugin_activity_unique_counter' => 'JetBrainsPluginActivityUniqueCounter',
'json_formatter' => 'JSONFormatter',
'json_web_token' => 'JSONWebToken',
'as_json' => 'AsJSON',
diff --git a/config/metrics/aggregates/code_review.yml b/config/metrics/aggregates/code_review.yml
index 04a0b5e34e9..aee0e602e7b 100644
--- a/config/metrics/aggregates/code_review.yml
+++ b/config/metrics/aggregates/code_review.yml
@@ -73,6 +73,7 @@
- 'i_code_review_post_merge_click_cherry_pick'
- 'i_code_review_post_merge_submit_revert_modal'
- 'i_code_review_post_merge_submit_cherry_pick_modal'
+ - 'i_code_review_user_jetbrains_api_request'
- name: code_review_category_monthly_active_users
operator: OR
source: redis
@@ -144,3 +145,4 @@
time_frame: [7d, 28d]
events:
- 'i_code_review_user_vs_code_api_request'
+ - 'i_code_review_user_jetbrains_api_request'
diff --git a/config/metrics/counts_28d/20220121140644_user_jetbrains_api_request_monthly.yml b/config/metrics/counts_28d/20220121140644_user_jetbrains_api_request_monthly.yml
new file mode 100644
index 00000000000..deae309753a
--- /dev/null
+++ b/config/metrics/counts_28d/20220121140644_user_jetbrains_api_request_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_user_jetbrains_api_request_monthly
+description: Count of unique users per month who use GitLab plugin for JetBrains
+product_section: dev
+product_stage: create
+product_group: group::code review
+product_category: editor_extension
+value_type: number
+status: active
+milestone: "14.8"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78713
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_user_jetbrains_api_request
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220121140634_user_jetbrains_api_request_weekly.yml b/config/metrics/counts_7d/20220121140634_user_jetbrains_api_request_weekly.yml
new file mode 100644
index 00000000000..40e7b3ba04f
--- /dev/null
+++ b/config/metrics/counts_7d/20220121140634_user_jetbrains_api_request_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_user_jetbrains_api_request_weekly
+description: Count of unique users per month who use GitLab plugin for JetBrains
+product_section: dev
+product_stage: create
+product_group: group::code review
+product_category: editor_extension
+value_type: number
+status: active
+milestone: "14.8"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78713
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_user_jetbrains_api_request
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/db/post_migrate/20220201173212_add_user_details_provisioning_index.rb b/db/post_migrate/20220201173212_add_user_details_provisioning_index.rb
new file mode 100644
index 00000000000..a864ec7e395
--- /dev/null
+++ b/db/post_migrate/20220201173212_add_user_details_provisioning_index.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddUserDetailsProvisioningIndex < Gitlab::Database::Migration[1.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'idx_user_details_on_provisioned_by_group_id_user_id'
+ OLD_INDEX_NAME = 'index_user_details_on_provisioned_by_group_id'
+
+ def up
+ add_concurrent_index :user_details, [:provisioned_by_group_id, :user_id], name: INDEX_NAME
+ remove_concurrent_index_by_name :user_details, OLD_INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :user_details, :provisioned_by_group_id, name: OLD_INDEX_NAME
+ remove_concurrent_index_by_name :user_details, INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20220201173212 b/db/schema_migrations/20220201173212
new file mode 100644
index 00000000000..b07c8e371a5
--- /dev/null
+++ b/db/schema_migrations/20220201173212
@@ -0,0 +1 @@
+7a48d49d576d183198df370593642419da5707d8b018a23f541c448e2aa7ad65 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 085ce257403..cb5653a896d 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -25345,6 +25345,8 @@ CREATE INDEX idx_security_scans_on_scan_type ON security_scans USING btree (scan
CREATE UNIQUE INDEX idx_serverless_domain_cluster_on_clusters_applications_knative ON serverless_domain_cluster USING btree (clusters_applications_knative_id);
+CREATE INDEX idx_user_details_on_provisioned_by_group_id_user_id ON user_details USING btree (provisioned_by_group_id, user_id);
+
CREATE UNIQUE INDEX idx_vuln_signatures_on_occurrences_id_and_signature_sha ON vulnerability_finding_signatures USING btree (finding_id, signature_sha);
CREATE UNIQUE INDEX idx_vuln_signatures_uniqueness_signature_sha ON vulnerability_finding_signatures USING btree (finding_id, algorithm_type, signature_sha);
@@ -27987,8 +27989,6 @@ CREATE UNIQUE INDEX index_user_details_on_phone ON user_details USING btree (pho
COMMENT ON INDEX index_user_details_on_phone IS 'JiHu-specific index';
-CREATE INDEX index_user_details_on_provisioned_by_group_id ON user_details USING btree (provisioned_by_group_id);
-
CREATE UNIQUE INDEX index_user_details_on_user_id ON user_details USING btree (user_id);
CREATE INDEX index_user_group_callouts_on_group_id ON user_group_callouts USING btree (group_id);
diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md
index 43293385ed9..8c5bd295a57 100644
--- a/doc/administration/packages/container_registry.md
+++ b/doc/administration/packages/container_registry.md
@@ -1548,6 +1548,46 @@ To fix this you can do one of two things:
We use a concrete example to illustrate how to
diagnose a problem with the S3 setup.
+#### Investigate a cleanup policy
+
+If you're unsure why your cleanup policy did or didn't delete a tag, execute the policy line by line
+by running the below script from the [Rails console](../../administration/operations/rails_console.md).
+This can help diagnose problems with the policy.
+
+```ruby
+repo = ContainerRepository.find(<project_id>)
+policy = repo.project.container_expiration_policy
+
+tags = repo.tags
+tags.map(&:name)
+
+tags.reject!(&:latest?)
+tags.map(&:name)
+
+regex_delete = ::Gitlab::UntrustedRegexp.new("\\A#{policy.name_regex}\\z")
+regex_retain = ::Gitlab::UntrustedRegexp.new("\\A#{policy.name_regex_keep}\\z")
+
+tags.select! { |tag| regex_delete.match?(tag.name) && !regex_retain.match?(tag.name) }
+
+tags.map(&:name)
+
+now = DateTime.current
+tags.sort_by! { |tag| tag.created_at || now }.reverse! # Lengthy operation
+
+tags = tags.drop(policy.keep_n)
+tags.map(&:name)
+
+older_than_timestamp = ChronicDuration.parse(policy.older_than).seconds.ago
+
+tags.select! { |tag| tag.created_at && tag.created_at < older_than_timestamp }
+
+tags.map(&:name)
+```
+
+- The script builds the list of tags to delete (`tags`).
+- `tags.map(&:name)` prints a list of tags to remove. This may be a lengthy operation.
+- After each filter, check the list of `tags` to see if it contains the intended tags to destroy.
+
#### Unexpected 403 error during push
A user attempted to enable an S3-backed Registry. The `docker login` step went
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 764622a91ec..d1baa8c0a67 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -1523,3 +1523,75 @@ DELETE /groups/:id/push_rule
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
+
+## Provisioned users API **(PREMIUM)**
+
+> Introduced in GitLab 14.8.
+
+### List provisioned users
+
+Get a list of users provisioned by a given group. Does not include users provisioned by subgroups.
+Requires at least the Maintainer role on the group.
+
+```plaintext
+GET /group/:provisioned_group_id/provisioned_users
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+|------------------------|----------|----------|-----------------------------------------------|
+| `provisioned_group_id` | integer | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
+| `username` | string | no | Get a single user with a specific username |
+| `search` | string | no | Filter list by name, email or username |
+| `active` | boolean | no | Filters only active users |
+| `blocked` | boolean | no | Filters only blocked users |
+| `created_after` | datetime | no | Return users created after the specified time |
+| `created_before` | datetime | no | Return users created before the specified time |
+
+```json
+[
+ {
+ id: 66,
+ username: "user22",
+ name: "John Doe22",
+ state: "active",
+ avatar_url: "https://www.gravatar.com/avatar/xxx?s=80&d=identicon",
+ web_url: "http://my.gitlab.com/user22",
+ created_at: "2021-09-10T12:48:22.381Z",
+ bio: "",
+ location: null,
+ public_email: "",
+ skype: "",
+ linkedin: "",
+ twitter: "",
+ website_url: "",
+ organization: null,
+ job_title: "",
+ pronouns: null,
+ bot: false,
+ work_information: null,
+ followers: 0,
+ following: 0,
+ local_time: null,
+ last_sign_in_at: null,
+ confirmed_at: "2021-09-10T12:48:22.330Z",
+ last_activity_on: null,
+ email: "user22@example.org",
+ theme_id: 1,
+ color_scheme_id: 1,
+ projects_limit: 100000,
+ current_sign_in_at: null,
+ identities: [ ],
+ can_create_group: true,
+ can_create_project: true,
+ two_factor_enabled: false,
+ external: false,
+ private_profile: false,
+ commit_email: "user22@example.org",
+ shared_runners_minutes_limit: null,
+ extra_shared_runners_minutes_limit: null
+ },
+ ...
+]
+```
diff --git a/doc/ci/runners/configure_runners.md b/doc/ci/runners/configure_runners.md
index d439702572a..60e21653a45 100644
--- a/doc/ci/runners/configure_runners.md
+++ b/doc/ci/runners/configure_runners.md
@@ -332,10 +332,6 @@ try to preserve worktrees and try to re-use them by default.
This has limitations when using the [Docker Machine executor](https://docs.gitlab.com/runner/executors/docker_machine.html).
-It does not work for [the `kubernetes` executor](https://docs.gitlab.com/runner/executors/kubernetes.html),
-but a [feature proposal](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/3847) exists.
-The `kubernetes` executor always clones into an temporary directory.
-
A Git strategy of `none` also re-uses the local working copy, but skips all Git
operations normally done by GitLab. GitLab Runner pre-clone scripts are also skipped,
if present. This strategy could mean you need to add `fetch` and `checkout` commands
diff --git a/lib/api/api.rb b/lib/api/api.rb
index bfd070ba6da..d47709311dd 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -76,6 +76,10 @@ module API
Gitlab::UsageDataCounters::VSCodeExtensionActivityUniqueCounter.track_api_request_when_trackable(user_agent: request&.user_agent, user: @current_user)
end
+ after do
+ Gitlab::UsageDataCounters::JetBrainsPluginActivityUniqueCounter.track_api_request_when_trackable(user_agent: request&.user_agent, user: @current_user)
+ end
+
# The locale is set to the current user's locale when `current_user` is loaded
after { Gitlab::I18n.use_default_locale }
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index ac3b4de0988..2bd59415771 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -27,6 +27,7 @@ module Gitlab
gon.revision = Gitlab.revision
gon.feature_category = Gitlab::ApplicationContext.current_context_attribute(:feature_category).presence
gon.gitlab_logo = ActionController::Base.helpers.asset_path('gitlab_logo.png')
+ gon.secure = Gitlab.config.gitlab.https
gon.sprite_icons = IconsHelper.sprite_icon_path
gon.sprite_file_icons = IconsHelper.sprite_file_icons_path
gon.emoji_sprites_css_path = ActionController::Base.helpers.stylesheet_path('emoji_sprites')
diff --git a/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb
new file mode 100644
index 00000000000..f3d5be5e28f
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module UsageDataCounters
+ module JetBrainsPluginActivityUniqueCounter
+ JETBRAINS_API_REQUEST_ACTION = 'i_code_review_user_jetbrains_api_request'
+ JETBRAINS_USER_AGENT_REGEX = /\Agitlab-jetbrains-plugin/.freeze
+
+ class << self
+ def track_api_request_when_trackable(user_agent:, user:)
+ user_agent&.match?(JETBRAINS_USER_AGENT_REGEX) && track_unique_action_by_user(JETBRAINS_API_REQUEST_ACTION, user)
+ end
+
+ private
+
+ def track_unique_action_by_user(action, user)
+ return unless user
+
+ track_unique_action(action, user.id)
+ end
+
+ def track_unique_action(action, value)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_usage_event(action, value)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
index 9668b727099..42c51ec3921 100644
--- a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
@@ -127,6 +127,11 @@
redis_slot: code_review
category: code_review
aggregation: weekly
+- name: i_code_review_user_jetbrains_api_request
+ redis_slot: code_review
+ category: code_review
+ aggregation: weekly
+ feature_flag: usage_data_i_code_review_user_jetbrains_api_request
- name: i_code_review_user_create_mr_from_issue
redis_slot: code_review
category: code_review
diff --git a/qa/qa.rb b/qa/qa.rb
index 703ed4ffe1d..105dde787f5 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -51,7 +51,8 @@ module QA
"smtp" => "SMTP",
"otp" => "OTP",
"jira_api" => "JiraAPI",
- "registry_tls" => "RegistryTLS"
+ "registry_tls" => "RegistryTLS",
+ "jetbrains" => "JetBrains"
)
loader.setup
diff --git a/qa/qa/tools/reliable_report.rb b/qa/qa/tools/reliable_report.rb
index b99b97c1ea6..27e54c2d8bf 100644
--- a/qa/qa/tools/reliable_report.rb
+++ b/qa/qa/tools/reliable_report.rb
@@ -58,7 +58,7 @@ module QA
{
title: "Reliable e2e test report",
description: report_issue_body,
- labels: "Quality,test,type::maintenance,reliable test report"
+ labels: "Quality,test,type::maintenance,reliable test report,automation:devops-mapping-disable"
},
headers: { "PRIVATE-TOKEN" => gitlab_access_token }
)
diff --git a/qa/spec/tools/reliable_report_spec.rb b/qa/spec/tools/reliable_report_spec.rb
index 1ff62df34e0..85b2590d3aa 100644
--- a/qa/spec/tools/reliable_report_spec.rb
+++ b/qa/spec/tools/reliable_report_spec.rb
@@ -167,7 +167,7 @@ describe QA::Tools::ReliableReport do
payload: {
title: "Reliable e2e test report",
description: issue_body,
- labels: "Quality,test,type::maintenance,reliable test report"
+ labels: "Quality,test,type::maintenance,reliable test report,automation:devops-mapping-disable"
}
)
expect(slack_notifier).to have_received(:post).with(
diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb
index 578ce04721c..95f60156c40 100644
--- a/spec/controllers/graphql_controller_spec.rb
+++ b/spec/controllers/graphql_controller_spec.rb
@@ -124,6 +124,16 @@ RSpec.describe GraphqlController do
post :execute
end
+
+ it 'calls the track jetbrains api when trackable method' do
+ agent = 'gitlab-jetbrains-plugin/0.0.1 intellij-idea/2021.2.4 java/11.0.13 mac-os-x/aarch64/12.1'
+ request.env['HTTP_USER_AGENT'] = agent
+
+ expect(Gitlab::UsageDataCounters::JetBrainsPluginActivityUniqueCounter)
+ .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user)
+
+ post :execute
+ end
end
context 'when user uses an API token' do
@@ -151,6 +161,16 @@ RSpec.describe GraphqlController do
subject
end
+
+ it 'calls the track jetbrains api when trackable method' do
+ agent = 'gitlab-jetbrains-plugin/0.0.1 intellij-idea/2021.2.4 java/11.0.13 mac-os-x/aarch64/12.1'
+ request.env['HTTP_USER_AGENT'] = agent
+
+ expect(Gitlab::UsageDataCounters::JetBrainsPluginActivityUniqueCounter)
+ .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user)
+
+ subject
+ end
end
context 'when user is not logged in' do
diff --git a/spec/frontend/broadcast_notification_spec.js b/spec/frontend/broadcast_notification_spec.js
index 8d433946632..cd947cd417a 100644
--- a/spec/frontend/broadcast_notification_spec.js
+++ b/spec/frontend/broadcast_notification_spec.js
@@ -30,6 +30,7 @@ describe('broadcast message on dismiss', () => {
expect(Cookies.set).toHaveBeenCalledWith('hide_broadcast_message_1', true, {
expires: new Date(endsAt),
+ secure: false,
});
});
});
diff --git a/spec/frontend/code_quality_walkthrough/components/step_spec.js b/spec/frontend/code_quality_walkthrough/components/step_spec.js
index bdbcda5f902..b43629c2f96 100644
--- a/spec/frontend/code_quality_walkthrough/components/step_spec.js
+++ b/spec/frontend/code_quality_walkthrough/components/step_spec.js
@@ -118,7 +118,7 @@ describe('When the code_quality_walkthrough URL parameter is present', () => {
expect(Cookies.set).toHaveBeenCalledWith(
EXPERIMENT_NAME,
{ commit_ci_file: true, data: dummyContext },
- { expires: 365 },
+ { expires: 365, secure: false },
);
});
diff --git a/spec/frontend/design_management/components/design_sidebar_spec.js b/spec/frontend/design_management/components/design_sidebar_spec.js
index f690974db1b..a818a86bef6 100644
--- a/spec/frontend/design_management/components/design_sidebar_spec.js
+++ b/spec/frontend/design_management/components/design_sidebar_spec.js
@@ -254,7 +254,10 @@ describe('Design management design sidebar component', () => {
it(`sets a ${cookieKey} cookie on clicking outside the popover`, () => {
jest.spyOn(Cookies, 'set');
wrapper.trigger('click');
- expect(Cookies.set).toHaveBeenCalledWith(cookieKey, 'true', { expires: 365 * 10 });
+ expect(Cookies.set).toHaveBeenCalledWith(cookieKey, 'true', {
+ expires: 365 * 10,
+ secure: false,
+ });
});
});
diff --git a/spec/frontend/emoji/components/utils_spec.js b/spec/frontend/emoji/components/utils_spec.js
index 36521eb1051..03eeb6b6bf7 100644
--- a/spec/frontend/emoji/components/utils_spec.js
+++ b/spec/frontend/emoji/components/utils_spec.js
@@ -31,6 +31,7 @@ describe('addToFrequentlyUsed', () => {
expect(Cookies.set).toHaveBeenCalledWith('frequently_used_emojis', 'thumbsup', {
expires: 365,
+ secure: false,
});
});
@@ -41,6 +42,7 @@ describe('addToFrequentlyUsed', () => {
expect(Cookies.set).toHaveBeenCalledWith('frequently_used_emojis', 'thumbsdown,thumbsup', {
expires: 365,
+ secure: false,
});
});
@@ -51,6 +53,7 @@ describe('addToFrequentlyUsed', () => {
expect(Cookies.set).toHaveBeenCalledWith('frequently_used_emojis', 'thumbsup', {
expires: 365,
+ secure: false,
});
});
});
diff --git a/spec/frontend/groups/landing_spec.js b/spec/frontend/groups/landing_spec.js
index f90f541eb96..d60adea202b 100644
--- a/spec/frontend/groups/landing_spec.js
+++ b/spec/frontend/groups/landing_spec.js
@@ -159,7 +159,10 @@ describe('Landing', () => {
});
it('should call Cookies.set', () => {
- expect(Cookies.set).toHaveBeenCalledWith(test.cookieName, 'true', { expires: 365 });
+ expect(Cookies.set).toHaveBeenCalledWith(test.cookieName, 'true', {
+ expires: 365,
+ secure: false,
+ });
});
});
diff --git a/spec/frontend/merge_conflicts/store/actions_spec.js b/spec/frontend/merge_conflicts/store/actions_spec.js
index 8fa8765a9f9..3e1774a6d56 100644
--- a/spec/frontend/merge_conflicts/store/actions_spec.js
+++ b/spec/frontend/merge_conflicts/store/actions_spec.js
@@ -207,7 +207,10 @@ describe('merge conflicts actions', () => {
],
[],
() => {
- expect(Cookies.set).toHaveBeenCalledWith('diff_view', payload);
+ expect(Cookies.set).toHaveBeenCalledWith('diff_view', payload, {
+ expires: 365,
+ secure: false,
+ });
done();
},
);
diff --git a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
index 2f61b5e9800..c28a03b35d7 100644
--- a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
+++ b/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
@@ -84,6 +84,7 @@ describe('Pipeline Schedule Callout', () => {
expect(setCookiesSpy).toHaveBeenCalledWith('pipeline_schedules_callout_dismissed', true, {
expires: 365,
+ secure: false,
});
});
});
diff --git a/spec/frontend/serverless/survey_banner_spec.js b/spec/frontend/serverless/survey_banner_spec.js
index 022aa47c113..3408d610089 100644
--- a/spec/frontend/serverless/survey_banner_spec.js
+++ b/spec/frontend/serverless/survey_banner_spec.js
@@ -37,7 +37,10 @@ describe('Knative survey banner', () => {
wrapper.find(GlBanner).vm.$emit('close');
await nextTick();
- expect(Cookies.set).toHaveBeenCalledWith('hide_serverless_survey', 'true', { expires: 3650 });
+ expect(Cookies.set).toHaveBeenCalledWith('hide_serverless_survey', 'true', {
+ expires: 3650,
+ secure: false,
+ });
expect(wrapper.find(GlBanner).exists()).toBe(false);
});
diff --git a/spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js b/spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js
index 1ef1304185d..47bf3c8ed83 100644
--- a/spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js
+++ b/spec/frontend/vue_shared/issuable/sidebar/components/issuable_sidebar_root_spec.js
@@ -70,7 +70,10 @@ describe('IssuableSidebarRoot', () => {
it('updates "collapsed_gutter" cookie value and layout classes', async () => {
await findToggleSidebarButton().trigger('click');
- expect(Cookies.set).toHaveBeenCalledWith(USER_COLLAPSED_GUTTER_COOKIE, true);
+ expect(Cookies.set).toHaveBeenCalledWith(USER_COLLAPSED_GUTTER_COOKIE, true, {
+ expires: 365,
+ secure: false,
+ });
assertPageLayoutClasses({ isExpanded: false });
});
});
diff --git a/spec/lib/gitlab/gon_helper_spec.rb b/spec/lib/gitlab/gon_helper_spec.rb
index b8ed4cf608d..047873d8237 100644
--- a/spec/lib/gitlab/gon_helper_spec.rb
+++ b/spec/lib/gitlab/gon_helper_spec.rb
@@ -6,9 +6,41 @@ RSpec.describe Gitlab::GonHelper do
let(:helper) do
Class.new do
include Gitlab::GonHelper
+
+ def current_user
+ nil
+ end
end.new
end
+ describe '#add_gon_variables' do
+ let(:gon) { double('gon').as_null_object }
+ let(:https) { true }
+
+ before do
+ allow(helper).to receive(:gon).and_return(gon)
+ stub_config_setting(https: https)
+ end
+
+ context 'when HTTPS is enabled' do
+ it 'sets the secure flag to true' do
+ expect(gon).to receive(:secure=).with(true)
+
+ helper.add_gon_variables
+ end
+ end
+
+ context 'when HTTP is enabled' do
+ let(:https) { false }
+
+ it 'sets the secure flag to false' do
+ expect(gon).to receive(:secure=).with(false)
+
+ helper.add_gon_variables
+ end
+ end
+ end
+
describe '#push_frontend_feature_flag' do
before do
skip_feature_flags_yaml_validation
diff --git a/spec/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter_spec.rb
new file mode 100644
index 00000000000..64fa8d26d81
--- /dev/null
+++ b/spec/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples 'a tracked jetbrains unique action' do |event|
+ before do
+ stub_application_setting(usage_ping_enabled: true)
+ end
+
+ def count_unique(date_from:, date_to:)
+ Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: action, start_date: date_from, end_date: date_to)
+ end
+
+ it 'tracks when the user agent is from jetbrains' do
+ aggregate_failures do
+ user_agent = { user_agent: 'gitlab-jetbrains-plugin/0.0.1 intellij-idea/2021.2.4 java/11.0.13 mac-os-x/aarch64/12.1' }
+
+ expect(track_action(user: user1, **user_agent)).to be_truthy
+ expect(track_action(user: user1, **user_agent)).to be_truthy
+ expect(track_action(user: user2, **user_agent)).to be_truthy
+
+ expect(count_unique(date_from: time - 1.week, date_to: time + 1.week)).to eq(2)
+ end
+ end
+
+ it 'does not track when the user agent is not from jetbrains' do
+ aggregate_failures do
+ user_agent = { user_agent: 'normal_user_agent' }
+
+ expect(track_action(user: user1, **user_agent)).to be_falsey
+ expect(track_action(user: user1, **user_agent)).to be_falsey
+ expect(track_action(user: user2, **user_agent)).to be_falsey
+
+ expect(count_unique(date_from: time - 1.week, date_to: time + 1.week)).to eq(0)
+ end
+ end
+
+ it 'does not track if user agent is not present' do
+ expect(track_action(user: nil, user_agent: nil)).to be_nil
+ end
+
+ it 'does not track if user is not present' do
+ user_agent = { user_agent: 'gitlab-jetbrains-plugin/0.0.1 intellij-idea/2021.2.4 java/11.0.13 mac-os-x/aarch64/12.1' }
+
+ expect(track_action(user: nil, **user_agent)).to be_nil
+ end
+end
+
+RSpec.describe Gitlab::UsageDataCounters::JetBrainsPluginActivityUniqueCounter, :clean_gitlab_redis_shared_state do
+ let(:user1) { build(:user, id: 1) }
+ let(:user2) { build(:user, id: 2) }
+ let(:time) { Time.current }
+
+ context 'when tracking a jetbrains api request' do
+ it_behaves_like 'a tracked jetbrains unique action' do
+ let(:action) { described_class::JETBRAINS_API_REQUEST_ACTION }
+
+ def track_action(params)
+ described_class.track_api_request_when_trackable(**params)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
index 882c79cb03f..127b1a6d4c4 100644
--- a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
@@ -3,11 +3,11 @@
RSpec.shared_examples 'group and project packages query' do
include GraphqlHelpers
- let_it_be(:versionaless_package) { create(:maven_package, project: project1, version: nil) }
- let_it_be(:maven_package) { create(:maven_package, project: project1, name: 'tab', version: '4.0.0', created_at: 5.days.ago) }
- let_it_be(:package) { create(:npm_package, project: project1, name: 'uab', version: '5.0.0', created_at: 4.days.ago) }
- let_it_be(:composer_package) { create(:composer_package, project: project2, name: 'vab', version: '6.0.0', created_at: 3.days.ago) }
- let_it_be(:debian_package) { create(:debian_package, project: project2, name: 'zab', version: '7.0.0', created_at: 2.days.ago) }
+ let_it_be(:versionless_package) { create(:maven_package, project: project1, version: nil) }
+ let_it_be(:maven_package) { create(:maven_package, project: project1, name: 'bab', version: '6.0.0', created_at: 1.day.ago) }
+ let_it_be(:npm_package) { create(:npm_package, project: project1, name: 'cab', version: '7.0.0', created_at: 4.days.ago) }
+ let_it_be(:composer_package) { create(:composer_package, project: project2, name: 'dab', version: '4.0.0', created_at: 3.days.ago) }
+ let_it_be(:debian_package) { create(:debian_package, project: project2, name: 'aab', version: '5.0.0', created_at: 2.days.ago) }
let_it_be(:composer_metadatum) do
create(:composer_metadatum, package: composer_package,
target_sha: 'afdeh',
@@ -21,11 +21,11 @@ RSpec.shared_examples 'group and project packages query' do
let(:fields) do
<<~QUERY
- count
- nodes {
- #{all_graphql_fields_for('packages'.classify, excluded: ['project'])}
- metadata { #{query_graphql_fragment('ComposerMetadata')} }
- }
+ count
+ nodes {
+ #{all_graphql_fields_for('packages'.classify, excluded: ['project'])}
+ metadata { #{query_graphql_fragment('ComposerMetadata')} }
+ }
QUERY
end
@@ -47,7 +47,7 @@ RSpec.shared_examples 'group and project packages query' do
it 'returns packages successfully' do
expect(package_names).to contain_exactly(
- package.name,
+ npm_package.name,
maven_package.name,
debian_package.name,
composer_package.name
@@ -88,7 +88,23 @@ RSpec.shared_examples 'group and project packages query' do
end
describe 'sorting and pagination' do
- let_it_be(:ascending_packages) { [maven_package, package, composer_package, debian_package].map { |package| global_id_of(package)} }
+ let_it_be(:packages_order_map) do
+ {
+ TYPE_ASC: [maven_package, npm_package, composer_package, debian_package],
+ TYPE_DESC: [debian_package, composer_package, npm_package, maven_package],
+
+ NAME_ASC: [debian_package, maven_package, npm_package, composer_package],
+ NAME_DESC: [composer_package, npm_package, maven_package, debian_package],
+
+ VERSION_ASC: [composer_package, debian_package, maven_package, npm_package],
+ VERSION_DESC: [npm_package, maven_package, debian_package, composer_package],
+
+ CREATED_ASC: [npm_package, composer_package, debian_package, maven_package],
+ CREATED_DESC: [maven_package, debian_package, composer_package, npm_package]
+ }
+ end
+
+ let(:expected_packages) { sorted_packages.map { |package| global_id_of(package) } }
let(:data_path) { [resource_type, :packages] }
@@ -96,22 +112,14 @@ RSpec.shared_examples 'group and project packages query' do
resource.add_reporter(current_user)
end
- [:CREATED_ASC, :NAME_ASC, :VERSION_ASC, :TYPE_ASC].each do |order|
+ [:CREATED_ASC, :NAME_ASC, :VERSION_ASC, :TYPE_ASC, :CREATED_DESC, :NAME_DESC, :VERSION_DESC, :TYPE_DESC].each do |order|
context "#{order}" do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { order }
- let(:first_param) { 4 }
- let(:all_records) { ascending_packages }
- end
- end
- end
+ let(:sorted_packages) { packages_order_map.fetch(order) }
- [:CREATED_DESC, :NAME_DESC, :VERSION_DESC, :TYPE_DESC].each do |order|
- context "#{order}" do
it_behaves_like 'sorted paginated query' do
let(:sort_param) { order }
let(:first_param) { 4 }
- let(:all_records) { ascending_packages.reverse }
+ let(:all_records) { expected_packages }
end
end
end
@@ -180,7 +188,7 @@ RSpec.shared_examples 'group and project packages query' do
context 'include_versionless' do
let(:params) { { include_versionless: true } }
- it { is_expected.to include({ "name" => versionaless_package.name }) }
+ it { is_expected.to include({ "name" => versionless_package.name }) }
end
end
end