mirror of
https://github.com/gitlabhq/gitlabhq.git
synced 2025-08-15 23:30:46 +00:00
Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
@ -772,17 +772,6 @@ rspec-ee unit gitlab-duo-chat pg14:
|
||||
- !reference [.base-script, script]
|
||||
- rspec_paralellized_job "--fail-fast=${RSPEC_FAIL_FAST_THRESHOLD} --tag real_ai_request"
|
||||
|
||||
rspec-ee unit gitlab-duo-chat-open-ai pg14:
|
||||
variables:
|
||||
REAL_AI_REQUEST: "true"
|
||||
OPENAI_EMBEDDINGS: "true"
|
||||
extends:
|
||||
- .rspec-ee-base-pg14
|
||||
- .rails:rules:ee-gitlab-duo-chat-open-ai
|
||||
script:
|
||||
- !reference [.base-script, script]
|
||||
- rspec_paralellized_job "--fail-fast=${RSPEC_FAIL_FAST_THRESHOLD} --tag real_ai_request"
|
||||
|
||||
rspec-ee migration pg14:
|
||||
extends:
|
||||
- .rspec-ee-base-pg14
|
||||
|
@ -2129,14 +2129,6 @@
|
||||
- if: '$VERTEX_AI_EMBEDDINGS == null'
|
||||
when: never
|
||||
|
||||
.rails:rules:ee-gitlab-duo-chat-open-ai:
|
||||
rules:
|
||||
- !reference [".rails:rules:ee-gitlab-duo-chat-base", rules]
|
||||
- if: '$OPENAI_API_KEY == null'
|
||||
when: never
|
||||
- if: '$OPENAI_EMBEDDINGS == null'
|
||||
when: never
|
||||
|
||||
.rails:rules:as-if-foss-migration:
|
||||
rules:
|
||||
- !reference [".strict-ee-only-rules", rules]
|
||||
|
@ -255,7 +255,6 @@ Style/FormatString:
|
||||
- 'lib/gitlab/exceptions_app.rb'
|
||||
- 'lib/gitlab/github_import/importer/single_endpoint_issue_events_importer.rb'
|
||||
- 'lib/gitlab/github_import/issuable_finder.rb'
|
||||
- 'lib/gitlab/github_import/label_finder.rb'
|
||||
- 'lib/gitlab/github_import/object_counter.rb'
|
||||
- 'lib/gitlab/github_import/page_counter.rb'
|
||||
- 'lib/gitlab/github_import/parallel_scheduling.rb'
|
||||
|
8
Gemfile
8
Gemfile
@ -363,10 +363,10 @@ gem 'gitlab-labkit', '~> 0.34.0' # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
gem 'thrift', '>= 0.16.0' # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
|
||||
# I18n
|
||||
gem 'rails-i18n', '~> 7.0' # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
gem 'gettext_i18n_rails', '~> 1.11.0' # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
gem 'gettext_i18n_rails_js', '~> 1.3' # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
gem 'gettext', '~> 3.3', require: false, group: :development # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
gem 'rails-i18n', '~> 7.0', feature_category: :internationalization
|
||||
gem 'gettext_i18n_rails', '~> 1.11.0', feature_category: :internationalization
|
||||
gem 'gettext_i18n_rails_js', '~> 2.0.0', feature_category: :internationalization
|
||||
gem 'gettext', '~> 3.3', require: false, group: :development, feature_category: :internationalization
|
||||
|
||||
gem 'batch-loader', '~> 2.0.1' # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
|
||||
|
@ -194,15 +194,16 @@
|
||||
{"name":"fog-local","version":"0.8.0","platform":"ruby","checksum":"263b2d09e54c69d1b87ad7f235a1a1e53c8a674edcedf7512c1715765ad7ef79"},
|
||||
{"name":"fog-xml","version":"0.1.3","platform":"ruby","checksum":"5604c42649ebb0d8a31bd973aa000c2dd0127f1c1c4c174b69266a2e78e37410"},
|
||||
{"name":"formatador","version":"0.2.5","platform":"ruby","checksum":"80821869ddacb79e72870ff4bb1531efacd278c04f2df26bc6b4529ee13582bd"},
|
||||
{"name":"forwardable","version":"1.3.3","platform":"ruby","checksum":"f17df4bd6afa6f46a003217023fe5716ef88ce261f5c4cf0edbdeed6470cafac"},
|
||||
{"name":"fugit","version":"1.8.1","platform":"ruby","checksum":"18ffb26813869610f71bb0b7d568c3624d2b3025aeebb6600a18df0c77a6a2b2"},
|
||||
{"name":"fuubar","version":"2.2.0","platform":"ruby","checksum":"9b0263c4074f39c68b37f1e4e69a7d3cfc7523c41bea43601235daa723179b4a"},
|
||||
{"name":"fuzzyurl","version":"0.9.0","platform":"ruby","checksum":"542efa80f2bcaadbdc402c2f0b572f2e335a1d53e375aecad68bbb3d86860c0f"},
|
||||
{"name":"gapic-common","version":"0.18.0","platform":"ruby","checksum":"6fd55a538ce2d63026fa05f379b1aec00788cc060f76903739516ab1ca1496ab"},
|
||||
{"name":"gemoji","version":"3.0.1","platform":"ruby","checksum":"80553f2f4932a7a95fb1b3c7c63f7dd937e7c8c610164bbdea28fd06eba5f36d"},
|
||||
{"name":"get_process_mem","version":"0.2.7","platform":"ruby","checksum":"4afd3c3641dd6a817c09806c7d6d509d8a9984512ac38dea8b917426bbf77eba"},
|
||||
{"name":"gettext","version":"3.3.6","platform":"ruby","checksum":"ee6bbd1b2f833ee52d7797fa68acbfecc4726aec6b6280fd7eab92aa0190b413"},
|
||||
{"name":"gettext","version":"3.4.9","platform":"ruby","checksum":"292864fe6a15c224cee4125a4a72fab426fdbb280e4cff3cfe44935f549b009a"},
|
||||
{"name":"gettext_i18n_rails","version":"1.11.0","platform":"ruby","checksum":"e19c7e4a256c500f7f38396dca44a282b9838ae278f57c362993a54964b22bbe"},
|
||||
{"name":"gettext_i18n_rails_js","version":"1.3.0","platform":"ruby","checksum":"5d10afe4be3639bff78c50a56768c20f39aecdabc580c08aa45573911c2bd687"},
|
||||
{"name":"gettext_i18n_rails_js","version":"2.0.0","platform":"ruby","checksum":"7bfb72699e3cdf9a2d892cc816e70442a08d0f4e340b92731249ad38b9205b51"},
|
||||
{"name":"git","version":"1.18.0","platform":"ruby","checksum":"c9b80462e4565cd3d7a9ba8440c41d2c52244b17b0dad0bfddb46de70630c465"},
|
||||
{"name":"gitaly","version":"16.5.0.pre.rc1","platform":"ruby","checksum":"ed17515ad04d4663a0efc15c8f2887b705f006133e8b10cc9321460eb0a38353"},
|
||||
{"name":"gitlab","version":"4.19.0","platform":"ruby","checksum":"3f645e3e195dbc24f0834fbf83e8ccfb2056d8e9712b01a640aad418a6949679"},
|
||||
@ -446,9 +447,10 @@
|
||||
{"name":"pg_query","version":"4.2.3","platform":"ruby","checksum":"1cc9955c7bce8e51e1abc11f1952e3d9d0f1cd4c16c58c56ec75d5aaf1cfd697"},
|
||||
{"name":"plist","version":"3.6.0","platform":"ruby","checksum":"f468bcf6b72ec6d1585ed6744eb4817c1932a5bf91895ed056e69b7f12ca10f2"},
|
||||
{"name":"png_quantizator","version":"0.2.1","platform":"ruby","checksum":"6023d4d064125c3a7e02929c95b7320ed6ac0d7341f9e8de0c9ea6576ef3106b"},
|
||||
{"name":"po_to_json","version":"1.0.1","platform":"ruby","checksum":"6a7188aa6c42a22c9718f9b39062862ef7f3d8f6a7b4177cae058c3308b56af7"},
|
||||
{"name":"po_to_json","version":"2.0.0","platform":"ruby","checksum":"9e59b2904c015d2fcad3ec02022970ad0fb6622f6eb5ba82b47dff99d2fd6b2a"},
|
||||
{"name":"premailer","version":"1.16.0","platform":"ruby","checksum":"03e4402c448e6bae13fb5f6301a8bde4f3508e1bff90ae7c0972c7be94694786"},
|
||||
{"name":"premailer-rails","version":"1.10.3","platform":"ruby","checksum":"7cdcb97027866f7a81c490c6d15ada7f39666b5f6375f0821b7e97e0483b112f"},
|
||||
{"name":"prime","version":"0.1.2","platform":"ruby","checksum":"d4e956cadfaf04de036dc7dc74f95bf6a285a62cc509b28b7a66b245d19fe3a4"},
|
||||
{"name":"proc_to_ast","version":"0.1.0","platform":"ruby","checksum":"92a73fa66e2250a83f8589f818b0751bcf227c68f85916202df7af85082f8691"},
|
||||
{"name":"prometheus-client-mmap","version":"0.28.1","platform":"aarch64-linux","checksum":"b190045625ee8f8b3ef90e583ef7fadeac745810c8a243f1ed5e9b47c18146f0"},
|
||||
{"name":"prometheus-client-mmap","version":"0.28.1","platform":"arm64-darwin","checksum":"9e7022848493b882d1de9f42d7784f9821e83b2c3b4b2dc9a12c2c8269209a6e"},
|
||||
@ -586,6 +588,7 @@
|
||||
{"name":"simplecov-html","version":"0.12.3","platform":"ruby","checksum":"4b1aad33259ffba8b29c6876c12db70e5750cb9df829486e4c6e5da4fa0aa07b"},
|
||||
{"name":"simplecov-lcov","version":"0.8.0","platform":"ruby","checksum":"0115f31cb7ef5ec4334f5d9382c67fd43de2e5270e21b65bfc693da82dd713c1"},
|
||||
{"name":"simplecov_json_formatter","version":"0.1.4","platform":"ruby","checksum":"529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428"},
|
||||
{"name":"singleton","version":"0.1.1","platform":"ruby","checksum":"b410b0417fcbb17bdfbc2d478ddba4c91e873d6e51c9d2d16b345c5ee5491c54"},
|
||||
{"name":"sixarm_ruby_unaccent","version":"1.2.0","platform":"ruby","checksum":"0043a6077bdf2c4b03040152676a07f8bf77144f9b007b1960ee5c94d13a4384"},
|
||||
{"name":"slack-messenger","version":"2.3.4","platform":"ruby","checksum":"49c611d2be5b0f9c250a3a957b9cc09b9c07b81dacb9843642d87b6fa35609c1"},
|
||||
{"name":"snaky_hash","version":"2.0.0","platform":"ruby","checksum":"fe8b2e39e8ff69320f7812af73ea06401579e29ff1734a7009567391600687de"},
|
||||
|
18
Gemfile.lock
18
Gemfile.lock
@ -609,6 +609,7 @@ GEM
|
||||
fog-core
|
||||
nokogiri (>= 1.5.11, < 2.0.0)
|
||||
formatador (0.2.5)
|
||||
forwardable (1.3.3)
|
||||
fugit (1.8.1)
|
||||
et-orbi (~> 1, >= 1.2.7)
|
||||
raabro (~> 1.4)
|
||||
@ -627,15 +628,18 @@ GEM
|
||||
gemoji (3.0.1)
|
||||
get_process_mem (0.2.7)
|
||||
ffi (~> 1.0)
|
||||
gettext (3.3.6)
|
||||
gettext (3.4.9)
|
||||
erubi
|
||||
locale (>= 2.0.5)
|
||||
prime
|
||||
racc
|
||||
text (>= 1.3.0)
|
||||
gettext_i18n_rails (1.11.0)
|
||||
fast_gettext (>= 0.9.0)
|
||||
gettext_i18n_rails_js (1.3.0)
|
||||
gettext_i18n_rails_js (2.0.0)
|
||||
gettext (>= 3.0.2)
|
||||
gettext_i18n_rails (>= 0.7.1)
|
||||
po_to_json (>= 1.0.0)
|
||||
po_to_json (>= 2.0.0)
|
||||
rails (>= 3.2.0)
|
||||
git (1.18.0)
|
||||
addressable (~> 2.8)
|
||||
@ -1200,7 +1204,7 @@ GEM
|
||||
google-protobuf (>= 3.22.3)
|
||||
plist (3.6.0)
|
||||
png_quantizator (0.2.1)
|
||||
po_to_json (1.0.1)
|
||||
po_to_json (2.0.0)
|
||||
json (>= 1.6.0)
|
||||
premailer (1.16.0)
|
||||
addressable
|
||||
@ -1209,6 +1213,9 @@ GEM
|
||||
premailer-rails (1.10.3)
|
||||
actionmailer (>= 3)
|
||||
premailer (~> 1.7, >= 1.7.9)
|
||||
prime (0.1.2)
|
||||
forwardable
|
||||
singleton
|
||||
proc_to_ast (0.1.0)
|
||||
coderay
|
||||
parser
|
||||
@ -1502,6 +1509,7 @@ GEM
|
||||
simplecov-html (0.12.3)
|
||||
simplecov-lcov (0.8.0)
|
||||
simplecov_json_formatter (0.1.4)
|
||||
singleton (0.1.1)
|
||||
sixarm_ruby_unaccent (1.2.0)
|
||||
slack-messenger (2.3.4)
|
||||
snaky_hash (2.0.0)
|
||||
@ -1811,7 +1819,7 @@ DEPENDENCIES
|
||||
fuubar (~> 2.2.0)
|
||||
gettext (~> 3.3)
|
||||
gettext_i18n_rails (~> 1.11.0)
|
||||
gettext_i18n_rails_js (~> 1.3)
|
||||
gettext_i18n_rails_js (~> 2.0.0)
|
||||
gitaly (~> 16.5.0.pre.rc1)
|
||||
gitlab-chronic (~> 0.10.5)
|
||||
gitlab-dangerfiles (~> 4.5.1)
|
||||
|
@ -202,7 +202,9 @@ export default {
|
||||
data-testid="pipeline-info-container"
|
||||
class="gl-display-flex gl-flex-wrap gl-align-items-center gl-justify-content-space-between"
|
||||
>
|
||||
<p class="mr-pipeline-title gl-m-0! gl-mr-3! gl-font-weight-bold gl-text-gray-900">
|
||||
<p
|
||||
class="mr-pipeline-title gl-align-self-start gl-m-0! gl-mr-3! gl-font-weight-bold gl-text-gray-900"
|
||||
>
|
||||
{{ pipeline.details.event_type_name }}
|
||||
<gl-link :href="pipeline.path" class="pipeline-id" data-testid="pipeline-id"
|
||||
>#{{ pipeline.id }}</gl-link
|
||||
|
@ -28,7 +28,7 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="gl-w-6 gl-h-6 gl-display-flex gl-align-self-center gl-mr-3">
|
||||
<div class="gl-w-6 gl-h-6 gl-display-flex gl-align-self-start gl-mr-3">
|
||||
<div class="gl-display-flex gl-m-auto">
|
||||
<gl-icon v-if="isMerged" name="merge" :size="16" class="gl-text-blue-500" />
|
||||
<gl-icon v-else-if="isClosed" name="merge-request-close" :size="16" class="gl-text-red-500" />
|
||||
|
@ -143,7 +143,9 @@ export default {
|
||||
:collapsed="mr.mergeDetailsCollapsed"
|
||||
@toggle="() => mr.toggleMergeDetails()"
|
||||
>
|
||||
<span class="gl-ml-0! gl-text-body! gl-flex-grow-1">
|
||||
<span
|
||||
class="gl-display-inline-flex gl-align-self-start gl-pt-2 gl-ml-0! gl-text-body! gl-flex-grow-1"
|
||||
>
|
||||
<bold-text :message="$options.i18n.removeDraftStatus" />
|
||||
</span>
|
||||
<template #actions>
|
||||
|
@ -7,7 +7,8 @@ import AwardsList from '~/vue_shared/components/awards_list.vue';
|
||||
import { isLoggedIn } from '~/lib/utils/common_utils';
|
||||
import { TYPENAME_USER } from '~/graphql_shared/constants';
|
||||
|
||||
import workItemAwardEmojiQuery from '../graphql/award_emoji.query.graphql';
|
||||
import groupWorkItemAwardEmojiQuery from '../graphql/group_award_emoji.query.graphql';
|
||||
import projectWorkItemAwardEmojiQuery from '../graphql/award_emoji.query.graphql';
|
||||
import updateAwardEmojiMutation from '../graphql/update_award_emoji.mutation.graphql';
|
||||
import {
|
||||
EMOJI_THUMBSDOWN,
|
||||
@ -23,6 +24,7 @@ export default {
|
||||
components: {
|
||||
AwardsList,
|
||||
},
|
||||
inject: ['isGroup'],
|
||||
props: {
|
||||
workItemId: {
|
||||
type: String,
|
||||
@ -75,7 +77,9 @@ export default {
|
||||
},
|
||||
apollo: {
|
||||
awardEmoji: {
|
||||
query: workItemAwardEmojiQuery,
|
||||
query() {
|
||||
return this.isGroup ? groupWorkItemAwardEmojiQuery : projectWorkItemAwardEmojiQuery;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
iid: this.workItemIid,
|
||||
@ -116,7 +120,7 @@ export default {
|
||||
after: this.pageInfo?.endCursor,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
} catch {
|
||||
this.$emit('error', I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR);
|
||||
}
|
||||
},
|
||||
@ -139,7 +143,7 @@ export default {
|
||||
return this.awardEmoji.nodes;
|
||||
}
|
||||
|
||||
// else make a copy of unmutable list and return the list after adding the new emoji
|
||||
// else make a copy of immutable list and return the list after adding the new emoji
|
||||
const awardEmojiNodes = [...this.awardEmoji.nodes];
|
||||
awardEmojiNodes.push({
|
||||
name,
|
||||
@ -162,7 +166,7 @@ export default {
|
||||
},
|
||||
updateWorkItemAwardEmojiWidgetCache({ cache, name, toggledOn }) {
|
||||
const query = {
|
||||
query: workItemAwardEmojiQuery,
|
||||
query: this.isGroup ? groupWorkItemAwardEmojiQuery : projectWorkItemAwardEmojiQuery,
|
||||
variables: {
|
||||
fullPath: this.workItemFullpath,
|
||||
iid: this.workItemIid,
|
||||
|
@ -1,7 +1,7 @@
|
||||
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
|
||||
#import "~/work_items/graphql/award_emoji.fragment.graphql"
|
||||
|
||||
query workItemAwardEmojis($fullPath: ID!, $iid: String, $after: String, $pageSize: Int) {
|
||||
query projectWorkItemAwardEmojis($fullPath: ID!, $iid: String, $after: String, $pageSize: Int) {
|
||||
workspace: project(fullPath: $fullPath) {
|
||||
id
|
||||
workItems(iid: $iid) {
|
||||
|
@ -0,0 +1,27 @@
|
||||
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
|
||||
#import "~/work_items/graphql/award_emoji.fragment.graphql"
|
||||
|
||||
query groupWorkItemAwardEmojis($fullPath: ID!, $iid: String, $after: String, $pageSize: Int) {
|
||||
workspace: group(fullPath: $fullPath) {
|
||||
id
|
||||
workItems(iid: $iid) {
|
||||
nodes {
|
||||
id
|
||||
iid
|
||||
widgets {
|
||||
... on WorkItemWidgetAwardEmoji {
|
||||
type
|
||||
awardEmoji(first: $pageSize, after: $after) {
|
||||
pageInfo {
|
||||
...PageInfo
|
||||
}
|
||||
nodes {
|
||||
...AwardEmojiFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -379,6 +379,10 @@ $tabs-holder-z-index: 250;
|
||||
.deployment-info {
|
||||
margin-bottom: $gl-padding-8;
|
||||
}
|
||||
|
||||
.gl-button {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> *:not(:last-child) {
|
||||
@ -645,6 +649,9 @@ $tabs-holder-z-index: 250;
|
||||
// to the end of the line or to force it to a
|
||||
// new line if there is not enough space.
|
||||
flex-grow: 999;
|
||||
// Avoid layout shift of title when Mini Graph
|
||||
// moves below title
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.label-branch {
|
||||
|
@ -3,6 +3,7 @@
|
||||
module CreatesCommit
|
||||
extend ActiveSupport::Concern
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
include SafeFormatHelper
|
||||
|
||||
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil, target_project: nil)
|
||||
@ -31,10 +32,10 @@ module CreatesCommit
|
||||
result = service.new(@project_to_commit_into, current_user, commit_params).execute
|
||||
|
||||
if result[:status] == :success
|
||||
update_flash_notice(success_notice)
|
||||
|
||||
success_path = final_success_path(success_path, target_project)
|
||||
|
||||
update_flash_notice(success_notice, success_path)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to success_path }
|
||||
format.json { render json: { message: _("success"), filePath: success_path } }
|
||||
@ -65,8 +66,13 @@ module CreatesCommit
|
||||
|
||||
private
|
||||
|
||||
def update_flash_notice(success_notice)
|
||||
flash[:notice] = success_notice || _("Your changes have been successfully committed.")
|
||||
def update_flash_notice(success_notice, success_path)
|
||||
changes_link = ActionController::Base.helpers.link_to _('changes'), success_path, class: 'gl-link'
|
||||
|
||||
default_message = safe_format(_("Your %{changes_link} have been committed successfully."),
|
||||
changes_link: changes_link)
|
||||
|
||||
flash[:notice] = success_notice || default_message
|
||||
|
||||
if create_merge_request?
|
||||
flash[:notice] =
|
||||
|
@ -1,22 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module ViteHelper
|
||||
def universal_javascript_include_tag(*args)
|
||||
if vite_enabled
|
||||
vite_javascript_tag(*args)
|
||||
else
|
||||
javascript_include_tag(*args)
|
||||
end
|
||||
end
|
||||
|
||||
def universal_asset_path(*args)
|
||||
if vite_enabled
|
||||
vite_asset_path(*args)
|
||||
else
|
||||
asset_path(*args)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def vite_enabled
|
||||
|
@ -84,7 +84,7 @@ class ActiveSession
|
||||
)
|
||||
|
||||
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
||||
redis.pipelined do |pipeline|
|
||||
Gitlab::Redis::CrossSlot::Pipeline.new(redis).pipelined do |pipeline|
|
||||
pipeline.setex(
|
||||
key_name(user.id, session_private_id),
|
||||
expiry,
|
||||
@ -135,9 +135,15 @@ class ActiveSession
|
||||
|
||||
redis.srem(lookup_key_name(user.id), session_ids)
|
||||
|
||||
session_keys = rack_session_keys(session_ids)
|
||||
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
||||
redis.del(key_names)
|
||||
redis.del(rack_session_keys(session_ids))
|
||||
if Gitlab::Redis::ClusterUtil.cluster?(redis)
|
||||
Gitlab::Redis::ClusterUtil.batch_unlink(key_names, redis)
|
||||
Gitlab::Redis::ClusterUtil.batch_unlink(session_keys, redis)
|
||||
else
|
||||
redis.del(key_names)
|
||||
redis.del(session_keys)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -206,7 +212,13 @@ class ActiveSession
|
||||
|
||||
session_keys.each_slice(SESSION_BATCH_SIZE).flat_map do |session_keys_batch|
|
||||
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
||||
redis.mget(session_keys_batch).compact.map do |raw_session|
|
||||
raw_sessions = if Gitlab::Redis::ClusterUtil.cluster?(redis)
|
||||
Gitlab::Redis::ClusterUtil.batch_get(session_keys_batch, redis)
|
||||
else
|
||||
redis.mget(session_keys_batch)
|
||||
end
|
||||
|
||||
raw_sessions.compact.map do |raw_session|
|
||||
load_raw_session(raw_session)
|
||||
end
|
||||
end
|
||||
@ -249,7 +261,13 @@ class ActiveSession
|
||||
|
||||
found = Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
||||
entry_keys = session_ids.map { |session_id| key_name(user_id, session_id) }
|
||||
session_ids.zip(redis.mget(entry_keys)).to_h
|
||||
entries = if Gitlab::Redis::ClusterUtil.cluster?(redis)
|
||||
Gitlab::Redis::ClusterUtil.batch_get(entry_keys, redis)
|
||||
else
|
||||
redis.mget(entry_keys)
|
||||
end
|
||||
|
||||
session_ids.zip(entries).to_h
|
||||
end
|
||||
|
||||
found.compact!
|
||||
@ -258,7 +276,13 @@ class ActiveSession
|
||||
|
||||
fallbacks = Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
||||
entry_keys = missing.map { |session_id| key_name_v1(user_id, session_id) }
|
||||
missing.zip(redis.mget(entry_keys)).to_h
|
||||
entries = if Gitlab::Redis::ClusterUtil.cluster?(redis)
|
||||
Gitlab::Redis::ClusterUtil.batch_get(entry_keys, redis)
|
||||
else
|
||||
redis.mget(entry_keys)
|
||||
end
|
||||
|
||||
missing.zip(entries).to_h
|
||||
end
|
||||
|
||||
fallbacks.merge(found.compact)
|
||||
|
@ -71,7 +71,11 @@ module Ci
|
||||
with_redis do |redis|
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/224171
|
||||
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
||||
redis.del(keys)
|
||||
if Gitlab::Redis::ClusterUtil.cluster?(redis)
|
||||
Gitlab::Redis::ClusterUtil.batch_unlink(keys, redis)
|
||||
else
|
||||
redis.del(keys)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420720
|
||||
milestone: '16.3'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
@ -1,8 +0,0 @@
|
||||
---
|
||||
name: use_embeddings_with_vertex
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130421
|
||||
rollout_issue_url:
|
||||
milestone: '16.5'
|
||||
type: development
|
||||
group: group::duo chat
|
||||
default_enabled: false
|
@ -27,6 +27,10 @@ Redis::Cluster::SlotLoader.prepend(Gitlab::Patch::SlotLoader)
|
||||
Redis::Cluster::CommandLoader.prepend(Gitlab::Patch::CommandLoader)
|
||||
Redis::Cluster.prepend(Gitlab::Patch::RedisCluster)
|
||||
|
||||
if Gitlab::Redis::Workhorse.params[:cluster].present?
|
||||
raise "Do not configure workhorse with a Redis Cluster as pub/sub commands are not cluster-compatible."
|
||||
end
|
||||
|
||||
# Make sure we initialize a Redis connection pool before multi-threaded
|
||||
# execution starts by
|
||||
# 1. Sidekiq
|
||||
|
@ -11,6 +11,14 @@ end
|
||||
|
||||
ActionCable::SubscriptionAdapter::Base.prepend(Gitlab::Patch::ActionCableSubscriptionAdapterIdentifier)
|
||||
|
||||
using_redis_cluster = begin
|
||||
Rails.application.config_for(:cable)[:cluster].present?
|
||||
rescue RuntimeError
|
||||
# config/cable.yml does not exist, but that is not the purpose of this check
|
||||
end
|
||||
|
||||
raise "Do not configure cable.yml with a Redis Cluster as ActionCable only works with Redis." if using_redis_cluster
|
||||
|
||||
# https://github.com/rails/rails/blob/bb5ac1623e8de08c1b7b62b1368758f0d3bb6379/actioncable/lib/action_cable/subscription_adapter/redis.rb#L18
|
||||
ActionCable::SubscriptionAdapter::Redis.redis_connector = lambda do |config|
|
||||
args = config.except(:adapter, :channel_prefix)
|
||||
|
@ -18,6 +18,11 @@ development:
|
||||
queues_metadata:
|
||||
cluster:
|
||||
- redis://localhost:7001
|
||||
shared_state:
|
||||
cluster:
|
||||
- redis://localhost:7001
|
||||
workhorse:
|
||||
url: redis://localhost:6379
|
||||
|
||||
test:
|
||||
chat:
|
||||
@ -38,3 +43,10 @@ test:
|
||||
queues_metadata:
|
||||
cluster:
|
||||
- redis://localhost:7001
|
||||
shared_state:
|
||||
cluster:
|
||||
- redis://localhost:7001
|
||||
# pubsub and workhorse are not redis-cluster compatible
|
||||
# even though they fall-back to shared_state
|
||||
workhorse:
|
||||
url: redis://localhost:6379
|
||||
|
@ -7,4 +7,4 @@ feature_categories:
|
||||
description: Stores paths to repository blobs locked by users
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/684e9d1b5979e11d2edae11a3028a696bfcdedf8
|
||||
milestone: '8.9'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_cell
|
||||
|
@ -7,4 +7,4 @@ feature_categories:
|
||||
description: Keeps disk path to repositories and link to the shard
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8614
|
||||
milestone: '11.6'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_cell
|
||||
|
@ -7,4 +7,4 @@ feature_categories:
|
||||
description: Keeps relation between projects and repository languages
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/19480
|
||||
milestone: '11.2'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_cell
|
||||
|
@ -9,4 +9,4 @@ description: |
|
||||
Policies are stored in the repository as a YAML file.
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53743
|
||||
milestone: '13.9'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_cell
|
||||
|
@ -7,4 +7,4 @@ feature_categories:
|
||||
description: Webhooks logs data.
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/330789c23c777d8ca646eba7c25f39cb7342cdee
|
||||
milestone: '9.3'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_cell
|
||||
|
@ -471,3 +471,78 @@ REPOSITORY TAG DIGE
|
||||
gitlab/gitlab-ee latest sha256:723aa6edd8f122d50cae490b1743a616d54d4a910db892314d68470cc39dfb24 (...)
|
||||
gitlab/gitlab-runner latest sha256:4a18a80f5be5df44cb7575f6b89d1fdda343297c6fd666c015c0e778b276e726 (...)
|
||||
```
|
||||
|
||||
## Creating a Custom GitLab Runner Docker Image
|
||||
|
||||
You can create a custom GitLab Runner Docker image to package AWS CLI and Amazon ECR Credential Helper. This setup facilitates
|
||||
secure and streamlined interactions with AWS services, especially for containerized applications. For example, to reduce time
|
||||
and error-prone manual configurations, teams who deploy microservices on AWS can use this setup to manage, deploy,
|
||||
and update Docker images on Amazon ECR, without using manual credential management.
|
||||
|
||||
1. [Authenticate GitLab with AWS](../cloud_deployment/index.md#authenticate-gitlab-with-aws).
|
||||
1. Create a `Dockerfile` with the following content:
|
||||
|
||||
```Dockerfile
|
||||
# Control package versions
|
||||
ARG GITLAB_RUNNER_VERSION=v16.4.0
|
||||
ARG AWS_CLI_VERSION=2.2.30
|
||||
|
||||
# AWS CLI and Amazon ECR Credential Helper
|
||||
FROM amazonlinux as aws-tools
|
||||
RUN set -e \
|
||||
&& yum update -y \
|
||||
&& yum install -y --allowerasing git make gcc curl unzip \
|
||||
&& curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" --output "awscliv2.zip" \
|
||||
&& unzip awscliv2.zip && ./aws/install -i /usr/local/bin \
|
||||
&& yum clean all
|
||||
|
||||
# Download and install ECR Credential Helper
|
||||
RUN curl --location --output /usr/local/bin/docker-credential-ecr-login "https://github.com/awslabs/amazon-ecr-credential-helper/releases/latest/download/docker-credential-ecr-login-linux-amd64"
|
||||
RUN chmod +x /usr/local/bin/docker-credential-ecr-login
|
||||
|
||||
# Configure the ECR Credential Helper
|
||||
RUN mkdir -p /root/.docker
|
||||
RUN echo '{ "credsStore": "ecr-login" }' > /root/.docker/config.json
|
||||
|
||||
# Final image based on GitLab Runner
|
||||
FROM gitlab/gitlab-runner:${GITLAB_RUNNER_VERSION}
|
||||
|
||||
# Install necessary packages
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends jq procps curl unzip groff libgcrypt20 tar gzip less openssh-client \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy AWS CLI and Amazon ECR Credential Helper binaries
|
||||
COPY --from=aws-tools /usr/local/bin/ /usr/local/bin/
|
||||
|
||||
# Copy ECR Credential Helper Configuration
|
||||
COPY --from=aws-tools /root/.docker/config.json /root/.docker/config.json
|
||||
```
|
||||
|
||||
1. To build the custom GitLab Runner Docker image within a `.gitlab-ci.yml`, include the following example below:
|
||||
|
||||
```yaml
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
|
||||
GITLAB_RUNNER_VERSION: v16.4.0
|
||||
AWS_CLI_VERSION: 2.13.21
|
||||
|
||||
stages:
|
||||
- build
|
||||
|
||||
build-image:
|
||||
stage: build
|
||||
script:
|
||||
- echo "Logging into GitLab Container Registry..."
|
||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
- echo "Building Docker image..."
|
||||
- docker build --build-arg GITLAB_RUNNER_VERSION=${GITLAB_RUNNER_VERSION} --build-arg AWS_CLI_VERSION=${AWS_CLI_VERSION} -t ${IMAGE_NAME} .
|
||||
- echo "Pushing Docker image to GitLab Container Registry..."
|
||||
- docker push ${IMAGE_NAME}
|
||||
rules:
|
||||
- changes:
|
||||
- Dockerfile
|
||||
```
|
||||
|
||||
1. [Register the runner](https://docs.gitlab.com/runner/register/index.html#docker).
|
||||
|
@ -703,6 +703,68 @@ to enable the `restrict_user_defined_variables` setting. The setting is `disable
|
||||
If you [store your CI/CD configurations in a different repository](../../ci/pipelines/settings.md#specify-a-custom-cicd-configuration-file),
|
||||
use this setting for control over the environment the pipeline runs in.
|
||||
|
||||
## Exporting variables
|
||||
|
||||
Scripts executed in separate shell contexts do not share exports, aliases,
|
||||
local function definitions, or any other local shell updates.
|
||||
|
||||
This means that if a job fails, variables created by user-defined scripts are not
|
||||
exported.
|
||||
|
||||
When runners execute jobs defined in `.gitlab-ci.yml`:
|
||||
|
||||
- Scripts specified in `before_script` and the main script are executed together in
|
||||
a single shell context, and are concatenated.
|
||||
- Scripts specified in `after_script` run in a shell context completely separate to
|
||||
the `before_script` and the specified scripts.
|
||||
|
||||
Regardless of the shell the scripts are executed in, the runner output includes:
|
||||
|
||||
- Predefined variables.
|
||||
- Variables defined in:
|
||||
- Instance, group, or project CI/CD settings.
|
||||
- The `.gitlab-ci.yml` file in the `variables:` section.
|
||||
- The `.gitlab-ci.yml` file in the `secrets:` section.
|
||||
- The `config.toml`.
|
||||
|
||||
The runner cannot handle manual exports, shell aliases, and functions executed in the body of the script, like `export MY_VARIABLE=1`.
|
||||
|
||||
For example, in the following `.gitlab-ci.yml` file, the following scripts are defined:
|
||||
|
||||
```yaml
|
||||
job:
|
||||
variables:
|
||||
JOB_DEFINED_VARIABLE: "job variable"
|
||||
before_script:
|
||||
- echo "This is the 'before_script' script"
|
||||
- export MY_VARIABLE="variable"
|
||||
script:
|
||||
- echo "This is the 'script' script"
|
||||
- echo "JOB_DEFINED_VARIABLE's value is ${JOB_DEFINED_VARIABLE}"
|
||||
- echo "CI_COMMIT_SHA's value is ${CI_COMMIT_SHA}"
|
||||
- echo "MY_VARIABLE's value is ${MY_VARIABLE}"
|
||||
after_script:
|
||||
- echo "JOB_DEFINED_VARIABLE's value is ${JOB_DEFINED_VARIABLE}"
|
||||
- echo "CI_COMMIT_SHA's value is ${CI_COMMIT_SHA}"
|
||||
- echo "MY_VARIABLE's value is ${MY_VARIABLE}"
|
||||
```
|
||||
|
||||
When the runner executes the job:
|
||||
|
||||
1. `before_script` is executed:
|
||||
1. Prints to the output.
|
||||
1. Defines the variable for `MY_VARIABLE`.
|
||||
1. `script` is executed:
|
||||
1. Prints to the output.
|
||||
1. Prints the value of `JOB_DEFINED_VARIABLE`.
|
||||
1. Prints the value of `CI_COMMIT_SHA`.
|
||||
1. Prints the value of `MY_VARIABLE`.
|
||||
1. `after_script` is executed in a new, separate shell context:
|
||||
1. Prints to the output.
|
||||
1. Prints the value of `JOB_DEFINED_VARIABLE`.
|
||||
1. Prints the value of `CI_COMMIT_SHA`.
|
||||
1. Prints an empty value of `MY_VARIABLE`. The variable value cannot be detected because `after_script` is in a separate shell context to `before_script`.
|
||||
|
||||
## Related topics
|
||||
|
||||
- You can configure [Auto DevOps](../../topics/autodevops/index.md) to pass CI/CD variables
|
||||
|
@ -131,36 +131,9 @@ Gitlab::CurrentSettings.update!(anthropic_api_key: <insert API key>)
|
||||
|
||||
### Populating embeddings and using embeddings fixture
|
||||
|
||||
Currently we have embeddings generate both with OpenAI and VertexAI. Bellow sections explain how to populate
|
||||
Embeddings are generated through VertexAI text embeddings endpoint. The sections below explain how to populate
|
||||
embeddings in the DB or extract embeddings to be used in specs.
|
||||
|
||||
FLAG:
|
||||
We are moving towards having VertexAI embeddings only, so eventually the OpenAI embeddings support will be drop
|
||||
as well as the section bellow will be removed.
|
||||
|
||||
#### OpenAI embeddings
|
||||
|
||||
To seed your development database with the embeddings for GitLab Documentation,
|
||||
you may use the pre-generated embeddings and a Rake task.
|
||||
|
||||
```shell
|
||||
RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:seed_pre_generated
|
||||
```
|
||||
|
||||
The DBCleaner gem we use clear the database tables before each test runs.
|
||||
Instead of fully populating the table `tanuki_bot_mvc` where we store OpenAI embeddings for the documentations,
|
||||
we can add a few selected embeddings to the table from a pre-generated fixture.
|
||||
|
||||
For instance, to test that the question "How can I reset my password" is correctly
|
||||
retrieving the relevant embeddings and answered, we can extract the top N closet embeddings
|
||||
to the question into a fixture and only restore a small number of embeddings quickly.
|
||||
To facilitate an extraction process, a Rake task been written.
|
||||
You can add or remove the questions needed to be tested in the Rake task and run the task to generate a new fixture.
|
||||
|
||||
```shell
|
||||
RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:extract_embeddings
|
||||
```
|
||||
|
||||
#### VertexAI embeddings
|
||||
|
||||
To seed your development database with the embeddings for GitLab Documentation,
|
||||
|
@ -206,7 +206,7 @@ Refer to [`strong_memoize.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/maste
|
||||
|
||||
# good
|
||||
def expensive_method(arg)
|
||||
strong_memoize_with(:expensive_method, arg)
|
||||
strong_memoize_with(:expensive_method, arg) do
|
||||
# ...
|
||||
end
|
||||
end
|
||||
|
@ -13,7 +13,7 @@ On self-managed GitLab, by default this feature is not available. To make it ava
|
||||
|
||||
This is the group-level documentation. For self-managed instances, see the [administration documentation](../../admin_area/reporting/git_abuse_rate_limit.md).
|
||||
|
||||
Git abuse rate limiting is a feature to automatically ban users who download, clone, pull, fetch, or fork more than a specified number of repositories of a group in a given time frame. Banned users cannot access the top-level group or any of its non-public subgroups via HTTP or SSH. The rate limit also applies to users who authenticate with a [personal](../../../user/profile/personal_access_tokens.md) or [group access token](../../../user/group/settings/group_access_tokens.md). Access to unrelated groups is unaffected.
|
||||
Git abuse rate limiting is a feature to automatically ban users who download, clone, pull, fetch, or fork more than a specified number of repositories of a group in a given time frame. Banned users cannot access the top-level group or any of its non-public subgroups via HTTP or SSH. The rate limit also applies to users who authenticate with [personal](../../../user/profile/personal_access_tokens.md) or [group access tokens](../../../user/group/settings/group_access_tokens.md), as well as [CI/CD job tokens](../../../ci/jobs/ci_job_token.md). Access to unrelated groups is unaffected.
|
||||
|
||||
Git abuse rate limiting does not apply to top-level group owners, [deploy tokens](../../../user/project/deploy_tokens/index.md), or [deploy keys](../../../user/project/deploy_keys/index.md).
|
||||
|
||||
|
@ -225,7 +225,7 @@ To install a package:
|
||||
Using a CI/CD job token:
|
||||
|
||||
```shell
|
||||
composer config gitlab-token.<DOMAIN-NAME> gitlab-ci-token ${CI_JOB_TOKEN}
|
||||
composer config -- gitlab-token.<DOMAIN-NAME> gitlab-ci-token "${CI_JOB_TOKEN}"
|
||||
```
|
||||
|
||||
Result in the `auth.json` file:
|
||||
|
@ -8,23 +8,29 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||
|
||||
This SDK is for instrumenting web sites and applications to send data for the GitLab [product analytics functionality](../index.md).
|
||||
|
||||
## How to use the Browser-SDK
|
||||
## How to use the Browser SDK
|
||||
|
||||
### Using the NPM package
|
||||
|
||||
Add the NPM package to your package JSON using your preferred package manager:
|
||||
|
||||
::Tabs
|
||||
|
||||
:::TabTitle yarn
|
||||
|
||||
```shell
|
||||
yarn add @gitlab/application-sdk-browser
|
||||
```
|
||||
|
||||
OR
|
||||
:::TabTitle npm
|
||||
|
||||
```shell
|
||||
npm i @gitlab/application-sdk-browser
|
||||
```
|
||||
|
||||
Then for browser usage you can import the client SDK:
|
||||
::EndTabs
|
||||
|
||||
Then, for browser usage import the client SDK:
|
||||
|
||||
```javascript
|
||||
import { glClientSDK } from '@gitlab/application-sdk-browser';
|
||||
@ -52,9 +58,9 @@ You can use a specific version of the SDK like this:
|
||||
<script src="https://unpkg.com/@gitlab/application-sdk-browser@0.2.5/dist/gl-sdk.min.js"></script>
|
||||
```
|
||||
|
||||
## Browser-SDK initialization options
|
||||
## Browser SDK initialization options
|
||||
|
||||
Apart from `appId` and `host`, the options below allow you to configure the Browser SDK.
|
||||
Apart from `appId` and `host`, you can configure the Browser SDK with the following options:
|
||||
|
||||
```typescript
|
||||
interface GitLabClientSDKOptions {
|
||||
@ -73,32 +79,48 @@ interface GitLabClientSDKOptions {
|
||||
}
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| :---------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `appId` | This is the ID given by the GitLab Project Analytics setup guide. This is used to make sure your data is sent to your analytics instance. |
|
||||
| `host` | This is the GitLab Project Analytics instance that is given by the setup guide. |
|
||||
| `hasCookieConsent` | To use cookies to identify unique users and record their full IP address. This is set to `false` by default. When `false`, users will be considered anonymous users. No cookies or other storage mechanisms will be used to identify users. |
|
||||
| `respectGlobalPrivacyControl` | To respect the user's [GPC](https://globalprivacycontrol.org/) configuration to permit or refuse tracking. This is set to `true` by default. When `false`, events will be emitted regardless of user configuration. |
|
||||
| `trackerId` | The `trackerId` is used to differentiate between multiple trackers running on the same page or application, as each tracker instance can be configured differently to capture different sets of data. This identifier helps ensure that the data sent to the collector is correctly associated with the correct tracker configuration. `Default trackerId value is set as gitlab`. |
|
||||
| `pagePingTracking` | Page ping is a feature that allows you to `track user engagement on your website or application by sending periodic events while a user is actively browsing a page.` Page pings provide valuable insight into how users interact with your content, such as how long they spend on a page, which sections they are viewing, and if they are scrolling or not. `pagePingTracking` can be boolean or an object. If true it enables page ping with default options. if false, it will not enable page ping tracking. it can also be an object containing two options : `minimumVisitLength` - The minimum time that must have elapsed before first heartbeat. `heartbeatDelay` - The interval at which the callback is fired. |
|
||||
| `plugins` | Specify which plugins to enable or disable. By default all plugins are enabled. |
|
||||
| Option | Description |
|
||||
| :---------------------------- | :---------- |
|
||||
| `appId` | The ID provided by the GitLab Project Analytics setup guide. This ID ensures your data is sent to your analytics instance. |
|
||||
| `host` | The GitLab Project Analytics instance provided by the setup guide. |
|
||||
| `hasCookieConsent` | Whether to use cookies to identify unique users and record their full IP address. Set to `false` by default. When `false`, users are considered anonymous users. No cookies or other storage mechanisms are used to identify users. |
|
||||
| `respectGlobalPrivacyControl` | Whether to respect the user's [GPC](https://globalprivacycontrol.org/) configuration to permit or refuse tracking. Set to `true` by default. When `false`, events are emitted regardless of user configuration. |
|
||||
| `trackerId` | Used to differentiate between multiple trackers running on the same page or application, because each tracker instance can be configured differently to capture different sets of data. This identifier helps ensure that the data sent to the collector is correctly associated with the correct tracker configuration. Default value is `gitlab`. |
|
||||
| `pagePingTracking` | Option to track user engagement on your website or application by sending periodic events while a user is actively browsing a page. Page pings provide valuable insight into how users interact with your content, such as how long they spend on a page, which sections they are viewing, and whether they are scrolling. `pagePingTracking` can be boolean or an object. As a boolean, set to `true` it enables page ping with default options, and set to `false` it disables page ping tracking. As an object, it has two options: `minimumVisitLength` (the minimum time that must have elapsed before the first heartbeat) and `heartbeatDelay` (the interval at which the callback is fired). |
|
||||
| `plugins` | Specify which plugins to enable or disable. By default all plugins are enabled. |
|
||||
|
||||
### Plugins
|
||||
|
||||
- `Client Hints`: It is an alternative the tracking the User Agent, which is particularly useful in those browsers which are freezing the User Agent string.
|
||||
- `Client Hints`: An alternative to tracking the User Agent, which is particularly useful in browsers that are freezing the User Agent string.
|
||||
Enabling this plugin will automatically capture the following context:
|
||||
|
||||
| Context | Example |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [iglu:org.ietf/http_client_hints/jsonschema/1-0-0](https://github.com/snowplow/iglu-central/blob/master/schemas/org.ietf/http_client_hints/jsonschema/1-0-0) | `{"isMobile" : false, "brands" : [{"brand" : "Google Chrome", version : "89"}, {"brand" : "Chromium", version : "89"}]}` |
|
||||
For example,
|
||||
[iglu:org.ietf/http_client_hints/jsonschema/1-0-0](https://github.com/snowplow/iglu-central/blob/master/schemas/org.ietf/http_client_hints/jsonschema/1-0-0)
|
||||
has the following configuration:
|
||||
|
||||
- `Link Click Tracking`: With this plugin, the tracker will add click event listeners to all link elements. Link clicks are tracked as self-describing events. Each link-click event captures the link’s href attribute. The event also has fields for the link’s ID, classes, and target (where the linked document is opened, such as a new tab or new window).
|
||||
```json
|
||||
{
|
||||
"isMobile":false,
|
||||
"brands":[
|
||||
{
|
||||
"brand":"Google Chrome",
|
||||
"version":"89"
|
||||
},
|
||||
{
|
||||
"brand":"Chromium",
|
||||
"version":"89"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `Performance Timing`: It collects performance-related data from a user's browser using the `Navigation Timing API`. This API provides detailed information about the various stages of loading a web page, such as domain lookup, connection time, content download, and rendering times. This plugin helps to gather insights into how well website performs for users, identify potential performance bottlenecks, and improve the overall user experience.
|
||||
- `Link Click Tracking`: With this plugin, the tracker adds click event listeners to all link elements. Link clicks are tracked as self-describing events. Each link-click event captures the link's `href` attribute. The event also has fields for the link's ID, classes, and target (where the linked document is opened, such as a new tab or new window).
|
||||
|
||||
- `Error Tracking`: It helps to capture and track errors that occur on website or application. By monitoring these errors, one can gain insights into potential issues with code or third-party libraries, which can help to improve the overall user experience and maintain the quality of website or application.
|
||||
- `Performance Timing`: It collects performance-related data from a user's browser using the `Navigation Timing API`. This API provides detailed information about the various stages of loading a web page, such as domain lookup, connection time, content download, and rendering times. This plugin helps to gather insights into how well a website performs for users, identify potential performance bottlenecks, and improve the overall user experience.
|
||||
|
||||
`By default all the plugins are enabled`. These plugins can be enabled or disabled through the `plugins` object:
|
||||
- `Error Tracking`: It helps to capture and track errors that occur on a website or application. By monitoring these errors, you can gain insights into potential issues with code or third-party libraries, which can help to improve the overall user experience, and maintain the quality of the website or application.
|
||||
|
||||
By default all plugins are enabled. You can disable or enable these plugins through the `plugins` object:
|
||||
|
||||
```typescript
|
||||
const tracker = glClientSDK({
|
||||
@ -124,7 +146,7 @@ glClient.identify(userId, userAttributes);
|
||||
|
||||
| Property | Type | Description |
|
||||
| :--------------- | :-------------------------- | :---------------------------------------------------------------------------- |
|
||||
| `userId` | `String` | The user identifier your application users to identify individual users. |
|
||||
| `userId` | `String` | The user identifier your application uses to identify individual users. |
|
||||
| `userAttributes` | `Object`/`Null`/`undefined` | The user attributes that need to be added to the session and tracking events. |
|
||||
|
||||
### `page`
|
||||
@ -152,9 +174,9 @@ glClient.track(eventName, eventAttributes);
|
||||
| `eventName` | `String` | The name of the custom event. |
|
||||
| `eventAttributes` | `Object`/`Null`/`undefined` | The event attributes that need to be added to the tracked event. |
|
||||
|
||||
### refreshLinkClickTracking
|
||||
### `refreshLinkClickTracking`
|
||||
|
||||
enableLinkClickTracking only tracks clicks on links which exist when the page has loaded. If new links can be added to the page after then which you wish to track, just use refreshLinkClickTracking.
|
||||
`enableLinkClickTracking` tracks only clicks on links that exist when the page has loaded. To track new links added to the page after it has been loaded, use `refreshLinkClickTracking`.
|
||||
|
||||
```javascript
|
||||
glClient.refreshLinkClickTracking();
|
||||
@ -163,9 +185,9 @@ glClient.refreshLinkClickTracking();
|
||||
### `trackError`
|
||||
|
||||
NOTE:
|
||||
While `trackError` is supported on the Browser SDK the resulting events are currently not yet used or available anywhere.
|
||||
`trackError` is supported on the Browser SDK, but the resulting events are not used or available.
|
||||
|
||||
Used to capture errors. This works only when the `errorTracking` plugin is enabled. As mentioned in [Plugins](#plugins) section, By default it is enabled.
|
||||
Used to capture errors. This works only when the `errorTracking` plugin is enabled. The [plugin](#plugins) is enabled by default.
|
||||
|
||||
```javascript
|
||||
glClient.trackError(eventAttributes);
|
||||
@ -190,17 +212,17 @@ try {
|
||||
|
||||
| Property | Type | Description |
|
||||
| :---------------- | :------- | :------------------------------------------------------------------------------------------------------------------- |
|
||||
| `eventAttributes` | `Object` | The event attributes that need to be added to the tracked event. `messeage` is a mandatory key in `eventAttributes`. |
|
||||
| `eventAttributes` | `Object` | The event attributes that need to be added to the tracked event. `message` is a mandatory key in `eventAttributes`. |
|
||||
|
||||
### `addCookieConsent`
|
||||
|
||||
`addCookieConsent` is used to allow tracking of user identifiers via cookies. By default `hasCookieConsent` is false and no user identifiers are passed. To enable tracking of user identifiers call the `addCookieConsent` method. This is not needed if you intialised the Browser SDK with `hasCookieConsent` set to true.
|
||||
`addCookieConsent` is used to allow tracking of user identifiers via cookies. By default `hasCookieConsent` is false, and no user identifiers are passed. To enable tracking of user identifiers, call the `addCookieConsent` method. This step is not needed if you intialized the Browser SDK with `hasCookieConsent` set to true.
|
||||
|
||||
```javascript
|
||||
glClient.addCookieConsent();
|
||||
```
|
||||
|
||||
### setCustomUrl
|
||||
### `setCustomUrl`
|
||||
|
||||
Used to set a custom URL for tracking.
|
||||
|
||||
@ -212,7 +234,7 @@ glClient.setCustomUrl(url);
|
||||
| :------- | :------- | :------------------------------------------------ |
|
||||
| `url` | `String` | The custom URL that you want to set for tracking. |
|
||||
|
||||
### setReferrerUrl
|
||||
### `setReferrerUrl`
|
||||
|
||||
Used to set a referrer URL for tracking.
|
||||
|
||||
@ -224,9 +246,9 @@ glClient.setReferrerUrl(url);
|
||||
| :------- | :------- | :-------------------------------------------------- |
|
||||
| `url` | `String` | The referrer URL that you want to set for tracking. |
|
||||
|
||||
### setDocumentTitle
|
||||
### `setDocumentTitle`
|
||||
|
||||
Used to override document title.
|
||||
Used to override the document title.
|
||||
|
||||
```javascript
|
||||
glClient.setDocumentTitle(title);
|
||||
@ -234,18 +256,18 @@ glClient.setDocumentTitle(title);
|
||||
|
||||
| Property | Type | Description |
|
||||
| :------- | :------- | :--------------------------------- |
|
||||
| `title` | `String` | The document title you want to set |
|
||||
| `title` | `String` | The document title you want to set. |
|
||||
|
||||
## Contribute
|
||||
|
||||
Want to contribute to Browser-SDK? follow [contributing guide](https://gitlab.com/gitlab-org/analytics-section/product-analytics/gl-application-sdk-js/-/blob/main/docs/Contributing.md).
|
||||
If you would like to contribute to Browser SDK, follow the [contributing guide](https://gitlab.com/gitlab-org/analytics-section/product-analytics/gl-application-sdk-js/-/blob/main/docs/Contributing.md).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If the Browser SDK is not sending events or is behaving in an unexpected way, take the following actions:
|
||||
If the Browser SDK is not sending events, or behaving in an unexpected way, take the following actions:
|
||||
|
||||
- Verify that the appId and host values in the options object are correct.
|
||||
- Check if any browser privacy settings, extensions, or ad blockers are interfering with the Browser SDK.
|
||||
1. Verify that the `appId` and host values in the options object are correct.
|
||||
1. Check if any browser privacy settings, extensions, or ad blockers are interfering with the Browser SDK.
|
||||
|
||||
For more information and assistance, consult the [Snowplow documentation](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/browser-tracker/browser-tracker-v3-reference/)
|
||||
or contact the [Analytics Instrumentation](https://about.gitlab.com/handbook/engineering/development/analytics/analytics-instrumentation/#team-members) team.
|
||||
For more information and assistance, see the [Snowplow documentation](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/browser-tracker/browser-tracker-v3-reference/)
|
||||
or contact the [Analytics Instrumentation team](https://about.gitlab.com/handbook/engineering/development/analytics/analytics-instrumentation/#team-members).
|
||||
|
@ -10,7 +10,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||
|
||||
When you have a lot of issues, it can be hard to get an overview.
|
||||
With weighted issues, you can get a better idea of how much time,
|
||||
value, or complexity a given issue has or costs.
|
||||
value, or complexity a given issue has or costs. You can also [sort by weight](sorting_issue_lists.md#sorting-by-weight)
|
||||
to see which issues need to be prioritized.
|
||||
|
||||
## View the issue weight
|
||||
|
||||
|
@ -7,6 +7,7 @@ module Gitlab
|
||||
|
||||
# The base cache key to use for storing/retrieving label IDs.
|
||||
CACHE_KEY = 'github-import/label-finder/%{project}/%{name}'
|
||||
CACHE_OBJECT_NOT_FOUND = -1
|
||||
|
||||
# project - An instance of `Project`.
|
||||
def initialize(project)
|
||||
@ -15,7 +16,18 @@ module Gitlab
|
||||
|
||||
# Returns the label ID for the given name.
|
||||
def id_for(name)
|
||||
Gitlab::Cache::Import::Caching.read_integer(cache_key_for(name))
|
||||
cache_key = cache_key_for(name)
|
||||
val = Gitlab::Cache::Import::Caching.read_integer(cache_key)
|
||||
|
||||
return val if Feature.disabled?(:import_fallback_to_db_empty_cache, project)
|
||||
|
||||
return if val == CACHE_OBJECT_NOT_FOUND
|
||||
return val if val.present?
|
||||
|
||||
object_id = project.labels.with_title(name).pick(:id) || CACHE_OBJECT_NOT_FOUND
|
||||
|
||||
Gitlab::Cache::Import::Caching.write(cache_key, object_id)
|
||||
object_id == CACHE_OBJECT_NOT_FOUND ? nil : object_id
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
@ -32,7 +44,7 @@ module Gitlab
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def cache_key_for(name)
|
||||
CACHE_KEY % { project: project.id, name: name }
|
||||
format(CACHE_KEY, project: project.id, name: name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -100,7 +100,7 @@ module Gitlab
|
||||
def refresh_keys_expiration
|
||||
with_redis do |redis|
|
||||
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
||||
redis.pipelined do |pipeline|
|
||||
Gitlab::Redis::CrossSlot::Pipeline.new(redis).pipelined do |pipeline|
|
||||
pipeline.expire(issue_ids_key, REDIS_EXPIRY_TIME)
|
||||
pipeline.expire(current_index_key, REDIS_EXPIRY_TIME)
|
||||
pipeline.expire(current_project_key, REDIS_EXPIRY_TIME)
|
||||
|
@ -26,6 +26,15 @@ module Gitlab
|
||||
end
|
||||
expired_count
|
||||
end
|
||||
|
||||
# Redis cluster alternative to mget
|
||||
def batch_get(keys, redis)
|
||||
keys.each_slice(1000).flat_map do |subset|
|
||||
Gitlab::Redis::CrossSlot::Pipeline.new(redis).pipelined do |pipeline|
|
||||
subset.map { |key| pipeline.get(key) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -94,8 +94,17 @@ module Gitlab
|
||||
|
||||
keys = job_ids.map { |jid| key_for(jid) }
|
||||
|
||||
with_redis { |redis| redis.mget(*keys) }
|
||||
.map { |result| !result.nil? }
|
||||
status = with_redis do |redis|
|
||||
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
||||
if Gitlab::Redis::ClusterUtil.cluster?(redis)
|
||||
Gitlab::Redis::ClusterUtil.batch_get(keys, redis)
|
||||
else
|
||||
redis.mget(*keys)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
status.map { |result| !result.nil? }
|
||||
end
|
||||
|
||||
# Returns the JIDs that are completed
|
||||
|
@ -5491,6 +5491,9 @@ msgstr ""
|
||||
msgid "Analytics|Create your visualization"
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Current month to date"
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Custom dashboards"
|
||||
msgstr ""
|
||||
|
||||
@ -5557,6 +5560,9 @@ msgstr ""
|
||||
msgid "Analytics|Event Props"
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Event counts update hourly"
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Failed to fetch data"
|
||||
msgstr ""
|
||||
|
||||
@ -5602,6 +5608,9 @@ msgstr ""
|
||||
msgid "Analytics|Pages"
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Previous month"
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Referer"
|
||||
msgstr ""
|
||||
|
||||
@ -5638,6 +5647,9 @@ msgstr ""
|
||||
msgid "Analytics|Something went wrong while loading available visualizations. Refresh the page to try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Something went wrong while loading product analytics usage data. Refresh the page to try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Something went wrong while loading the dashboard. Refresh the page to try again or see %{linkStart}troubleshooting documentation%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
@ -5653,6 +5665,12 @@ msgstr ""
|
||||
msgid "Analytics|Target URL"
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|This group has no projects with product analytics onboarded in the current or previous month."
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|This table excludes projects that do not have product analytics onboarded."
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|To create your own dashboards, first configure a project to store your dashboards."
|
||||
msgstr ""
|
||||
|
||||
@ -5665,6 +5683,9 @@ msgstr ""
|
||||
msgid "Analytics|Updating visualization %{visualizationName}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Usage by project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Analytics|Use the visualization designer to create custom visualizations. After you save a visualization, you can add it to a dashboard."
|
||||
msgstr ""
|
||||
|
||||
@ -55202,6 +55223,9 @@ msgstr[1] ""
|
||||
msgid "YouTube"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your %{changes_link} have been committed successfully."
|
||||
msgstr ""
|
||||
|
||||
msgid "Your %{group} membership will now expire in %{days}."
|
||||
msgstr ""
|
||||
|
||||
@ -55901,6 +55925,9 @@ msgid_plural "changes"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "changes"
|
||||
msgstr ""
|
||||
|
||||
msgid "check"
|
||||
msgid_plural "checks"
|
||||
msgstr[0] ""
|
||||
|
@ -25,7 +25,7 @@ module QA
|
||||
|
||||
Page::File::Show.perform do |file|
|
||||
aggregate_failures 'file details' do
|
||||
expect(file).to have_notice('Your changes have been successfully committed.')
|
||||
expect(file).to have_notice('Your changes have been committed successfully.')
|
||||
expect(file).to have_file_content(updated_file_content)
|
||||
expect(file).to have_commit_message(commit_message_for_update)
|
||||
end
|
||||
|
@ -21,6 +21,7 @@ sed -i 's|url:.*$|url: redis://redis:6379|g' config/resque.yml
|
||||
if [[ "$USE_REDIS_CLUSTER" != "false" ]] && [[ "$SETUP_DB" != "false" ]]; then
|
||||
cp config/redis.yml.example config/redis.yml
|
||||
sed -i 's|- .*$|- redis://rediscluster:7001|g' config/redis.yml
|
||||
sed -i 's|url:.*$|url: redis://redis:6379|g' config/redis.yml
|
||||
fi
|
||||
|
||||
setup_database_yml
|
||||
|
@ -50,7 +50,10 @@ RSpec.describe 'a maintainer edits files on a source-branch of an MR from a fork
|
||||
click_button 'Commit changes'
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_content('Your changes have been successfully committed')
|
||||
expect(page).to have_content('Your changes have been committed successfully')
|
||||
page.within '.flash-container' do
|
||||
expect(page).to have_link 'changes'
|
||||
end
|
||||
expect(page).to have_content(content)
|
||||
end
|
||||
end
|
||||
|
@ -120,7 +120,7 @@ RSpec.describe 'Editing file blob', :js, feature_category: :groups_and_projects
|
||||
it 'updates content' do
|
||||
edit_and_commit
|
||||
|
||||
expect(page).to have_content 'successfully committed'
|
||||
expect(page).to have_content 'committed successfully.'
|
||||
expect(page).to have_content 'NextFeature'
|
||||
end
|
||||
|
||||
|
@ -79,6 +79,25 @@ RSpec.describe 'Projects > Files > User edits files', :js, feature_category: :gr
|
||||
expect(page).to have_content('*.rbca')
|
||||
end
|
||||
|
||||
it 'displays a flash message with a link when an edited file was committed' do
|
||||
click_link('.gitignore')
|
||||
edit_in_single_file_editor
|
||||
find('.file-editor', match: :first)
|
||||
|
||||
editor_set_value('*.rbca')
|
||||
fill_in(:commit_message, with: 'New commit message', visible: true)
|
||||
click_button('Commit changes')
|
||||
|
||||
expect(page).to have_current_path(project_blob_path(project, 'master/.gitignore'), ignore_query: true)
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_content('Your changes have been committed successfully')
|
||||
page.within '.flash-container' do
|
||||
expect(page).to have_link 'changes'
|
||||
end
|
||||
end
|
||||
|
||||
it 'commits an edited file to a new branch' do
|
||||
click_link('.gitignore')
|
||||
edit_in_single_file_editor
|
||||
|
@ -9,7 +9,8 @@ import { isLoggedIn } from '~/lib/utils/common_utils';
|
||||
import AwardList from '~/vue_shared/components/awards_list.vue';
|
||||
import WorkItemAwardEmoji from '~/work_items/components/work_item_award_emoji.vue';
|
||||
import updateAwardEmojiMutation from '~/work_items/graphql/update_award_emoji.mutation.graphql';
|
||||
import workItemAwardEmojiQuery from '~/work_items/graphql/award_emoji.query.graphql';
|
||||
import groupWorkItemAwardEmojiQuery from '~/work_items/graphql/group_award_emoji.query.graphql';
|
||||
import projectWorkItemAwardEmojiQuery from '~/work_items/graphql/award_emoji.query.graphql';
|
||||
import {
|
||||
EMOJI_THUMBSUP,
|
||||
EMOJI_THUMBSDOWN,
|
||||
@ -42,6 +43,7 @@ describe('WorkItemAwardEmoji component', () => {
|
||||
const workItemQueryResponse = workItemByIidResponseFactory();
|
||||
const mockWorkItem = workItemQueryResponse.data.workspace.workItems.nodes[0];
|
||||
|
||||
const groupAwardEmojiQuerySuccessHandler = jest.fn().mockResolvedValue(workItemQueryResponse);
|
||||
const awardEmojiQuerySuccessHandler = jest.fn().mockResolvedValue(workItemQueryResponse);
|
||||
const awardEmojiQueryEmptyHandler = jest.fn().mockResolvedValue(
|
||||
workItemByIidResponseFactory({
|
||||
@ -83,10 +85,12 @@ describe('WorkItemAwardEmoji component', () => {
|
||||
awardEmojiQueryHandler = awardEmojiQuerySuccessHandler,
|
||||
awardEmojiMutationHandler = awardEmojiAddSuccessHandler,
|
||||
workItemIid = '1',
|
||||
isGroup = false,
|
||||
} = {}) => {
|
||||
mockApolloProvider = createMockApollo(
|
||||
[
|
||||
[workItemAwardEmojiQuery, awardEmojiQueryHandler],
|
||||
[projectWorkItemAwardEmojiQuery, awardEmojiQueryHandler],
|
||||
[groupWorkItemAwardEmojiQuery, groupAwardEmojiQuerySuccessHandler],
|
||||
[updateAwardEmojiMutation, awardEmojiMutationHandler],
|
||||
],
|
||||
{},
|
||||
@ -108,6 +112,9 @@ describe('WorkItemAwardEmoji component', () => {
|
||||
wrapper = shallowMount(WorkItemAwardEmoji, {
|
||||
isLoggedIn: isLoggedIn(),
|
||||
apolloProvider: mockApolloProvider,
|
||||
provide: {
|
||||
isGroup,
|
||||
},
|
||||
propsData: {
|
||||
workItemId: 'gid://gitlab/WorkItem/1',
|
||||
workItemFullpath: 'test-project-path',
|
||||
@ -270,7 +277,7 @@ describe('WorkItemAwardEmoji component', () => {
|
||||
};
|
||||
});
|
||||
|
||||
it('calls mutation succesfully and adds the award emoji with proper user details', async () => {
|
||||
it('calls mutation successfully and adds the award emoji with proper user details', async () => {
|
||||
createComponent({
|
||||
awardEmojiMutationHandler: awardEmojiAddSuccessHandler,
|
||||
});
|
||||
@ -345,4 +352,18 @@ describe('WorkItemAwardEmoji component', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('group award emoji query', () => {
|
||||
it('is not called in a project context', () => {
|
||||
createComponent();
|
||||
|
||||
expect(groupAwardEmojiQuerySuccessHandler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('is called in a group context', () => {
|
||||
createComponent({ isGroup: true });
|
||||
|
||||
expect(groupAwardEmojiQuerySuccessHandler).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,59 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ViteHelper, feature_category: :tooling do
|
||||
let(:source) { 'foo.js' }
|
||||
let(:vite_source) { 'vite/foo.js' }
|
||||
let(:vite_tag) { '<tag src="vite/foo"></tag>' }
|
||||
let(:webpack_source) { 'webpack/foo.js' }
|
||||
let(:webpack_tag) { '<tag src="webpack/foo"></tag>' }
|
||||
|
||||
context 'when vite enabled' do
|
||||
before do
|
||||
stub_rails_env('development')
|
||||
stub_feature_flags(vite: true)
|
||||
|
||||
allow(helper).to receive(:vite_javascript_tag).and_return(vite_tag)
|
||||
allow(helper).to receive(:vite_asset_path).and_return(vite_source)
|
||||
allow(helper).to receive(:vite_stylesheet_tag).and_return(vite_tag)
|
||||
allow(helper).to receive(:vite_asset_url).and_return(vite_source)
|
||||
allow(helper).to receive(:vite_running).and_return(true)
|
||||
end
|
||||
|
||||
describe '#universal_javascript_include_tag' do
|
||||
it 'returns vite javascript tag' do
|
||||
expect(helper.universal_javascript_include_tag(source)).to eq(vite_tag)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#universal_asset_path' do
|
||||
it 'returns vite asset path' do
|
||||
expect(helper.universal_asset_path(source)).to eq(vite_source)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when vite disabled' do
|
||||
before do
|
||||
stub_feature_flags(vite: false)
|
||||
|
||||
allow(helper).to receive(:javascript_include_tag).and_return(webpack_tag)
|
||||
allow(helper).to receive(:asset_path).and_return(webpack_source)
|
||||
allow(helper).to receive(:stylesheet_link_tag).and_return(webpack_tag)
|
||||
allow(helper).to receive(:path_to_stylesheet).and_return(webpack_source)
|
||||
end
|
||||
|
||||
describe '#universal_javascript_include_tag' do
|
||||
it 'returns webpack javascript tag' do
|
||||
expect(helper.universal_javascript_include_tag(source)).to eq(webpack_tag)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#universal_asset_path' do
|
||||
it 'returns ActionView asset path' do
|
||||
expect(helper.universal_asset_path(source)).to eq(webpack_source)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -22,7 +22,9 @@ RSpec.describe 'cross-database foreign keys' do
|
||||
'merge_requests.updated_by_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
|
||||
'merge_requests.merge_user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
|
||||
'merge_requests.author_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
|
||||
'path_locks.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429380
|
||||
'project_authorizations.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422044
|
||||
'security_orchestration_policy_configurations.bot_user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429438
|
||||
'user_group_callouts.user_id' # https://gitlab.com/gitlab-org/gitlab/-/issues/421287
|
||||
]
|
||||
end
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::LabelFinder, :clean_gitlab_redis_cache do
|
||||
RSpec.describe Gitlab::GithubImport::LabelFinder, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:finder) { described_class.new(project) }
|
||||
let_it_be(:bug) { create(:label, project: project, name: 'Bug') }
|
||||
@ -18,23 +18,64 @@ RSpec.describe Gitlab::GithubImport::LabelFinder, :clean_gitlab_redis_cache do
|
||||
expect(finder.id_for(feature.name)).to eq(feature.id)
|
||||
end
|
||||
|
||||
it 'returns nil for an empty cache key' do
|
||||
it 'fetches object id from database if not in cache' do
|
||||
key = finder.cache_key_for(bug.name)
|
||||
|
||||
Gitlab::Cache::Import::Caching.write(key, '')
|
||||
|
||||
expect(finder.id_for(bug.name)).to be_nil
|
||||
expect(finder.id_for(bug.name)).to eq(bug.id)
|
||||
end
|
||||
|
||||
it 'returns nil for a non existing label name' do
|
||||
expect(finder.id_for('kittens')).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil and skips database read if cache has no record' do
|
||||
key = finder.cache_key_for(bug.name)
|
||||
|
||||
Gitlab::Cache::Import::Caching.write(key, -1)
|
||||
|
||||
expect(finder.id_for(bug.name)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'without a cache in place' do
|
||||
it 'returns nil for a label' do
|
||||
it 'caches the ID of a database row and returns the ID' do
|
||||
expect(Gitlab::Cache::Import::Caching)
|
||||
.to receive(:write)
|
||||
.with("github-import/label-finder/#{project.id}/#{feature.name}", feature.id)
|
||||
.and_call_original
|
||||
|
||||
expect(finder.id_for(feature.name)).to eq(feature.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with FF import_fallback_to_db_empty_cache disabled' do
|
||||
before do
|
||||
stub_feature_flags(import_fallback_to_db_empty_cache: false)
|
||||
end
|
||||
|
||||
it 'returns nil for a non existing label name' do
|
||||
expect(finder.id_for('kittens')).to be_nil
|
||||
end
|
||||
|
||||
it 'does not fetch object id from database if not in cache' do
|
||||
expect(finder.id_for(feature.name)).to be_nil
|
||||
end
|
||||
|
||||
it 'fetches object id from cache if present' do
|
||||
finder.build_cache
|
||||
|
||||
expect(finder.id_for(feature.name)).to eq(feature.id)
|
||||
end
|
||||
|
||||
it 'returns -1 if cache is -1' do
|
||||
key = finder.cache_key_for(bug.name)
|
||||
|
||||
Gitlab::Cache::Import::Caching.write(key, -1)
|
||||
|
||||
expect(finder.id_for(bug.name)).to eq(-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1061,6 +1061,7 @@ approval_rules:
|
||||
- users
|
||||
- groups
|
||||
- group_users
|
||||
- group_members
|
||||
- security_orchestration_policy_configuration
|
||||
- protected_branches
|
||||
- approval_merge_request_rule_sources
|
||||
|
@ -7,6 +7,7 @@ require 'support/helpers/rails_helpers'
|
||||
RSpec.describe Gitlab::InstrumentationHelper, :clean_gitlab_redis_repository_cache, :clean_gitlab_redis_cache,
|
||||
:use_null_store_as_repository_cache, feature_category: :scalability do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
include RedisHelpers
|
||||
|
||||
describe '.add_instrumentation_data', :request_store do
|
||||
let(:payload) { {} }
|
||||
@ -39,11 +40,18 @@ RSpec.describe Gitlab::InstrumentationHelper, :clean_gitlab_redis_repository_cac
|
||||
end
|
||||
|
||||
context 'when Redis calls are made' do
|
||||
let_it_be(:redis_store_class) { define_helper_redis_store_class }
|
||||
|
||||
before do # init redis connection with `test` env details
|
||||
redis_store_class.with(&:ping)
|
||||
RequestStore.clear!
|
||||
end
|
||||
|
||||
it 'adds Redis data and omits Gitaly data' do
|
||||
stub_rails_env('staging') # to avoid raising CrossSlotError
|
||||
Gitlab::Redis::Sessions.with { |redis| redis.mset('test-cache', 123, 'test-cache2', 123) }
|
||||
redis_store_class.with { |redis| redis.mset('test-cache', 123, 'test-cache2', 123) }
|
||||
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
|
||||
Gitlab::Redis::Sessions.with { |redis| redis.mget('cache-test', 'cache-test-2') }
|
||||
redis_store_class.with { |redis| redis.mget('cache-test', 'cache-test-2') }
|
||||
end
|
||||
Gitlab::Redis::Queues.with { |redis| redis.set('test-queues', 321) }
|
||||
|
||||
|
@ -231,8 +231,16 @@ RSpec.describe Gitlab::Issues::Rebalancing::State, :clean_gitlab_redis_shared_st
|
||||
|
||||
def check_existing_keys
|
||||
index = 0
|
||||
# spec only, we do not actually scan keys in the code
|
||||
recently_finished_keys_count = Gitlab::Redis::SharedState.with { |redis| redis.scan(0, match: "#{described_class::RECENTLY_FINISHED_REBALANCE_PREFIX}:*") }.last.count
|
||||
cursor = '0'
|
||||
recently_finished_keys_count = 0
|
||||
|
||||
# loop to scan since it may run against a Redis Cluster
|
||||
loop do
|
||||
# spec only, we do not actually scan keys in the code
|
||||
cursor, items = Gitlab::Redis::SharedState.with { |redis| redis.scan(cursor, match: "#{described_class::RECENTLY_FINISHED_REBALANCE_PREFIX}:*") }
|
||||
recently_finished_keys_count += items.count
|
||||
break if cursor == '0'
|
||||
end
|
||||
|
||||
index += 1 if rebalance_caching.get_current_index > 0
|
||||
index += 1 if rebalance_caching.get_current_project_id.present?
|
||||
|
@ -1059,7 +1059,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
|
||||
end
|
||||
|
||||
def value_in_queues
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
Gitlab::Redis::Workhorse.with do |redis|
|
||||
runner_queue_key = runner.send(:runner_queue_key)
|
||||
redis.get(runner_queue_key)
|
||||
end
|
||||
|
Reference in New Issue
Block a user