Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot
2023-10-26 18:11:56 +00:00
parent 5ef8690cb9
commit ea413f31cf
53 changed files with 535 additions and 233 deletions

View File

@ -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

View File

@ -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]

View File

@ -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'

View File

@ -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

View File

@ -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"},

View File

@ -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)

View File

@ -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

View File

@ -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" />

View File

@ -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>

View File

@ -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,

View File

@ -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) {

View File

@ -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
}
}
}
}
}
}
}
}

View File

@ -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 {

View File

@ -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] =

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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).

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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).

View File

@ -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:

View 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 links href attribute. The event also has fields for the links 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).

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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] ""

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
});
});
});

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1061,6 +1061,7 @@ approval_rules:
- users
- groups
- group_users
- group_members
- security_orchestration_policy_configuration
- protected_branches
- approval_merge_request_rule_sources

View File

@ -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) }

View File

@ -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?

View File

@ -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