Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-03-03 18:16:36 +00:00
parent 98ba44db4f
commit dc1018cb5d
136 changed files with 1536 additions and 511 deletions

View File

@ -835,11 +835,6 @@ rspec-ee unit pg14:
- .rspec-ee-unit-parallel
- .rails:rules:ee-only-unit
rspec-ee unit pg14 es8:
extends:
- .rspec-ee-base-pg14-es8
- .rspec-ee-unit-parallel
rspec-ee unit pg14 single-db:
extends:
- rspec-ee unit pg14
@ -874,11 +869,6 @@ rspec-ee integration pg14:
- .rspec-ee-integration-parallel
- .rails:rules:ee-only-integration
rspec-ee integration pg14 es8:
extends:
- .rspec-ee-base-pg14-es8
- .rspec-ee-integration-parallel
rspec-ee integration pg14 single-db:
extends:
- rspec-ee integration pg14
@ -928,11 +918,6 @@ rspec-ee system pg14:
- .rspec-ee-system-parallel
- .rails:rules:ee-only-system
rspec-ee system pg14 es8:
extends:
- .rspec-ee-base-pg14-es8
- .rspec-ee-system-parallel
rspec-ee system pg14 single-db:
extends:
- rspec-ee system pg14
@ -1038,80 +1023,7 @@ rspec system pg16:
#####################################
# EE: default branch nightly scheduled jobs #
# PG14
rspec-ee unit pg14 opensearch1:
extends:
- .rspec-ee-base-pg14-opensearch1
- .rspec-ee-unit-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee unit pg14 opensearch2:
extends:
- .rspec-ee-base-pg14-opensearch2
- .rspec-ee-unit-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee integration pg14 opensearch1:
extends:
- .rspec-ee-base-pg14-opensearch1
- .rspec-ee-integration-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee integration pg14 opensearch2:
extends:
- .rspec-ee-base-pg14-opensearch2
- .rspec-ee-integration-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg14 opensearch1:
extends:
- .rspec-ee-base-pg14-opensearch1
- .rspec-ee-system-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg14 opensearch2:
extends:
- .rspec-ee-base-pg14-opensearch2
- .rspec-ee-system-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# PG15
rspec-ee unit pg15 opensearch1:
extends:
- .rspec-ee-base-pg15-opensearch1
- .rspec-ee-unit-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee unit pg15 opensearch2:
extends:
- .rspec-ee-base-pg15-opensearch2
- .rspec-ee-unit-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee integration pg15 opensearch1:
extends:
- .rspec-ee-base-pg15-opensearch1
- .rspec-ee-integration-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee integration pg15 opensearch2:
extends:
- .rspec-ee-base-pg15-opensearch2
- .rspec-ee-integration-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg15 opensearch1:
extends:
- .rspec-ee-base-pg15-opensearch1
- .rspec-ee-system-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg15 opensearch2:
extends:
- .rspec-ee-base-pg15-opensearch2
- .rspec-ee-system-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee migration pg15:
extends:
- .rspec-ee-base-pg15
@ -1132,33 +1044,18 @@ rspec-ee unit pg15:
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-unit-parallel
rspec-ee unit pg15 es8:
extends:
- .rspec-ee-base-pg15-es8
- .rspec-ee-unit-parallel
rspec-ee integration pg15:
extends:
- .rspec-ee-base-pg15
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-integration-parallel
rspec-ee integration pg15 es8:
extends:
- .rspec-ee-base-pg15-es8
- .rspec-ee-integration-parallel
rspec-ee system pg15:
extends:
- .rspec-ee-base-pg15
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-system-parallel
rspec-ee system pg15 es8:
extends:
- .rspec-ee-base-pg15-es8
- .rspec-ee-system-parallel
# PG16
rspec-ee migration pg16:
extends:
@ -1192,62 +1089,61 @@ rspec-ee system pg16:
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-system-parallel
# We have too many jobs in nightly pipeline, more than 2k+,
# which exceeds the limit of jobs a pipeline can have. Disable below for now.
#
# rspec-ee unit pg16 opensearch1:
# extends:
# - .rspec-ee-base-pg16-opensearch1
# - .rspec-ee-unit-parallel
# - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# Integration tests with Elastic Search and the actual PG production version (PG16)
# https://gitlab.com/gitlab-org/quality/engineering-productivity/team/-/issues/534
rspec-ee unit pg16 opensearch1:
extends:
- .rspec-ee-base-pg16-opensearch1
- .rspec-ee-unit-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# rspec-ee unit pg16 opensearch2:
# extends:
# - .rspec-ee-base-pg16-opensearch2
# - .rspec-ee-unit-parallel
# - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee unit pg16 opensearch2:
extends:
- .rspec-ee-base-pg16-opensearch2
- .rspec-ee-unit-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# rspec-ee integration pg16 opensearch1:
# extends:
# - .rspec-ee-base-pg16-opensearch1
# - .rspec-ee-integration-parallel
# - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee integration pg16 opensearch1:
extends:
- .rspec-ee-base-pg16-opensearch1
- .rspec-ee-integration-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# rspec-ee integration pg16 opensearch2:
# extends:
# - .rspec-ee-base-pg16-opensearch2
# - .rspec-ee-integration-parallel
# - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee integration pg16 opensearch2:
extends:
- .rspec-ee-base-pg16-opensearch2
- .rspec-ee-integration-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# rspec-ee system pg16 opensearch1:
# extends:
# - .rspec-ee-base-pg16-opensearch1
# - .rspec-ee-system-parallel
# - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg16 opensearch1:
extends:
- .rspec-ee-base-pg16-opensearch1
- .rspec-ee-system-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# rspec-ee system pg16 opensearch2:
# extends:
# - .rspec-ee-base-pg16-opensearch2
# - .rspec-ee-system-parallel
# - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg16 opensearch2:
extends:
- .rspec-ee-base-pg16-opensearch2
- .rspec-ee-system-parallel
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# rspec-ee unit pg16 es8:
# extends:
# - .rspec-ee-base-pg16-es8
# - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# - .rspec-ee-unit-parallel
rspec-ee unit pg16 es8:
extends:
- .rspec-ee-base-pg16-es8
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-unit-parallel
# rspec-ee integration pg16 es8:
# extends:
# - .rspec-ee-base-pg16-es8
# - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# - .rspec-ee-integration-parallel
rspec-ee integration pg16 es8:
extends:
- .rspec-ee-base-pg16-es8
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-integration-parallel
# rspec-ee system pg16 es8:
# extends:
# - .rspec-ee-base-pg16-es8
# - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# - .rspec-ee-system-parallel
rspec-ee system pg16 es8:
extends:
- .rspec-ee-base-pg16-es8
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-system-parallel
# EE: default branch nightly scheduled jobs #
#####################################

View File

@ -243,47 +243,11 @@ include:
- .rspec-base
- .use-pg14-es7-ee
.rspec-ee-base-pg14-es8:
extends:
- .rspec-base
- .use-pg14-es8-ee
- .rails:rules:run-search-tests
.rspec-ee-base-pg14-opensearch1:
extends:
- .rspec-base
- .use-pg14-opensearch1-ee
- .rails:rules:run-search-tests
.rspec-ee-base-pg14-opensearch2:
extends:
- .rspec-base
- .use-pg14-opensearch2-ee
- .rails:rules:run-search-tests
.rspec-ee-base-pg15:
extends:
- .rspec-base
- .use-pg15-es7-ee
.rspec-ee-base-pg15-es8:
extends:
- .rspec-base
- .use-pg15-es8-ee
- .rails:rules:run-search-tests
.rspec-ee-base-pg15-opensearch1:
extends:
- .rspec-base
- .use-pg15-opensearch1-ee
- .rails:rules:run-search-tests
.rspec-ee-base-pg15-opensearch2:
extends:
- .rspec-base
- .use-pg15-opensearch2-ee
- .rails:rules:run-search-tests
.rspec-ee-base-pg16:
extends:
- .rspec-base

View File

@ -9,7 +9,6 @@ Layout/EmptyLinesAroundMethodBody:
- 'app/models/repository.rb'
- 'app/services/members/destroy_service.rb'
- 'ee/app/models/software_license.rb'
- 'ee/lib/gitlab/elastic/helper.rb'
- 'ee/spec/support/helpers/identity_verification_helpers.rb'
- 'lib/api/helpers/packages_helpers.rb'
- 'lib/gitlab/background_migration/batched_migration_job.rb'

View File

@ -195,7 +195,6 @@ Style/RedundantSelf:
- 'ee/lib/gitlab/auth/smartcard.rb'
- 'ee/lib/gitlab/ci/reports/license_scanning/report.rb'
- 'ee/lib/gitlab/elastic/client.rb'
- 'ee/lib/gitlab/elastic/helper.rb'
- 'ee/lib/gitlab/geo.rb'
- 'ee/lib/gitlab/geo/oauth/login_state.rb'
- 'ee/lib/gitlab/geo/oauth/logout_state.rb'

View File

@ -698,8 +698,8 @@ gem 'valid_email', '~> 0.1', feature_category: :shared
gem 'jsonb_accessor', '~> 1.4', feature_category: :shared
gem 'json', '~> 2.10.0', feature_category: :shared
gem 'json_schemer', '~> 2.3.0', feature_category: :shared
gem 'oj', '~> 3.13.21', feature_category: :shared
gem 'oj-introspect', '~> 0.7', feature_category: :shared
gem 'oj', '~> 3.16.0', '>=3.16.10', feature_category: :shared
gem 'oj-introspect', '~> 0.8', feature_category: :shared
gem 'multi_json', '~> 1.14.1', feature_category: :shared
gem 'yajl-ruby', '~> 1.4.3', require: 'yajl', feature_category: :shared

View File

@ -447,8 +447,8 @@
{"name":"oauth2","version":"2.0.9","platform":"ruby","checksum":"b21f9defcf52dc1610e0dfab4c868342173dcd707fd15c777d9f4f04e153f7fb"},
{"name":"octokit","version":"9.2.0","platform":"ruby","checksum":"4fa47ff35ce654127edf2c836ab9269bcc8829f5542dc1e86871f697ce7f4316"},
{"name":"ohai","version":"18.1.18","platform":"ruby","checksum":"42ee8196945cb935fdeec93ba7aaee757d1d552f7b933912a1f25863c3cc1ff0"},
{"name":"oj","version":"3.13.23","platform":"ruby","checksum":"206dfdc4020ad9974705037f269cfba211d61b7662a58c717cce771829ccef51"},
{"name":"oj-introspect","version":"0.7.2","platform":"ruby","checksum":"c415a44567ed2870d8e963a69421d9322128e194fab7867e37e54d5a25d5333d"},
{"name":"oj","version":"3.16.10","platform":"ruby","checksum":"7f26bed974e331e16d579b470b0865010757f6fe6ee30ea9b67df653fbe13d7c"},
{"name":"oj-introspect","version":"0.8.0","platform":"ruby","checksum":"5cbb15309d60294881e5c2f65ceb22e3b5798f26d0a1e65ae47a6342b87d9264"},
{"name":"omniauth","version":"2.1.2","platform":"ruby","checksum":"def03277298b8f8a5d3ff16cdb2eb5edb9bffed60ee7dda24cc0c89b3ae6a0ce"},
{"name":"omniauth-alicloud","version":"3.0.0","platform":"ruby","checksum":"9c5c4f3abb40d774b946015f177d503fbde99b2b57c0858284c25cc39369013e"},
{"name":"omniauth-atlassian-oauth2","version":"0.2.0","platform":"ruby","checksum":"eb07574a188ab8a03376ce288bce86bc2dd4a1382ffa5781cb5e2b7bc15d76c9"},
@ -709,7 +709,7 @@
{"name":"spring-commands-rspec","version":"1.0.4","platform":"ruby","checksum":"6202e54fa4767452e3641461a83347645af478bf45dddcca9737b43af0dd1a2c"},
{"name":"sprite-factory","version":"1.7.1","platform":"ruby","checksum":"5586524a1aec003241f1abc6852b61433e988aba5ee2b55f906387bf49b01ba2"},
{"name":"sprockets","version":"3.7.2","platform":"ruby","checksum":"5ea1d7facd09203c1aa196afd6178208cd25abdbcc2a9978810a2f0754e152a0"},
{"name":"sprockets-rails","version":"3.5.1","platform":"ruby","checksum":"c44626cb3887a1a8b572ca258685db33b4ebd041aa73428a716eac444ee5ef48"},
{"name":"sprockets-rails","version":"3.5.2","platform":"ruby","checksum":"a9e88e6ce9f8c912d349aa5401509165ec42326baf9e942a85de4b76dbc4119e"},
{"name":"ssh_data","version":"1.3.0","platform":"ruby","checksum":"ec7c1e95a3aebeee412147998f4c147b4b05da6ed0aafda6083f9449318eaac0"},
{"name":"ssrf_filter","version":"1.0.8","platform":"ruby","checksum":"03f49f54837e407d43ee93ec733a8a94dc1bcf8185647ac61606e63aaedaa0db"},
{"name":"stackprof","version":"0.2.27","platform":"ruby","checksum":"aff6d28656c852e74cf632cc2046f849033dc1dedffe7cb8c030d61b5745e80c"},

View File

@ -122,7 +122,7 @@ PATH
specs:
ipynbdiff (0.4.8)
diffy (~> 3.4)
oj (~> 3.13.16)
oj (~> 3.16, >= 3.16.10)
PATH
remote: vendor/gems/attr_encrypted
@ -1243,9 +1243,11 @@ GEM
plist (~> 3.1)
train-core
wmi-lite (~> 1.0)
oj (3.13.23)
oj-introspect (0.7.2)
oj (>= 3.13.23)
oj (3.16.10)
bigdecimal (>= 3.0)
ostruct (>= 0.2)
oj-introspect (0.8.0)
oj (>= 3.16.10)
omniauth (2.1.2)
hashie (>= 3.4.6)
rack (>= 2.2.3)
@ -1808,7 +1810,7 @@ GEM
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.5.1)
sprockets-rails (3.5.2)
actionpack (>= 6.1)
activesupport (>= 6.1)
sprockets (>= 3.0.0)
@ -2208,8 +2210,8 @@ DEPENDENCIES
oauth2 (~> 2.0)
octokit (~> 9.0)
ohai (~> 18.1)
oj (~> 3.13.21)
oj-introspect (~> 0.7)
oj (~> 3.16.0, >= 3.16.10)
oj-introspect (~> 0.8)
omniauth (~> 2.1.0)
omniauth-alicloud (~> 3.0.0)
omniauth-atlassian-oauth2 (~> 0.2.0)

View File

@ -450,8 +450,8 @@
{"name":"oauth2","version":"2.0.9","platform":"ruby","checksum":"b21f9defcf52dc1610e0dfab4c868342173dcd707fd15c777d9f4f04e153f7fb"},
{"name":"octokit","version":"9.2.0","platform":"ruby","checksum":"4fa47ff35ce654127edf2c836ab9269bcc8829f5542dc1e86871f697ce7f4316"},
{"name":"ohai","version":"18.1.18","platform":"ruby","checksum":"42ee8196945cb935fdeec93ba7aaee757d1d552f7b933912a1f25863c3cc1ff0"},
{"name":"oj","version":"3.13.23","platform":"ruby","checksum":"206dfdc4020ad9974705037f269cfba211d61b7662a58c717cce771829ccef51"},
{"name":"oj-introspect","version":"0.7.2","platform":"ruby","checksum":"c415a44567ed2870d8e963a69421d9322128e194fab7867e37e54d5a25d5333d"},
{"name":"oj","version":"3.16.10","platform":"ruby","checksum":"7f26bed974e331e16d579b470b0865010757f6fe6ee30ea9b67df653fbe13d7c"},
{"name":"oj-introspect","version":"0.8.0","platform":"ruby","checksum":"5cbb15309d60294881e5c2f65ceb22e3b5798f26d0a1e65ae47a6342b87d9264"},
{"name":"omniauth","version":"2.1.2","platform":"ruby","checksum":"def03277298b8f8a5d3ff16cdb2eb5edb9bffed60ee7dda24cc0c89b3ae6a0ce"},
{"name":"omniauth-alicloud","version":"3.0.0","platform":"ruby","checksum":"9c5c4f3abb40d774b946015f177d503fbde99b2b57c0858284c25cc39369013e"},
{"name":"omniauth-atlassian-oauth2","version":"0.2.0","platform":"ruby","checksum":"eb07574a188ab8a03376ce288bce86bc2dd4a1382ffa5781cb5e2b7bc15d76c9"},
@ -720,7 +720,7 @@
{"name":"spring-commands-rspec","version":"1.0.4","platform":"ruby","checksum":"6202e54fa4767452e3641461a83347645af478bf45dddcca9737b43af0dd1a2c"},
{"name":"sprite-factory","version":"1.7.1","platform":"ruby","checksum":"5586524a1aec003241f1abc6852b61433e988aba5ee2b55f906387bf49b01ba2"},
{"name":"sprockets","version":"3.7.2","platform":"ruby","checksum":"5ea1d7facd09203c1aa196afd6178208cd25abdbcc2a9978810a2f0754e152a0"},
{"name":"sprockets-rails","version":"3.5.1","platform":"ruby","checksum":"c44626cb3887a1a8b572ca258685db33b4ebd041aa73428a716eac444ee5ef48"},
{"name":"sprockets-rails","version":"3.5.2","platform":"ruby","checksum":"a9e88e6ce9f8c912d349aa5401509165ec42326baf9e942a85de4b76dbc4119e"},
{"name":"ssh_data","version":"1.3.0","platform":"ruby","checksum":"ec7c1e95a3aebeee412147998f4c147b4b05da6ed0aafda6083f9449318eaac0"},
{"name":"ssrf_filter","version":"1.0.8","platform":"ruby","checksum":"03f49f54837e407d43ee93ec733a8a94dc1bcf8185647ac61606e63aaedaa0db"},
{"name":"stackprof","version":"0.2.27","platform":"ruby","checksum":"aff6d28656c852e74cf632cc2046f849033dc1dedffe7cb8c030d61b5745e80c"},

View File

@ -122,7 +122,7 @@ PATH
specs:
ipynbdiff (0.4.8)
diffy (~> 3.4)
oj (~> 3.13.16)
oj (~> 3.16, >= 3.16.10)
PATH
remote: vendor/gems/attr_encrypted
@ -1260,9 +1260,11 @@ GEM
plist (~> 3.1)
train-core
wmi-lite (~> 1.0)
oj (3.13.23)
oj-introspect (0.7.2)
oj (>= 3.13.23)
oj (3.16.10)
bigdecimal (>= 3.0)
ostruct (>= 0.2)
oj-introspect (0.8.0)
oj (>= 3.16.10)
omniauth (2.1.2)
hashie (>= 3.4.6)
rack (>= 2.2.3)
@ -1841,7 +1843,7 @@ GEM
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.5.1)
sprockets-rails (3.5.2)
actionpack (>= 6.1)
activesupport (>= 6.1)
sprockets (>= 3.0.0)
@ -2243,8 +2245,8 @@ DEPENDENCIES
oauth2 (~> 2.0)
octokit (~> 9.0)
ohai (~> 18.1)
oj (~> 3.13.21)
oj-introspect (~> 0.7)
oj (~> 3.16.0, >= 3.16.10)
oj-introspect (~> 0.8)
omniauth (~> 2.1.0)
omniauth-alicloud (~> 3.0.0)
omniauth-atlassian-oauth2 (~> 0.2.0)

View File

@ -6,6 +6,8 @@ import {
SCHEDULE_SOURCE,
MERGE_TRAIN_EVENT_TYPE,
MERGED_RESULT_EVENT_TYPE,
PIPELINE_TYPE_BRANCH,
PIPELINE_TYPE_TAG,
} from '../constants';
export default {
@ -37,6 +39,12 @@ export default {
isMergedResultsPipeline() {
return this.mergeRequestEventType === MERGED_RESULT_EVENT_TYPE;
},
isBranchPipeline() {
return this.pipeline.type === PIPELINE_TYPE_BRANCH;
},
isTagPipeline() {
return this.pipeline.type === PIPELINE_TYPE_TAG;
},
isDetachedPipeline() {
return this.mergeRequestEventType === DETACHED_EVENT_TYPE;
},
@ -64,6 +72,8 @@ export default {
latest: this.pipeline.latest,
mergeTrainPipeline: this.isMergeTrainPipeline,
mergedResultsPipeline: this.isMergedResultsPipeline,
branchPipeline: this.isBranchPipeline,
tagPipeline: this.isTagPipeline,
detached: this.isDetachedPipeline,
failed: Boolean(this.failureReason),
autoDevops: this.isAutoDevopsPipeline,
@ -109,7 +119,7 @@ export default {
<gl-badge
v-if="badges.latest"
v-gl-tooltip
:title="__('Latest pipeline for the most recent commit on this branch')"
:title="__('Latest pipeline for the most recent commit on this ref')"
variant="success"
>
{{ s__('Pipelines|latest') }}
@ -166,6 +176,22 @@ export default {
>
{{ s__('Pipelines|merged results') }}
</gl-badge>
<gl-badge
v-if="badges.branchPipeline"
v-gl-tooltip
:title="s__('Pipelines|This pipeline ran for a branch.')"
variant="info"
>
{{ s__('Pipelines|branch') }}
</gl-badge>
<gl-badge
v-if="badges.tagPipeline"
v-gl-tooltip
:title="s__('Pipelines|This pipeline ran for a tag.')"
variant="info"
>
{{ s__('Pipelines|tag') }}
</gl-badge>
<gl-badge
v-if="badges.stuck"
v-gl-tooltip

View File

@ -5,3 +5,5 @@ export const AUTO_DEVOPS_SOURCE = 'AUTO_DEVOPS_SOURCE';
export const DETACHED_EVENT_TYPE = 'DETACHED';
export const MERGED_RESULT_EVENT_TYPE = 'MERGED_RESULT';
export const MERGE_TRAIN_EVENT_TYPE = 'MERGE_TRAIN';
export const PIPELINE_TYPE_BRANCH = 'branch';
export const PIPELINE_TYPE_TAG = 'tag';

View File

@ -52,6 +52,7 @@ query getPipelineHeaderData($fullPath: ID!, $iid: ID!) {
name
totalJobs
refText
type
triggeredByPath
stuck
child

View File

@ -41,6 +41,12 @@ export default {
this.pipeline.flags.merged_result_pipeline && !this.pipeline.flags.merge_train_pipeline
);
},
showBranchBadge() {
return this.pipeline.flags.type === 'branch';
},
showTagBadge() {
return this.pipeline.flags.type === 'tag';
},
autoDevopsTagId() {
return `pipeline-url-autodevops-${this.pipeline.id}`;
},
@ -76,7 +82,7 @@ export default {
<gl-badge
v-if="pipeline.flags.latest"
v-gl-tooltip
:title="__('Latest pipeline for the most recent commit on this branch')"
:title="__('Latest pipeline for the most recent commit on this ref')"
variant="success"
data-testid="pipeline-url-latest"
>{{ __('latest') }}</gl-badge
@ -149,6 +155,22 @@ export default {
<gl-badge v-if="pipeline.flags.stuck" variant="warning" data-testid="pipeline-url-stuck">{{
__('stuck')
}}</gl-badge>
<gl-badge
v-if="showTagBadge"
v-gl-tooltip
:title="s__(`Pipeline|This pipeline ran for a tag.`)"
variant="info"
data-testid="pipeline-url-tag"
>{{ s__('Pipeline|tag') }}</gl-badge
>
<gl-badge
v-if="showBranchBadge"
v-gl-tooltip
:title="s__(`Pipeline|This pipeline ran for a branch.`)"
variant="info"
data-testid="pipeline-url-branch"
>{{ s__('Pipeline|branch') }}</gl-badge
>
<gl-badge
v-if="pipeline.flags.detached_merge_request_pipeline"
v-gl-tooltip

View File

@ -0,0 +1,4 @@
fragment TroubleshootJob on Pipeline {
# Overridden in EE
id
}

View File

@ -1,10 +1,12 @@
#import "ee_else_ce/ci/pipelines_page/graphql/fragments/troubleshoot_job.fragment.graphql"
query getPipelineFailedJobs($fullPath: ID!, $pipelineIid: ID!) {
project(fullPath: $fullPath) {
id
pipeline(iid: $pipelineIid) {
id
active
troubleshootJobWithAi
...TroubleshootJob
jobs(statuses: [FAILED], retried: false) {
count
nodes {

View File

@ -39,10 +39,10 @@ export default {
</script>
<template>
<div id="peek-view-add-request" class="view gl-flex">
<gl-form class="gl-flex gl-items-center" @submit.prevent="addRequest">
<gl-form class="gl-flex gl-items-center gl-gap-4" @submit.prevent="addRequest">
<gl-button
v-gl-tooltip.viewport
class="gl-mr-2"
class="!gl-text-neutral-0"
category="tertiary"
variant="link"
icon="plus"
@ -57,17 +57,16 @@ export default {
type="text"
:placeholder="$options.i18n.inputLabel"
:aria-label="$options.i18n.inputLabel"
class="gl-ml-2 !gl-px-3 !gl-py-2"
class="gl-w-20 !gl-bg-alpha-light-24 !gl-text-neutral-0 !gl-placeholder-neutral-0"
@keyup.esc="clearForm"
/>
<gl-button
v-gl-tooltip.viewport
class="gl-ml-2"
category="tertiary"
type="submit"
variant="link"
icon="file-addition-solid"
size="small"
class="!gl-text-neutral-0"
:aria-label="$options.i18n.submitLabel"
>
{{ $options.i18n.submitLabel }}

View File

@ -59,17 +59,24 @@ export default {
return this.currentRequest.details[this.metric];
},
metricDetailsSummary() {
const summary = {};
const summary = [];
if (!this.metricDetails.summaryOptions?.hideTotal) {
summary[__('Total')] = this.metricDetails.calls;
if (this.metricDetails.calls && !this.metricDetails.summaryOptions?.hideTotal) {
summary.push([__('Total'), this.metricDetails.calls]);
}
if (!this.metricDetails.summaryOptions?.hideDuration) {
summary[s__('PerformanceBar|Total duration')] = this.metricDetails.duration;
if (this.metricDetails.duration && !this.metricDetails.summaryOptions?.hideDuration) {
summary.push([s__('PerformanceBar|Total duration'), this.metricDetails.duration]);
}
return { ...summary, ...(this.metricDetails.summary || {}) };
for (const entry of Object.entries(this.metricDetails.summary ?? {})) {
// Filter out entries which have no value
if (entry[1]) {
summary.push(entry);
}
}
return summary;
},
metricDetailsLabel() {
if (this.metricDetails.duration && this.metricDetails.calls) {
@ -146,7 +153,7 @@ export default {
<gl-button
v-gl-tooltip.viewport
v-gl-modal="modalId"
class="gl-mr-2"
class="gl-mr-2 !gl-text-neutral-0"
:title="header"
variant="link"
>
@ -154,11 +161,19 @@ export default {
{{ metricDetailsLabel }}
</span>
</gl-button>
<gl-modal :modal-id="modalId" :title="header" size="lg" footer-class="!gl-hidden" scrollable>
<gl-modal
:modal-id="modalId"
:title="header"
size="lg"
scrollable
hide-backdrop
hide-footer
no-focus-on-show
>
<div class="gl-flex gl-items-center gl-justify-between">
<div class="gl-flex gl-items-center" data-testid="performance-bar-summary">
<div v-for="(value, name) in metricDetailsSummary" :key="name" class="gl-pr-8">
<div v-if="value" data-testid="performance-bar-summary-item">
<div class="gl-flex gl-items-center gl-gap-8" data-testid="performance-bar-summary">
<div v-for="[name, value] in metricDetailsSummary" :key="name">
<div data-testid="performance-bar-summary-item">
<div>{{ name }}</div>
<div class="gl-text-size-h1 gl-font-semibold">{{ value }}</div>
</div>

View File

@ -41,6 +41,7 @@ export default {
<div class="view gl-flex gl-gap-2">
<gl-button
icon="information-o"
class="!gl-text-neutral-0"
variant="link"
:aria-label="s__('PerformanceBar|Debugging information')"
@click="showInfoModal"
@ -52,12 +53,13 @@ export default {
size="sm"
hide-backdrop
hide-footer
no-focus-on-show
>
<div class="gl-pb-6">
<div class="gl-flex gl-flex-col gl-text-lg">
<strong class="gl-border-b gl-mb-4 gl-w-full gl-font-bold">
{{ s__('PerformanceBar|Host') }}</strong
>
<strong class="gl-border-b gl-mb-4 gl-w-full gl-font-bold gl-text-neutral-0">
{{ s__('PerformanceBar|Host') }}
</strong>
<div>
<gl-emoji data-testid="host-emoji" data-name="computer" />
<span>{{ hostInfo }} </span>

View File

@ -138,6 +138,18 @@ export default {
this.store.findRequest(this.currentRequestId).fullUrl,
);
},
backgroundClass() {
if (this.env === 'production') {
return 'gl-bg-neutral-950';
}
if (this.env === 'staging') {
return 'gl-bg-purple-950 dark:gl-bg-purple-50';
}
if (this.env === 'development') {
return 'gl-bg-red-900 dark:gl-bg-red-50';
}
return 'gl-bg-neutral-1000';
},
},
created() {
if (!this.showZoekt) {
@ -167,7 +179,7 @@ export default {
};
</script>
<template>
<div id="js-peek" :class="env">
<div id="js-peek" :class="[env, backgroundClass]">
<div
v-if="currentRequest"
class="container-fluid gl-flex gl-overflow-x-auto"
@ -189,14 +201,16 @@ export default {
id="peek-view-trace"
class="view"
>
<gl-link class="gl-underline" :href="currentRequest.details.tracing.tracing_url">{{
s__('PerformanceBar|Trace')
}}</gl-link>
<gl-link
class="!gl-text-neutral-0 gl-underline"
:href="currentRequest.details.tracing.tracing_url"
>{{ s__('PerformanceBar|Trace') }}</gl-link
>
</div>
<div v-if="showFlamegraphButtons" id="peek-flamegraph" class="view">
<gl-link
v-gl-tooltip.viewport
class="gl-text-sm"
class="gl-text-sm !gl-text-neutral-0"
:href="flamegraphPath('wall', currentRequestId)"
:title="s__('PerformanceBar|Wall flamegraph')"
>{{ s__('PerformanceBar|Wall') }}</gl-link
@ -204,7 +218,7 @@ export default {
/
<gl-link
v-gl-tooltip.viewport
class="gl-text-sm"
class="gl-text-sm !gl-text-neutral-0"
:href="flamegraphPath('cpu', currentRequestId)"
:title="s__('PerformanceBar|CPU flamegraph')"
>{{ s__('PerformanceBar|CPU') }}</gl-link
@ -212,7 +226,7 @@ export default {
/
<gl-link
v-gl-tooltip.viewport
class="gl-text-sm"
class="gl-text-sm !gl-text-neutral-0"
:href="flamegraphPath('object', currentRequestId)"
:title="s__('PerformanceBar|Object flamegraph')"
>{{ s__('PerformanceBar|Object') }}</gl-link
@ -226,7 +240,7 @@ export default {
v-if="currentRequest.details"
id="peek-download"
v-gl-tooltip.viewport
class="view gl-text-sm"
class="view gl-text-sm !gl-text-neutral-0"
is-unsafe-link
:download="downloadName"
:href="downloadPath"
@ -237,7 +251,7 @@ export default {
v-if="showMemoryReportButton"
id="peek-memory-report"
v-gl-tooltip.viewport
class="view gl-text-sm"
class="view gl-text-sm !gl-text-neutral-0"
:href="memoryReportPath"
:title="s__('PerformanceBar|Download memory report')"
>{{ s__('PerformanceBar|Memory report') }}</gl-link
@ -245,7 +259,7 @@ export default {
<gl-link
v-if="statsUrl"
v-gl-tooltip.viewport
class="view gl-text-sm"
class="view gl-text-sm !gl-text-neutral-0"
:href="statsUrl"
:title="s__('PerformanceBar|Show stats')"
>{{ s__('PerformanceBar|Stats') }}</gl-link

View File

@ -29,7 +29,10 @@ export default {
</script>
<template>
<div id="peek-request-selector" data-testid="request-dropdown" class="view gl-mr-5">
<gl-form-select v-model="currentRequestId">
<gl-form-select
v-model="currentRequestId"
select-class="gl-bg-alpha-light-24 gl-text-neutral-0 gl-w-26"
>
<option
v-for="request in requests"
:key="request.id"

View File

@ -11,7 +11,7 @@ const REPLACE_BLOB_MODAL_ID = 'modal-replace-blob';
export default {
i18n: {
replace: __('Replace file'),
replace: __('Replace'),
},
replaceBlobModalId: REPLACE_BLOB_MODAL_ID,
components: {

View File

@ -5,7 +5,7 @@ import { setUrlParams, relativePathToAbsolute, getBaseURL } from '~/lib/utils/ur
import { DEFAULT_BLOB_INFO } from '~/repository/constants';
export const i18n = {
btnCopyContentsTitle: __('Copy file contents'),
btnCopyContentsTitle: s__('BlobViewer|Copy contents'),
btnDownloadTitle: __('Download'),
btnRawTitle: s__('BlobViewer|Open raw'),
};

View File

@ -12,7 +12,8 @@ import BlobButtonGroup from './blob_button_group.vue';
import BlobDeleteFileGroup from './blob_delete_file_group.vue';
export const i18n = {
dropdownLabel: __('Actions'),
dropdownLabel: __('File actions'),
dropdownTooltip: __('Actions'),
fetchError: __('An error occurred while fetching lock information, please try again.'),
};
@ -117,7 +118,7 @@ export default {
</script>
<template>
<gl-disclosure-dropdown
v-gl-tooltip-directive.hover="$options.i18n.dropdownLabel"
v-gl-tooltip-directive.hover="$options.i18n.dropdownTooltip"
no-caret
icon="ellipsis_v"
data-testid="default-actions-container"

View File

@ -30,7 +30,6 @@ import {
} from '~/work_items/utils';
import { TYPENAME_MERGE_REQUEST, TYPENAME_VULNERABILITY } from '~/graphql_shared/constants';
import {
I18N_WORK_ITEM_CREATE_BUTTON_LABEL,
I18N_WORK_ITEM_ERROR_CREATING,
sprintfWorkItem,
i18n,
@ -382,7 +381,7 @@ export default {
return sprintfWorkItem(I18N_WORK_ITEM_ERROR_CREATING, this.selectedWorkItemTypeName);
},
createWorkItemText() {
return sprintfWorkItem(I18N_WORK_ITEM_CREATE_BUTTON_LABEL, this.selectedWorkItemTypeName);
return sprintfWorkItem(s__('WorkItem|Create %{workItemType}'), this.selectedWorkItemTypeName);
},
makeConfidentialText() {
return sprintfWorkItem(

View File

@ -5,7 +5,6 @@ import { __, s__ } from '~/locale';
import { isMetaClick } from '~/lib/utils/common_utils';
import { convertTypeEnumToName, newWorkItemPath } from '~/work_items/utils';
import {
I18N_NEW_WORK_ITEM_BUTTON_LABEL,
sprintfWorkItem,
ROUTES,
RELATED_ITEM_ID_URL_QUERY_PARAM,
@ -138,11 +137,14 @@ export default {
},
newWorkItemButtonText() {
return this.alwaysShowWorkItemTypeSelect && this.workItemTypeName
? sprintfWorkItem(I18N_NEW_WORK_ITEM_BUTTON_LABEL, '')
? sprintfWorkItem(s__('WorkItem|New %{workItemType}'), '')
: this.newWorkItemText;
},
newWorkItemText() {
return sprintfWorkItem(I18N_NEW_WORK_ITEM_BUTTON_LABEL, this.selectedWorkItemTypeLowercase);
return sprintfWorkItem(
s__('WorkItem|New %{workItemType}'),
this.selectedWorkItemTypeLowercase,
);
},
workItemCreatedText() {
return sprintfWorkItem(

View File

@ -17,7 +17,6 @@ import {
WORK_ITEMS_TYPE_MAP,
I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER,
I18N_WORK_ITEM_SEARCH_ERROR,
I18N_WORK_ITEM_NO_MATCHES_FOUND,
sprintfWorkItem,
} from '../../constants';
import { formatAncestors, isReference } from '../../utils';
@ -232,7 +231,6 @@ export default {
},
},
i18n: {
noMatchesFoundMessage: I18N_WORK_ITEM_NO_MATCHES_FOUND,
addInputPlaceholder: I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER,
},
safeHtmlConfig: { ADD_TAGS: ['strong', 'span'] },
@ -276,7 +274,7 @@ export default {
</template>
<template #no-results-content>
<span data-testid="no-match-found-namespace-message">{{
$options.i18n.noMatchesFoundMessage
s__('WorkItem|No matches found')
}}</span>
</template>
</gl-token-selector>

View File

@ -24,10 +24,6 @@ import {
BASE_ALLOWED_CREATE_TYPES,
WORK_ITEM_TYPE_VALUE_KEY_RESULT,
WORK_ITEM_TYPE_VALUE_OBJECTIVE,
I18N_WORK_ITEM_COPY_CREATE_NOTE_EMAIL,
I18N_WORK_ITEM_ERROR_COPY_REFERENCE,
I18N_WORK_ITEM_ERROR_COPY_EMAIL,
I18N_WORK_ITEM_NEW_RELATED_ITEM,
WORK_ITEM_TYPE_ENUM_EPIC,
WORK_ITEM_TYPE_VALUE_EPIC,
WORK_ITEM_TYPE_VALUE_MAP,
@ -260,19 +256,26 @@ export default {
this.workItemType,
),
copyCreateNoteEmail: sprintfWorkItem(
I18N_WORK_ITEM_COPY_CREATE_NOTE_EMAIL,
s__('WorkItem|Copy %{workItemType} email address'),
this.workItemType,
),
copyReferenceError: sprintfWorkItem(
s__(
'WorkItem|Something went wrong while copying the %{workItemType} reference. Please try again.',
),
this.workItemType,
),
copyReferenceError: sprintfWorkItem(I18N_WORK_ITEM_ERROR_COPY_REFERENCE, this.workItemType),
copyCreateNoteEmailError: sprintfWorkItem(
I18N_WORK_ITEM_ERROR_COPY_EMAIL,
s__(
'WorkItem|Something went wrong while copying the %{workItemType} email address. Please try again.',
),
this.workItemType,
),
};
},
newRelatedItemLabel() {
return this.workItemType === WORK_ITEM_TYPE_VALUE_EPIC
? sprintfWorkItem(I18N_WORK_ITEM_NEW_RELATED_ITEM, this.workItemType)
? sprintfWorkItem(s__('WorkItem|New related %{workItemType}'), this.workItemType)
: s__('WorkItem|New related item');
},
areYouSureDeleteMessage() {

View File

@ -12,9 +12,6 @@ import {
FORM_TYPES,
WORK_ITEMS_TYPE_MAP,
WORK_ITEM_TYPE_ENUM_TASK,
I18N_WORK_ITEM_CREATE_BUTTON_LABEL,
I18N_WORK_ITEM_ADD_BUTTON_LABEL,
I18N_WORK_ITEM_ADD_MULTIPLE_BUTTON_LABEL,
I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL,
I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP,
WORK_ITEM_TYPE_VALUE_EPIC,
@ -192,12 +189,12 @@ export default {
},
addOrCreateButtonLabel() {
if (this.isCreateForm) {
return sprintfWorkItem(I18N_WORK_ITEM_CREATE_BUTTON_LABEL, this.childrenTypeName);
return sprintfWorkItem(s__('WorkItem|Create %{workItemType}'), this.childrenTypeName);
}
if (this.workItemsToAdd.length > 1) {
return sprintfWorkItem(I18N_WORK_ITEM_ADD_MULTIPLE_BUTTON_LABEL, this.childrenTypeName);
return sprintfWorkItem(s__('WorkItem|Add %{workItemType}s'), this.childrenTypeName);
}
return sprintfWorkItem(I18N_WORK_ITEM_ADD_BUTTON_LABEL, this.childrenTypeName);
return sprintfWorkItem(s__('WorkItem|Add %{workItemType}'), this.childrenTypeName);
},
confidentialityCheckboxLabel() {
return sprintfWorkItem(I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL, this.childrenTypeName);

View File

@ -8,7 +8,6 @@ import { getParameterByName } from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import {
FORM_TYPES,
WORK_ITEMS_TREE_TEXT,
WORK_ITEM_TYPE_VALUE_MAP,
WORK_ITEMS_TYPE_MAP,
WORK_ITEM_TYPE_ENUM_OBJECTIVE,
@ -42,7 +41,6 @@ import WorkItemRolledUpCount from './work_item_rolled_up_count.vue';
export default {
FORM_TYPES,
WORK_ITEMS_TREE_TEXT,
WORK_ITEM_TYPE_ENUM_OBJECTIVE,
WORK_ITEM_TYPE_ENUM_KEY_RESULT,
components: {
@ -390,7 +388,7 @@ export default {
<template>
<crud-component
ref="workItemTree"
:title="$options.WORK_ITEMS_TREE_TEXT.title"
:title="s__('WorkItem|Child items')"
:anchor-id="widgetName"
:is-loading="isLoadingChildren && !fetchNextPageInProgress"
is-collapsible
@ -463,7 +461,11 @@ export default {
</template>
<template v-if="showEmptyMessage" #empty>
{{ $options.WORK_ITEMS_TREE_TEXT.empty }}
{{
s__(
'WorkItem|No child items are currently assigned. Use child items to break down work into smaller parts.',
)
}}
</template>
<template #default>

View File

@ -76,18 +76,12 @@ export const I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR = s__(
'WorkItem|Something went wrong while fetching work item award emojis. Please try again.',
);
export const I18N_NEW_WORK_ITEM_BUTTON_LABEL = s__('WorkItem|New %{workItemType}');
export const I18N_WORK_ITEM_CREATE_BUTTON_LABEL = s__('WorkItem|Create %{workItemType}');
export const I18N_WORK_ITEM_NEW_RELATED_ITEM = s__('WorkItem|New related %{workItemType}');
export const I18N_WORK_ITEM_ADD_BUTTON_LABEL = s__('WorkItem|Add %{workItemType}');
export const I18N_WORK_ITEM_ADD_MULTIPLE_BUTTON_LABEL = s__('WorkItem|Add %{workItemType}s');
export const I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER = s__(
'WorkItem|Search existing items, paste URL, or enter reference ID',
);
export const I18N_WORK_ITEM_SEARCH_ERROR = s__(
'WorkItem|Something went wrong while fetching the %{workItemType}. Please try again.',
);
export const I18N_WORK_ITEM_NO_MATCHES_FOUND = s__('WorkItem|No matches found');
export const I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL = s__(
'WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least the Planner role',
);
@ -95,17 +89,6 @@ export const I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP = s__(
'WorkItem|A non-confidential %{workItemType} cannot be assigned to a confidential parent %{parentWorkItemType}.',
);
export const I18N_WORK_ITEM_ERROR_COPY_REFERENCE = s__(
'WorkItem|Something went wrong while copying the %{workItemType} reference. Please try again.',
);
export const I18N_WORK_ITEM_ERROR_COPY_EMAIL = s__(
'WorkItem|Something went wrong while copying the %{workItemType} email address. Please try again.',
);
export const I18N_WORK_ITEM_COPY_CREATE_NOTE_EMAIL = s__(
'WorkItem|Copy %{workItemType} email address',
);
export const MAX_WORK_ITEMS = 10;
export const I18N_MAX_WORK_ITEMS_ERROR_MESSAGE = sprintf(
@ -205,13 +188,6 @@ export const WORK_ITEM_TYPE_VALUE_MAP = {
[WORK_ITEM_TYPE_VALUE_TICKET]: WORK_ITEM_TYPE_ENUM_TICKET,
};
export const WORK_ITEMS_TREE_TEXT = {
title: s__('WorkItem|Child items'),
empty: s__(
'WorkItem|No child items are currently assigned. Use child items to break down work into smaller parts.',
),
};
export const FORM_TYPES = {
create: 'create',
add: 'add',

View File

@ -36,6 +36,7 @@ export function optimisticAwardUpdate({ note, name, fullPath, workItemIid }) {
const { mutation } = getMutation({ note, name });
const currentUserId = window.gon.current_user_id;
const currentUserFullName = window.gon.current_user_fullname;
return (store) => {
store.updateQuery(
@ -52,7 +53,7 @@ export function optimisticAwardUpdate({ note, name, fullPath, workItemIid }) {
user: {
__typename: 'UserCore',
id: convertToGraphQLId(TYPENAME_USER, currentUserId),
name: null,
name: currentUserFullName,
},
},
};

View File

@ -357,9 +357,6 @@ $gl-bronze-plan: #cd7f32;
/*
Performance Bar
*/
$perf-bar-production: $gray-950;
$perf-bar-staging: $purple-950;
$perf-bar-development: $red-900;
$perf-bar-bucket-bg: $black;
$perf-bar-bucket-box-shadow-from: rgba($white, 0.2);
$perf-bar-bucket-box-shadow-to: rgba($black, 0.25);

View File

@ -9,60 +9,18 @@
z-index: #{$zindex-modal-backdrop - 1};
height: $performance-bar-height;
background: $black;
font-size: $gl-font-size-small;
line-height: $performance-bar-height;
color: $gray-50;
select {
width: 200px;
}
input {
width: $input-short-width - 60px;
}
select,
input {
color: inherit;
background-color: rgba($white, 0.2);
&::placeholder {
color: rgba($white, 0.7);
}
}
option {
color: initial;
}
// stylelint-disable-next-line gitlab/no-gl-class
.gl-link,
.gl-button {
color: $white;
}
&.disabled {
display: none;
}
&.production {
background-color: $perf-bar-production;
}
&.staging {
background-color: $perf-bar-staging;
}
&.development {
background-color: $perf-bar-development;
// stylelint-disable-next-line gitlab/no-gl-class
.gl-dark & {
background-color: $red-950;
}
}
// UI Elements
.bucket {
background: $perf-bar-bucket-bg;
@ -87,22 +45,6 @@
color: $perf-bar-canary-text;
}
strong {
color: $white;
}
table {
color: $black;
td {
vertical-align: top;
}
.backtrace-row {
display: none;
}
}
.view {
flex-shrink: 0;
@ -126,19 +68,4 @@
}
}
}
.performance-bar-modal {
.modal-body {
padding: 0;
}
.modal-footer {
display: none;
}
}
}
#modal-peek-pg-queries-content {
color: $black;
}

View File

@ -409,6 +409,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
)
end
display_max_limit_warning
respond_to do |format|
format.html do
# use next to appease Rubocop
@ -683,6 +685,14 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
view: diff_view
)
end
def display_max_limit_warning
return unless @merge_request.reached_versions_limit?
flash[:alert] = format(
_("This merge request has reached the maximum limit of %{limit} versions and cannot be updated further. " \
"Close this merge request and create a new one instead."), limit: MergeRequest::DIFF_VERSION_LIMIT)
end
end
Projects::MergeRequestsController.prepend_mod_with('Projects::MergeRequestsController')

View File

@ -95,7 +95,7 @@ class Projects::PipelinesController < Projects::ApplicationController
def create
service_response = Ci::CreatePipelineService
.new(project, current_user, create_params)
.execute(:web, ignore_skip_ci: true, save_on_errors: false)
.execute(:web, ignore_skip_ci: true, save_on_errors: false, **create_execute_params)
@pipeline = service_response.payload
@ -262,6 +262,10 @@ class Projects::PipelinesController < Projects::ApplicationController
params.require(:pipeline).permit(:ref, variables_attributes: %i[key variable_type secret_value])
end
def create_execute_params
params.require(:pipeline).permit(inputs: {}).to_h.symbolize_keys
end
def ensure_pipeline
render_404 unless pipeline
end

View File

@ -22,6 +22,7 @@ module Ci
all_runners
end
items = by_ids(items)
items = search(items)
items = by_active(items)
items = by_status(items)
@ -45,6 +46,12 @@ module Ci
attr_reader :group, :project
def by_ids(items)
return items unless @params[:id_in]
items.id_in(@params[:id_in])
end
def runner_type
@params[:type_type]&.to_sym
end

View File

@ -134,3 +134,5 @@ module Mutations
end
end
end
Mutations::Namespace::PackageSettings::Update.prepend_mod

View File

@ -71,6 +71,8 @@ module Types
field :nuget_symbol_server_enabled, GraphQL::Types::Boolean,
null: false,
description: 'Indicates wheather the NuGet symbol server is enabled for this namespace.'
description: 'Indicates whether the NuGet symbol server is enabled for this namespace.'
end
end
Types::Namespace::PackageSettingsType.prepend_mod

View File

@ -39,6 +39,7 @@ class MergeRequest < ApplicationRecord
SORTING_PREFERENCE_FIELD = :merge_requests_sort
CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH = 2700
MERGE_LEASE_TIMEOUT = 15.minutes.to_i
DIFF_VERSION_LIMIT = 1_000
belongs_to :target_project, class_name: "Project"
belongs_to :source_project, class_name: "Project"
@ -333,6 +334,11 @@ class MergeRequest < ApplicationRecord
includes(:target_project)
end
scope :by_commit_sha, ->(sha) do
Gitlab::AppLogger.info(
event: 'merge_request_by_commit_sha_call',
message: "MergeRequest.by_commit_sha called via #{caller_locations.reject { |line| line.path.include?('/gems/') }.first}"
)
where('EXISTS (?)', MergeRequestDiff.select(1).where('merge_requests.latest_merge_request_diff_id = merge_request_diffs.id').by_commit_sha(sha)).reorder(nil)
end
scope :by_merge_commit_sha, ->(sha) do
@ -348,6 +354,11 @@ class MergeRequest < ApplicationRecord
from_union([by_squash_commit_sha(sha), by_merge_commit_sha(sha), by_merged_commit_sha(sha)])
end
scope :by_related_commit_sha, ->(sha) do
Gitlab::AppLogger.info(
event: 'merge_request_by_related_commit_sha_call',
message: "MergeRequest.by_related_commit_sha called via #{caller_locations.reject { |line| line.path.include?('/gems/') }.first}"
)
from_union(
[
by_commit_sha(sha),
@ -2454,6 +2465,12 @@ class MergeRequest < ApplicationRecord
delegate :squash_always?, :squash_never?, :squash_enabled_by_default?, :squash_readonly?, to: :squash_option
def reached_versions_limit?
return false if Feature.disabled?(:merge_requests_diffs_limit, target_project)
merge_request_diffs.count >= DIFF_VERSION_LIMIT
end
private
def merge_base_pipelines

View File

@ -75,6 +75,11 @@ class MergeRequestDiff < ApplicationRecord
scope :viewable, -> { without_state(:empty) }
scope :by_head_commit_sha, ->(sha) { where(head_commit_sha: sha) }
scope :by_commit_sha, ->(sha) do
Gitlab::AppLogger.info(
event: 'merge_request_diff_by_commit_sha_call',
message: "MergeRequestDiff.by_commit_sha called via #{caller_locations.reject { |line| line.path.include?('/gems/') }.first}"
)
joins(:merge_request_diff_commits).where(merge_request_diff_commits: { sha: sha }).reorder(nil)
end

View File

@ -136,7 +136,7 @@ class MergeRequestDiffCommit < ApplicationRecord
def message
Gitlab::AppLogger.info(
event: 'mrdc_message_method',
message: "mrdc#message called via #{caller_locations(2, 1).first.path}"
message: "mrdc#message called via #{caller_locations.reject { |line| line.path.include?('/gems/') }.first}"
)
if ::Feature.enabled?(:disable_message_attribute_on_mr_diff_commits, project)

View File

@ -50,3 +50,5 @@ class Namespace::PackageSetting < ApplicationRecord
end
end
end
Namespace::PackageSetting.prepend_mod

View File

@ -2613,6 +2613,7 @@ class Project < ApplicationRecord
.append(key: 'CI_PROJECT_PATH', value: full_path)
.append(key: 'CI_PROJECT_PATH_SLUG', value: full_path_slug)
.append(key: 'CI_PROJECT_NAMESPACE', value: namespace.full_path)
.append(key: 'CI_PROJECT_NAMESPACE_SLUG', value: Gitlab::Utils.slugify(namespace.full_path))
.append(key: 'CI_PROJECT_NAMESPACE_ID', value: namespace.id.to_s)
.append(key: 'CI_PROJECT_ROOT_NAMESPACE', value: namespace.root_ancestor.path)
.append(key: 'CI_PROJECT_URL', value: web_url)

View File

@ -901,9 +901,13 @@ class Repository
options[:start_repository] = start_project.repository.raw_repository
end
skip_target_sha = options.delete(:skip_target_sha)
unless skip_target_sha
options[:target_sha] = self.commit(options[:branch_name])&.sha
if Feature.enabled?(:commit_files_target_sha, project)
options[:target_sha] = self.commit(options[:branch_name])&.sha || blank_ref
else
skip_target_sha = options.delete(:skip_target_sha)
unless skip_target_sha
options[:target_sha] = self.commit(options[:branch_name])&.sha
end
end
with_cache_hooks { raw.commit_files(user, **options) }

View File

@ -13,6 +13,11 @@ class BasePolicy < DeclarativePolicy::Base
end
end
desc "The current instance is a GitLab Dedicated instance"
condition :gitlab_dedicated do
Gitlab::CurrentSettings.gitlab_dedicated_instance?
end
desc "User is blocked"
with_options scope: :user, score: 0
condition(:blocked) { @user&.blocked? }
@ -92,6 +97,10 @@ class BasePolicy < DeclarativePolicy::Base
enable :change_repository_storage
end
rule { gitlab_dedicated & admin }.policy do
enable :read_dedicated_hosted_runner_usage
end
rule { default }.enable :read_cross_project
condition(:is_gitlab_com, score: 0, scope: :global) { ::Gitlab.com? }

View File

@ -9,6 +9,9 @@ module MergeRequests
def execute
old_diff_refs = merge_request.diff_refs
return if merge_request.reached_versions_limit?
new_diff = merge_request.create_merge_request_diff
clear_cache(new_diff)

View File

@ -47,8 +47,14 @@ module Namespaces
end
def package_settings_params
@params.slice(*ALLOWED_ATTRIBUTES)
@params.slice(*allowed_attributes)
end
def allowed_attributes
ALLOWED_ATTRIBUTES
end
end
end
end
Namespaces::PackageSettings::UpdateService.prepend_mod

View File

@ -126,6 +126,8 @@ module Snippets
end
def commit_attrs(snippet, msg)
return super if Feature.enabled?(:commit_files_target_sha, snippet.project)
super.merge(skip_target_sha: true)
end
end

View File

@ -0,0 +1,9 @@
---
name: commit_files_target_sha
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/517122
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181459
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/520058
milestone: '17.10'
group: group::source code
type: gitlab_com_derisk
default_enabled: false

View File

@ -0,0 +1,9 @@
---
name: merge_requests_diffs_limit
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/517497
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183063
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/521970
milestone: '17.10'
group: group::source code
type: gitlab_com_derisk
default_enabled: false

View File

@ -8,14 +8,6 @@ description: Keeps approval merge request rules
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8497
milestone: '11.7'
gitlab_schema: gitlab_main_cell
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: merge_request_id
table: merge_requests
sharding_key: target_project_id
belongs_to: merge_request
desired_sharding_key_migration_job_name: BackfillApprovalMergeRequestRulesProjectId
table_size: medium
sharding_key:
project_id: projects

View File

@ -17,5 +17,4 @@ desired_sharding_key:
table: approval_merge_request_rules
sharding_key: project_id
belongs_to: approval_merge_request_rule
awaiting_backfill_on_parent: true
table_size: small

View File

@ -17,5 +17,4 @@ desired_sharding_key:
table: approval_merge_request_rules
sharding_key: project_id
belongs_to: approval_merge_request_rule
awaiting_backfill_on_parent: true
table_size: large

View File

@ -0,0 +1,8 @@
---
migration_job_name: BackfillScanResultPoliciesNamespaceId
description: Backfills sharding key `scan_result_policies.namespace_id` from `security_orchestration_policy_configurations`.
feature_category: security_policy_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183125
milestone: '17.10'
queued_migration_version: 20250301125858
finalized_by: # version of the migration that finalized this BBM

View File

@ -0,0 +1,8 @@
---
migration_job_name: BackfillScanResultPoliciesProjectId
description: Backfills sharding key `scan_result_policies.project_id` from `security_orchestration_policy_configurations`.
feature_category: security_policy_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183125
milestone: '17.10'
queued_migration_version: 20250301125534
finalized_by: # version of the migration that finalized this BBM

View File

@ -26,3 +26,6 @@ desired_sharding_key:
sharding_key: namespace_id
belongs_to: security_orchestration_policy_configuration
table_size: small
desired_sharding_key_migration_job_name:
- BackfillScanResultPoliciesProjectId
- BackfillScanResultPoliciesNamespaceId

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
class AddAuditEventsEnabledToNamespacePackageSettings < Gitlab::Database::Migration[2.2]
milestone '17.10'
def up
add_column :namespace_package_settings, :audit_events_enabled, :boolean, default: false, null: false,
if_not_exists: true
end
def down
remove_column :namespace_package_settings, :audit_events_enabled, if_exists: true
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddBillingMonthYearIndex < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.10'
INDEX_NAME = 'idx_gitlab_hosted_runner_monthly_usages_on_billing_month_year'
def up
add_concurrent_index :ci_gitlab_hosted_runner_monthly_usages, "EXTRACT(YEAR FROM billing_month)", name: INDEX_NAME,
using: :btree
end
def down
remove_concurrent_index_by_name :ci_gitlab_hosted_runner_monthly_usages, name: INDEX_NAME
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddNamespaceIdToScanResultPolicies < Gitlab::Database::Migration[2.2]
milestone '17.10'
def change
add_column :scan_result_policies, :namespace_id, :bigint
end
end

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
class ValidateApprovalMergeRequestRulesProjectIdNotNullConstraint < Gitlab::Database::Migration[2.2]
milestone '17.10'
def up
validate_not_null_constraint :approval_merge_request_rules, :project_id
end
def down
# no-op
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class AddScanResultPoliciesProjectIdTrigger < Gitlab::Database::Migration[2.2]
milestone '17.10'
def up
install_sharding_key_assignment_trigger(
table: :scan_result_policies,
sharding_key: :project_id,
parent_table: :security_orchestration_policy_configurations,
parent_sharding_key: :project_id,
foreign_key: :security_orchestration_policy_configuration_id
)
end
def down
remove_sharding_key_assignment_trigger(
table: :scan_result_policies,
sharding_key: :project_id,
parent_table: :security_orchestration_policy_configurations,
parent_sharding_key: :project_id,
foreign_key: :security_orchestration_policy_configuration_id
)
end
end

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
class QueueBackfillScanResultPoliciesProjectId < Gitlab::Database::Migration[2.2]
milestone '17.10'
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
MIGRATION = "BackfillScanResultPoliciesProjectId"
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 1000
SUB_BATCH_SIZE = 100
def up
queue_batched_background_migration(
MIGRATION,
:scan_result_policies,
:id,
:project_id,
:security_orchestration_policy_configurations,
:project_id,
:security_orchestration_policy_configuration_id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(
MIGRATION,
:scan_result_policies,
:id,
[
:project_id,
:security_orchestration_policy_configurations,
:project_id,
:security_orchestration_policy_configuration_id
]
)
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class IndexScanResultPoliciesOnNamespaceId < Gitlab::Database::Migration[2.2]
milestone '17.10'
disable_ddl_transaction!
INDEX_NAME = 'index_scan_result_policies_on_namespace_id'
def up
add_concurrent_index :scan_result_policies, :namespace_id, name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :scan_result_policies, INDEX_NAME
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddScanResultPoliciesNamespaceIdFk < Gitlab::Database::Migration[2.2]
milestone '17.10'
disable_ddl_transaction!
def up
add_concurrent_foreign_key :scan_result_policies, :namespaces, column: :namespace_id, on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key :scan_result_policies, column: :namespace_id
end
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class AddScanResultPoliciesNamespaceIdTrigger < Gitlab::Database::Migration[2.2]
milestone '17.10'
def up
install_sharding_key_assignment_trigger(
table: :scan_result_policies,
sharding_key: :namespace_id,
parent_table: :security_orchestration_policy_configurations,
parent_sharding_key: :namespace_id,
foreign_key: :security_orchestration_policy_configuration_id
)
end
def down
remove_sharding_key_assignment_trigger(
table: :scan_result_policies,
sharding_key: :namespace_id,
parent_table: :security_orchestration_policy_configurations,
parent_sharding_key: :namespace_id,
foreign_key: :security_orchestration_policy_configuration_id
)
end
end

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
class QueueBackfillScanResultPoliciesNamespaceId < Gitlab::Database::Migration[2.2]
milestone '17.10'
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
MIGRATION = "BackfillScanResultPoliciesNamespaceId"
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 1000
SUB_BATCH_SIZE = 100
def up
queue_batched_background_migration(
MIGRATION,
:scan_result_policies,
:id,
:namespace_id,
:security_orchestration_policy_configurations,
:namespace_id,
:security_orchestration_policy_configuration_id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(
MIGRATION,
:scan_result_policies,
:id,
[
:namespace_id,
:security_orchestration_policy_configurations,
:namespace_id,
:security_orchestration_policy_configuration_id
]
)
end
end

View File

@ -0,0 +1 @@
93e562375a953780fe30c5ef8781f6a78f5fcb0de8ad77021dbdb2e846f2f016

View File

@ -0,0 +1 @@
77fa54ab6762eb8c9ba172d6bbfdf7d51f599445a06b2d2b60f206e0c19ccd83

View File

@ -0,0 +1 @@
80718abeb6da1c012b1b339f5ad3e57746cffb0473185f95d37edb4b76fb494a

View File

@ -0,0 +1 @@
56f1db3bdeea1aeef9df49e501eb7e1dac093f18f05a4e07172cb4bbd55ceecd

View File

@ -0,0 +1 @@
3226c5fca1dd5555283876ef828ba17e805a246ee2e441d4d05498edfc735e2e

View File

@ -0,0 +1 @@
3a0f04fc4a380d6617e65f9d39dfab44de21cc5584b54c5857ea46e15250561e

View File

@ -0,0 +1 @@
35b534dc4a99b72d70f522fba4cbf4b624cd2ec01439ea13656e72f9204a48f9

View File

@ -0,0 +1 @@
8352e0e9e20603bdb7e4fccac26214043c30d8e34dbe8b8b8a998a1716865adb

View File

@ -0,0 +1 @@
f152eb71fe1e65c715bdd5341625103e799e6dbf76f13a0c344179770157cdc9

View File

@ -0,0 +1 @@
1f93c1cf8cc282f62a840707a186c9b78eea50ab89511a5c838b5c4226b86a00

View File

@ -1990,6 +1990,22 @@ RETURN NEW;
END
$$;
CREATE FUNCTION trigger_4c320a13bc8d() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW."project_id" IS NULL THEN
SELECT "project_id"
INTO NEW."project_id"
FROM "security_orchestration_policy_configurations"
WHERE "security_orchestration_policy_configurations"."id" = NEW."security_orchestration_policy_configuration_id";
END IF;
RETURN NEW;
END
$$;
CREATE FUNCTION trigger_4cc5c3ac4d7f() RETURNS trigger
LANGUAGE plpgsql
AS $$
@ -3171,6 +3187,22 @@ RETURN NEW;
END
$$;
CREATE FUNCTION trigger_b83b7e51e2f5() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW."namespace_id" IS NULL THEN
SELECT "namespace_id"
INTO NEW."namespace_id"
FROM "security_orchestration_policy_configurations"
WHERE "security_orchestration_policy_configurations"."id" = NEW."security_orchestration_policy_configuration_id";
END IF;
RETURN NEW;
END
$$;
CREATE FUNCTION trigger_b8eecea7f351() RETURNS trigger
LANGUAGE plpgsql
AS $$
@ -8597,6 +8629,7 @@ CREATE TABLE approval_merge_request_rules (
role_approvers integer[] DEFAULT '{}'::integer[] NOT NULL,
approval_policy_action_idx smallint DEFAULT 0 NOT NULL,
CONSTRAINT check_6fca5928b2 CHECK ((char_length(section) <= 255)),
CONSTRAINT check_90caab37e0 CHECK ((project_id IS NOT NULL)),
CONSTRAINT check_approval_m_r_rules_allowed_role_approvers_valid_entries CHECK (((role_approvers = '{}'::integer[]) OR (role_approvers <@ ARRAY[20, 30, 40, 50, 60])))
);
@ -16925,6 +16958,7 @@ CREATE TABLE namespace_package_settings (
nuget_symbol_server_enabled boolean DEFAULT false NOT NULL,
terraform_module_duplicates_allowed boolean DEFAULT false NOT NULL,
terraform_module_duplicate_exception_regex text DEFAULT ''::text NOT NULL,
audit_events_enabled boolean DEFAULT false NOT NULL,
CONSTRAINT check_31340211b1 CHECK ((char_length(generic_duplicate_exception_regex) <= 255)),
CONSTRAINT check_d63274b2b6 CHECK ((char_length(maven_duplicate_exception_regex) <= 255)),
CONSTRAINT check_eedcf85c48 CHECK ((char_length(nuget_duplicate_exception_regex) <= 255)),
@ -21177,6 +21211,7 @@ CREATE TABLE scan_result_policies (
action_idx smallint DEFAULT 0 NOT NULL,
custom_roles bigint[] DEFAULT '{}'::bigint[] NOT NULL,
licenses jsonb DEFAULT '{}'::jsonb NOT NULL,
namespace_id bigint,
CONSTRAINT age_value_null_or_positive CHECK (((age_value IS NULL) OR (age_value >= 0))),
CONSTRAINT check_scan_result_policies_rule_idx_positive CHECK (((rule_idx IS NULL) OR (rule_idx >= 0))),
CONSTRAINT custom_roles_array_check CHECK ((array_position(custom_roles, NULL::bigint) IS NULL))
@ -27358,9 +27393,6 @@ ALTER TABLE ONLY project_type_ci_runners_e59bb2812d
ALTER TABLE ONLY group_type_ci_runners_e59bb2812d
ADD CONSTRAINT check_81b90172a6 UNIQUE (id);
ALTER TABLE approval_merge_request_rules
ADD CONSTRAINT check_90caab37e0 CHECK ((project_id IS NOT NULL)) NOT VALID;
ALTER TABLE approvals
ADD CONSTRAINT check_9da7c942dc CHECK ((project_id IS NOT NULL)) NOT VALID;
@ -31123,6 +31155,8 @@ CREATE UNIQUE INDEX idx_external_audit_event_destination_id_key_uniq ON audit_ev
CREATE INDEX idx_external_status_checks_on_id_and_project_id ON external_status_checks USING btree (id, project_id);
CREATE INDEX idx_gitlab_hosted_runner_monthly_usages_on_billing_month_year ON ci_gitlab_hosted_runner_monthly_usages USING btree (EXTRACT(year FROM billing_month));
CREATE INDEX idx_gpg_keys_on_user_externally_verified ON gpg_keys USING btree (user_id) WHERE (externally_verified = true);
CREATE INDEX idx_group_audit_events_on_author_id_created_at_id ON ONLY group_audit_events USING btree (author_id, created_at, id);
@ -35045,6 +35079,8 @@ CREATE UNIQUE INDEX index_scan_execution_policy_rules_on_unique_policy_rule_inde
CREATE UNIQUE INDEX index_scan_result_policies_on_configuration_action_and_rule_idx ON scan_result_policies USING btree (security_orchestration_policy_configuration_id, project_id, orchestration_policy_idx, rule_idx, action_idx);
CREATE INDEX index_scan_result_policies_on_namespace_id ON scan_result_policies USING btree (namespace_id);
CREATE INDEX index_scan_result_policies_on_project_id ON scan_result_policies USING btree (project_id);
CREATE INDEX index_scan_result_policy_violations_on_approval_policy_rule_id ON scan_result_policy_violations USING btree (approval_policy_rule_id);
@ -38485,6 +38521,8 @@ CREATE TRIGGER trigger_4ad9a52a6614 BEFORE INSERT OR UPDATE ON sbom_occurrences_
CREATE TRIGGER trigger_4b43790d717f BEFORE INSERT OR UPDATE ON protected_environment_approval_rules FOR EACH ROW EXECUTE FUNCTION trigger_4b43790d717f();
CREATE TRIGGER trigger_4c320a13bc8d BEFORE INSERT OR UPDATE ON scan_result_policies FOR EACH ROW EXECUTE FUNCTION trigger_4c320a13bc8d();
CREATE TRIGGER trigger_4cc5c3ac4d7f BEFORE INSERT OR UPDATE ON bulk_import_export_uploads FOR EACH ROW EXECUTE FUNCTION trigger_4cc5c3ac4d7f();
CREATE TRIGGER trigger_4dc8ec48e038 BEFORE INSERT OR UPDATE ON requirements_management_test_reports FOR EACH ROW EXECUTE FUNCTION trigger_4dc8ec48e038();
@ -38637,6 +38675,8 @@ CREATE TRIGGER trigger_b75e5731e305 BEFORE INSERT OR UPDATE ON dast_profiles_pip
CREATE TRIGGER trigger_b7abb8fc4cf0 BEFORE INSERT OR UPDATE ON work_item_progresses FOR EACH ROW EXECUTE FUNCTION trigger_b7abb8fc4cf0();
CREATE TRIGGER trigger_b83b7e51e2f5 BEFORE INSERT OR UPDATE ON scan_result_policies FOR EACH ROW EXECUTE FUNCTION trigger_b83b7e51e2f5();
CREATE TRIGGER trigger_b8eecea7f351 BEFORE INSERT OR UPDATE ON dependency_proxy_manifest_states FOR EACH ROW EXECUTE FUNCTION trigger_b8eecea7f351();
CREATE TRIGGER trigger_b9839c6d713f BEFORE INSERT ON application_settings FOR EACH ROW EXECUTE FUNCTION function_for_trigger_b9839c6d713f();
@ -39810,6 +39850,9 @@ ALTER TABLE ONLY push_rules
ALTER TABLE ONLY merge_request_diffs
ADD CONSTRAINT fk_8483f3258f FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;
ALTER TABLE ONLY scan_result_policies
ADD CONSTRAINT fk_84d4bc9abe FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY requirements
ADD CONSTRAINT fk_85044baef0 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -61,7 +61,7 @@ The banner can be customized with a specific message.
An error is displayed when a user tries to perform a write operation that isn't allowed.
![Maintenance Mode banner and error message](img/maintenance_mode_error_message_v17.6.png)
![Maintenance Mode banner and error message](img/maintenance_mode_error_message_v17_6.png)
{{< alert type="note" >}}

View File

@ -17,7 +17,7 @@ You can analyze your users' GitLab activities over time.
How do you interpret the user cohorts table? Let's review an example with the
following user cohorts:
![User cohort table showing retention and inactivity metrics, highlighting March and April 2020.](img/cohorts_v13_9_a.png)
![User cohort table showing retention and inactivity metrics, highlighting March and April 2020.](img/cohorts_v13_9.png)
For the cohort of March 2020, three users were added to this server and have
been active since this month. One month later (April 2020), two users are still

View File

@ -409,6 +409,12 @@ Returns [`CiConfig`](#ciconfig).
| <a id="queryciconfigsha"></a>`sha` | [`String`](#string) | Sha for the pipeline. |
| <a id="queryciconfigskipverifyprojectsha"></a>`skipVerifyProjectSha` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Introduced** in GitLab 16.5. **Status**: Experiment. If the provided `sha` is found in the project's repository but is not associated with a Git reference (a detached commit), the verification fails and a validation error is returned. Otherwise, verification passes, even if the `sha` is invalid. Set to `true` to skip this verification process. |
### `Query.ciDedicatedHostedRunnerFilters`
Returns available filters for GitLab Dedicated runner usage data.
Returns [`CiDedicatedHostedRunnerFilters`](#cidedicatedhostedrunnerfilters).
### `Query.ciDedicatedHostedRunnerUsage`
Compute usage data for runners across namespaces on GitLab Dedicated. Defaults to the current year if no year or billing month is specified. Ultimate only.
@ -11400,6 +11406,7 @@ Input type: `UpdateNamespacePackageSettingsInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationupdatenamespacepackagesettingsauditeventsenabled"></a>`auditEventsEnabled` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.10. |
| <a id="mutationupdatenamespacepackagesettingsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationupdatenamespacepackagesettingsgenericduplicateexceptionregex"></a>`genericDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |
| <a id="mutationupdatenamespacepackagesettingsgenericduplicatesallowed"></a>`genericDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate generic packages are allowed for this namespace. |
@ -11413,7 +11420,7 @@ Input type: `UpdateNamespacePackageSettingsInput`
| <a id="mutationupdatenamespacepackagesettingsnpmpackagerequestsforwarding"></a>`npmPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether npm package forwarding is allowed for this namespace. |
| <a id="mutationupdatenamespacepackagesettingsnugetduplicateexceptionregex"></a>`nugetDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When nuget_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |
| <a id="mutationupdatenamespacepackagesettingsnugetduplicatesallowed"></a>`nugetDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate NuGet packages are allowed for this namespace. |
| <a id="mutationupdatenamespacepackagesettingsnugetsymbolserverenabled"></a>`nugetSymbolServerEnabled` | [`Boolean`](#boolean) | Indicates wheather the NuGet symbol server is enabled for this namespace. |
| <a id="mutationupdatenamespacepackagesettingsnugetsymbolserverenabled"></a>`nugetSymbolServerEnabled` | [`Boolean`](#boolean) | Indicates whether the NuGet symbol server is enabled for this namespace. |
| <a id="mutationupdatenamespacepackagesettingspypipackagerequestsforwarding"></a>`pypiPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether PyPI package forwarding is allowed for this namespace. |
| <a id="mutationupdatenamespacepackagesettingsterraformmoduleduplicateexceptionregex"></a>`terraformModuleDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When terraform_module_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |
| <a id="mutationupdatenamespacepackagesettingsterraformmoduleduplicatesallowed"></a>`terraformModuleDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate Terraform packages are allowed for this namespace. |
@ -21732,6 +21739,17 @@ CI/CD config variables.
| <a id="ciconfigvariablevalue"></a>`value` | [`String`](#string) | Value of the variable. |
| <a id="ciconfigvariablevalueoptions"></a>`valueOptions` | [`[String!]`](#string) | Value options for the variable. |
### `CiDedicatedHostedRunnerFilters`
Filter options available for GitLab Dedicated runner usage data.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="cidedicatedhostedrunnerfiltersrunners"></a>`runners` | [`CiRunnerConnection`](#cirunnerconnection) | List of unique runners with usage data. (see [Connections](#connections)) |
| <a id="cidedicatedhostedrunnerfiltersyears"></a>`years` | [`[Int!]`](#int) | List of years with available usage data. |
### `CiDedicatedHostedRunnerUsage`
Compute usage data for hosted runners on GitLab Dedicated.
@ -32641,6 +32659,7 @@ Namespace-level Package Registry settings.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="packagesettingsauditeventsenabled"></a>`auditEventsEnabled` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Introduced** in GitLab 17.10. **Status**: Experiment. Indicates whether audit events are created when publishing or deleting a package in the namespace (Premium and Ultimate only). Returns `null` if `package_registry_audit_events` feature flag is disabled. |
| <a id="packagesettingsgenericduplicateexceptionregex"></a>`genericDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |
| <a id="packagesettingsgenericduplicatesallowed"></a>`genericDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate generic packages are allowed for this namespace. |
| <a id="packagesettingslockmavenpackagerequestsforwarding"></a>`lockMavenPackageRequestsForwarding` | [`Boolean!`](#boolean) | Indicates whether Maven package forwarding is locked for all descendent namespaces. |
@ -32654,7 +32673,7 @@ Namespace-level Package Registry settings.
| <a id="packagesettingsnpmpackagerequestsforwardinglocked"></a>`npmPackageRequestsForwardingLocked` | [`Boolean!`](#boolean) | Indicates whether npm package forwarding settings are locked by a parent namespace. |
| <a id="packagesettingsnugetduplicateexceptionregex"></a>`nugetDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When nuget_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |
| <a id="packagesettingsnugetduplicatesallowed"></a>`nugetDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate NuGet packages are allowed for this namespace. |
| <a id="packagesettingsnugetsymbolserverenabled"></a>`nugetSymbolServerEnabled` | [`Boolean!`](#boolean) | Indicates wheather the NuGet symbol server is enabled for this namespace. |
| <a id="packagesettingsnugetsymbolserverenabled"></a>`nugetSymbolServerEnabled` | [`Boolean!`](#boolean) | Indicates whether the NuGet symbol server is enabled for this namespace. |
| <a id="packagesettingspypipackagerequestsforwarding"></a>`pypiPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether PyPI package forwarding is allowed for this namespace. |
| <a id="packagesettingspypipackagerequestsforwardinglocked"></a>`pypiPackageRequestsForwardingLocked` | [`Boolean!`](#boolean) | Indicates whether PyPI package forwarding settings are locked by a parent namespace. |
| <a id="packagesettingsterraformmoduleduplicateexceptionregex"></a>`terraformModuleDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When terraform_module_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |

View File

@ -30,6 +30,16 @@ in GitLab 15.0. Iterating pages of results with a number (`?page=2`) is unsuppor
{{< /alert >}}
{{< alert type="warning" >}}
In version 17.7, the error handling behavior when a requested path is not found is updated.
The endpoint now returns a status code `404 Not Found`. Previously, the status code was `200 OK`.
If your implementation relies on receiving a `200` status code with an empty array for
missing paths, you must update your error handling to handle the new `404` responses.
{{< /alert >}}
```plaintext
GET /projects/:id/repository/tree
```

View File

@ -44,7 +44,11 @@ There are a few ways to view a list of environments for a given project:
![Deployments list](img/deployments_list_v13_10.png)
Deployments show up in this list only after a deployment job has created them.
Deployments show up in this list only after a deployment job has created them.
- To view a list of all manual jobs in a deployment pipeline, select the **Run** ({{< icon name="play" >}}) dropdown list.
![Viewing a manual job in a deployment pipeline](img/view_manual_jobs_v17_10.png)
### Environment URL

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -27,6 +27,7 @@ These types of pipelines all appear on the **Pipelines** tab of a merge request.
Your pipeline can run every time you commit changes to a branch.
This type of pipeline is called a *branch pipeline*.
They display a `branch` label in pipeline lists.
This pipeline runs by default. No configuration is required.
@ -43,6 +44,7 @@ Branch pipelines:
A pipeline can run every time you create or push a new [tag](../../user/project/repository/tags/_index.md).
This type of pipeline is called a *tag pipeline*.
They display a `tag` label in pipeline lists.
This pipeline runs by default. No configuration is required.
@ -60,6 +62,7 @@ Instead of a branch pipeline, you can configure your pipeline to run every time
source branch in a merge request.
This type of pipeline is called a *merge request pipeline*.
They display a `merge request` label in pipeline lists.
Merge request pipelines do not run by default. You must configure
the jobs in the `.gitlab-ci.yml` file to run as merge request pipelines.

View File

@ -113,6 +113,7 @@ Predefined variables become available at three different phases of pipeline exec
| `CI_PROJECT_NAME` | Pre-pipeline | The name of the directory for the project. For example if the project URL is `gitlab.example.com/group-name/project-1`, `CI_PROJECT_NAME` is `project-1`. |
| `CI_PROJECT_NAMESPACE` | Pre-pipeline | The project namespace (username or group name) of the job. |
| `CI_PROJECT_NAMESPACE_ID` | Pre-pipeline | The project namespace ID of the job. Introduced in GitLab 15.7. |
| `CI_PROJECT_NAMESPACE_SLUG` | Pre-pipeline | `$CI_PROJECT_NAMESPACE` in lowercase with characters that are not `a-z` or `0-9` replaced with - and shortened to 63 bytes. |
| `CI_PROJECT_PATH_SLUG` | Pre-pipeline | `$CI_PROJECT_PATH` in lowercase with characters that are not `a-z` or `0-9` replaced with `-` and shortened to 63 bytes. Use in URLs and domain names. |
| `CI_PROJECT_PATH` | Pre-pipeline | The project namespace with the project name included. |
| `CI_PROJECT_REPOSITORY_LANGUAGES` | Pre-pipeline | A comma-separated, lowercase list of the languages used in the repository. For example `ruby,javascript,html,css`. The maximum number of languages is limited to 5. An issue [proposes to increase the limit](https://gitlab.com/gitlab-org/gitlab/-/issues/368925). |

View File

@ -271,6 +271,7 @@ predicate:
CI_PROJECT_ID: '45821955'
CI_PROJECT_NAME: npm-provenance-example
CI_PROJECT_NAMESPACE: strongjz
CI_PROJECT_NAMESPACE_SLUG: strongjz
CI_PROJECT_NAMESPACE_ID: '36018'
CI_PROJECT_PATH: strongjz/npm-provenance-example
CI_PROJECT_PATH_SLUG: strongjz-npm-provenance-example

View File

@ -5,9 +5,61 @@ info: Any user with at least the Maintainer role can merge updates to this conte
title: Application secrets
---
This page is a development guide for application secrets.
GitLab must be able to access various secrets such as access tokens and other credentials to function.
These secrets are encrypted and stored at rest and may be found in different data stores depending on use.
Use this guide to understand how different kinds of secrets are stored and managed.
## Secret entries
## Application secrets and operational secrets
Broadly speaking, there are two classes of secrets:
1. **Application secrets.** The GitLab application uses these to implement a particular feature or function.
An example would be access tokens or private keys to create cryptographic signatures. We store
these secrets in the database in encrypted columns.
See [Secure Coding Guidelines: At rest](secure_coding_guidelines.md#at-rest).
1. **Operational secrets.** Used to read and store other secrets or bootstrap the application. For this reason,
they cannot be stored in the database.
These secrets are stored as [Rails credentials](https://guides.rubyonrails.org/security.html#environmental-security)
in the `config/secrets.yml` file, directly for source installation, or through an installer like Omnibus or Helm (where
actual secrets can be stored in an external secrets container like
[Kubernetes secrets](https://kubernetes.io/docs/concepts/configuration/secret/) or [Vault](https://www.vaultproject.io/)).
## Application secrets
Application secrets should be stored in postgres using `ActiveRecord::Encryption`:
```ruby
class MyModel < ApplicationRecord
encrypts :my_secret
end
```
{{< alert type="note" >}}
Until recently, we used `attr_encrypted` instead of `ActiveRecord::Encryption`. We are in the process of
migrating all columns to use the new Rails-native encryption framework (see [epic 15420](https://gitlab.com/groups/gitlab-org/-/epics/15420)).
{{< /alert >}}
{{< alert type="note" >}}
Despite there being precedent, application secrets should not be stored as an `ApplicationSetting`.
This can lead to the entire application malfunctioning if this secret fails to decode. To reduce
coupling to other features, isolate secrets into dedicated tables.
{{< /alert >}}
{{< alert type="note" >}}
In some cases, it can be undesirable to store secrets in the database. For example, if the secret is needed
to bootstrap the Rails application, it may have to access the database in an initializer, which can lead to
initialization races as the database connection itself may not yet be ready. In this case, store the secret
as an operational secret instead.
{{< /alert >}}
## Operational secrets
We maintain a number of operational secrets in `config/secrets.yml`, primarily to manage other secrets. Historically, GitLab
used this approach for all secrets, including application secrets, but has meanwhile moved most of these into postgres.
The only exception is `openid_connect_signing_key` since it needs to be accessed from a Rails initializer before
the database may be ready.
### Secret entries
|Entry |Description |
|--- |--- |
@ -20,7 +72,7 @@ This page is a development guide for application secrets.
| `active_record_encryption_deterministic_key` | The base key to deterministically-encrypt data for `ActiveRecord::Encryption` encrypted columns |
| `active_record_encryption_key_derivation_salt` | The derivation salt to encrypt data for `ActiveRecord::Encryption` encrypted columns |
## Where the secrets are stored
### Where the secrets are stored
|Installation type |Location |
|--- |--- |
@ -28,9 +80,9 @@ This page is a development guide for application secrets.
| Cloud Native GitLab Charts |[Kubernetes Secrets](https://docs.gitlab.com/charts/installation/secrets.html#gitlab-rails-secret) |
| Self-compiled |`<path-to-gitlab-rails>/config/secrets.yml` (Automatically generated by [`config/initializers/01_secret_token.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/initializers/01_secret_token.rb)) |
## Warning: Before you add a new secret to application secrets
### Warning: Before you add a new secret to application secrets
### Add support to Omnibus GitLab and the Cloud Native GitLab charts
#### Add support to Omnibus GitLab and the Cloud Native GitLab charts
Before you add a new secret to
[`config/initializers/01_secret_token.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/initializers/01_secret_token.rb),
@ -45,45 +97,36 @@ have write access.
- [Change for Omnibus GitLab installation](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/8026)
- [Change for Cloud Native installation](https://gitlab.com/gitlab-org/charts/gitlab/-/merge_requests/3988)
### Populate the secrets in live environments
#### Populate the secrets in live environments
Additionally, in case you need the secret to have the same value on all nodes (which is usually the case),
you need to make sure
[it's configured for all live environments (GitLab.com, staging, pre)](https://gitlab.com/gitlab-com/gl-infra/k8s-workloads/gitlab-com/-/blob/master/releases/gitlab-external-secrets/values/values.yaml.gotmpl)
prior to changing this file.
### Document the new secrets
#### Document the new secrets
#### Add the new secrets to this documentation file
1. Add the new secrets to this documentation file.
1. Mention the new secrets in the next release upgrade notes.
For instance, for the 17.8 release, the notes would go in `data/release_posts/17_8/17-8-upgrade.yml` and contain something like the following:
The new secrets should be documented in `doc/development/application_secrets.md`.
```yaml
---
upgrades:
- reporter: <your username> # item author username
description: |
In Gitlab 17.8, three new secrets have been added to support the upcoming encryption framework:
- `active_record_encryption_primary_key`
- `active_record_encryption_deterministic_key`
- `active_record_encryption_key_derivation_salt`
#### Mention the new secrets in the next release upgrade notes
**If you have a multi-node configuration, you should ensure these secrets are the same on all nodes.** Otherwise, the application will automatically generate the missing secrets.
The new secrets should be mentioned in the next release notes, in the upgrade section.
If you use the [GitLab helm chart](https://docs.gitlab.com/charts/) and disabled the [shared-secrets chart](https://docs.gitlab.com/charts/charts/shared-secrets/), you will need to [manually create these secrets](https://docs.gitlab.com/charts/installation/secrets.html#gitlab-rails-secret).
```
For instance, for the 17.8 release, the notes would go in `data/release_posts/17_8/17-8-upgrade.yml` and contain something like the following:
```yaml
---
upgrades:
- reporter: <your username> # item author username
description: |
In Gitlab 17.8, three new secrets have been added to support the upcoming encryption framework:
- `active_record_encryption_primary_key`
- `active_record_encryption_deterministic_key`
- `active_record_encryption_key_derivation_salt`
**If you have a multi-node configuration, you should ensure these secrets are the same on all nodes.** Otherwise, the application will automatically generate the missing secrets.
If you use the [GitLab helm chart](https://docs.gitlab.com/charts/) and disabled the [shared-secrets chart](https://docs.gitlab.com/charts/charts/shared-secrets/), you will need to [manually create these secrets](https://docs.gitlab.com/charts/installation/secrets.html#gitlab-rails-secret).
```
#### Mention the new secrets in the next Cloud Native GitLab charts upgrade notes
The new secrets should be mentioned in the current major release upgrade notes.
For instance, for 8.8, you should document the new secrets in <https://docs.gitlab.com/charts/releases/8_0.html>.
1. Mention the new secrets in the next Cloud Native GitLab charts upgrade notes.
For instance, for 8.8, you should document the new secrets in <https://docs.gitlab.com/charts/releases/8_0.html>.
## Further iteration

View File

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

View File

@ -91,7 +91,7 @@ To view the list of traces:
1. Select **Monitor > Traces**.
1. Optional. To view the details of a trace, select it from the list.
![list of traces](img/tracing_list_v16.11.png)
![list of traces](img/tracing_list_v16_11.png)
The trace details page and a list of spans are displayed.

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -96,12 +96,12 @@ To view the full timestamp of an error:
In the following example, the error happened at 11:41 CEST:
![MonitorDetailErrors](img/last_seen_v16.10.png)
![MonitorDetailErrors](img/last_seen_v16_10.png)
The **Last 24 hours** graph measures how many times this error occurred per hour.
By pointing at the `11 am` bar, the dialog shows the error was seen 239 times:
![MonitorDetailErrors](img/error_bucket_v16.10.png)
![MonitorDetailErrors](img/error_bucket_v16_10.png)
The **Last seen** field does not update until the full hour is complete, due to
the library used for the call

View File

@ -499,7 +499,7 @@ To resolve a vulnerability, you can either:
- [Resolve a vulnerability with a merge request](#resolve-a-vulnerability-with-a-merge-request).
- [Resolve a vulnerability manually](#resolve-a-vulnerability-manually).
![Create merge request from vulnerability](img/create_mr_from_vulnerability_v13_4_updated.png)
![Create merge request from vulnerability](img/create_mr_from_vulnerability_v13_4.png)
### Resolve a vulnerability with a merge request

View File

@ -444,8 +444,8 @@ Audit event types belong to the following product categories.
| Type name | Event triggered when | Saved to database | Introduced in | Scope |
|:----------|:---------------------|:------------------|:--------------|:------|
| [`package_registry_package_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178181) | A package was deleted from GitLab package registry. Available only when the feature flag `package_registry_audit_events` is enabled. | {{< icon name="check-circle" >}} Yes | GitLab [17.10](https://gitlab.com/gitlab-org/gitlab/-/issues/329588) | Project, Group |
| [`package_registry_package_published`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178181) | A package was published to GitLab package registry. Available only when the feature flag `package_registry_audit_events` is enabled. | {{< icon name="check-circle" >}} Yes | GitLab [17.9](https://gitlab.com/gitlab-org/gitlab/-/issues/329588) | Project, Group |
| [`package_registry_package_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178181) | A package was deleted from GitLab package registry. Available only when the feature flag `package_registry_audit_events` is enabled and the namespace's package setting `audit_events_enabled` is true. | {{< icon name="check-circle" >}} Yes | GitLab [17.10](https://gitlab.com/gitlab-org/gitlab/-/issues/329588) | Project, Group |
| [`package_registry_package_published`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178181) | A package was published to GitLab package registry. Available only when the feature flag `package_registry_audit_events` is enabled and the namespace's package setting `audit_events_enabled` is true. | {{< icon name="check-circle" >}} Yes | GitLab [17.9](https://gitlab.com/gitlab-org/gitlab/-/issues/329588) | Project, Group |
### Permissions

View File

@ -199,6 +199,28 @@ Several known issues exist when you allow anyone to pull from the package regist
- It does not work with the [Composer](../composer_repository/_index.md#install-a-composer-package), because Composer only has a group endpoint.
- It works with Conan, but using [`conan search`](../conan_repository/_index.md#search-for-conan-packages-in-the-package-registry) does not work.
## Audit events
{{< details >}}
- Tier: Premium, Ultimate
- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
{{< /details >}}
{{< history >}}
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/329588) in GitLab 17.10 [with a flag](../../../administration/feature_flags.md) named `package_registry_audit_events`. Disabled by default.
{{< /history >}}
Create audit events when a package is published or deleted. Namespace Owners can turn on the `audit_events_enabled` setting through the [GraphQl API](../../../api/graphql/reference/_index.md#packagesettings).
You can view audit events:
- On the [**Group audit events**](../../compliance/audit_events.md#group-audit-events) page if the package's project is in a group.
- On the [**Project audit events**](../../compliance/audit_events.md#project-audit-events) page if the package's project is in a user namespace.
## Accepting contributions
This table lists unsupported package manager formats that we are accepting contributions for.

View File

@ -0,0 +1,225 @@
---
stage: Package
group: Package Registry
info: For assistance with this tutorial, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects.
title: 'Tutorial: Structure the package registry for enterprise scale'
---
As your organization grows, package management can become increasingly complex.
The GitLab package registry model offers a powerful solution for enterprise package management.
Understanding how to leverage the package registry is important to working with packages securely, simply, and at scale.
In this tutorial, you'll learn how to incorporate the GitLab package registry model into an enterprise group structure. Although the examples provided here are specific to Maven and npm packages, you can extend the concepts of this tutorial to any package supported by the GitLab package registry.
When you finish this tutorial, you'll know how to:
1. [Set up a single root or **top-level group** to structure your work](#create-an-enterprise-structure).
1. [Configure projects for publishing packages with clear ownership](#set-up-a-top-level-group).
1. [Set up top-level group package consumption for simplified access](#publish-packages).
1. [Add deploy tokens so your team can access your organization's packages](#add-deploy-tokens).
1. [Configure CI/CD to work with your packages securely](#use-packages-with-cicd).
## Before you begin
You'll need the following to complete this tutorial:
- An npm or Maven package.
- Familiarity with the GitLab package registry.
- A test project. You can use an existing project, or create one for this tutorial.
## Understand the GitLab package registry
Traditional package managers like JFrog Artifactory and Sonatype Nexus use a single, centralized repository to store and update your packages.
With GitLab, you manage packages directly in your group or project. This means:
- Teams publish packages to projects that store code.
- Teams consume packages from root group registries that aggregate all packages below them.
- Access control is inherited from your existing GitLab permissions.
Because your packages are stored and managed like code, you can add package management to your existing projects or groups.
This model offers several advantages:
- Clear ownership of packages alongside their source code
- Granular access control without additional configuration
- Simplified CI/CD integration
- Natural alignment with team structures
- Single URL for accessing all company packages through root group consumption
## Create an enterprise structure
Consider organizing your code under a single top-level group. For example:
```plaintext
company/ (top-level group)
├── retail-division/
│ ├── shared-libraries/ # Division-specific shared code
│ └── teams/
│ ├── checkout/ # Team publishes packages here
│ └── inventory/ # Team publishes packages here
├── banking-division/
│ ├── shared-libraries/ # Division-specific shared code
│ └── teams/
│ ├── payments/ # Team publishes packages here
│ └── fraud/ # Team publishes packages here
└── shared-platform/ # Enterprise-wide shared code
├── java-commons/ # Shared Java libraries
└── ui-components/ # Shared UI components
```
In this structure, all the teams in a company publish code and packages to their own projects,
while inheriting the configurations of the top-level `company/` group.
## Set up a top-level group
You can use an existing top-level group if you have one, and you have the Owner role.
If you don't have a group, create one:
1. On the left sidebar, at the top, select **Create new** ({{< icon name="plus" >}}) and **New group**.
1. In **Group name**, enter a name for the group.
1. In **Group URL**, enter a path for the group, which is used as the namespace.
1. Choose the [visibility level](../../public_access.md).
1. Optional. Fill in information to personalize your experience.
1. Select **Create group**.
This group will store the other groups and projects in your organization. If you have other projects and groups, you can
[transfer them to the new top-level group](../../group/manage.md#transfer-a-group) for management.
Before you move on, make sure you have at least:
- A top-level group.
- A project that belongs to the top-level group or one of its subgroups.
## Publish packages
To maintain clear ownership, teams should publish packages to their own package registries.
This keeps packages with their source code and ensures version history is tied to project activity.
{{< tabs >}}
{{< tab title="Maven projects" >}}
To publish Maven packages:
- Configure your `pom.xml` file to publish to the project's package registry:
```xml
<!-- checkout/pom.xml -->
<distributionManagement>
<repository>
<id>gitlab-maven</id>
<url>${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/maven</url>
</repository>
</distributionManagement>
```
{{< /tab >}}
{{< tab title="npm projects" >}}
To publish npm packages:
- Configure your `package.json` file:
```json
// ui-components/package.json
{
"name": "@company/ui-components",
"publishConfig": {
"registry": "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/npm/"
}
}
```
{{< /tab >}}
{{< /tabs >}}
## Consume packages
Because your projects are organized under a single top-level group, your packages are still accessible to
the organization. Let's configure a single API endpoint for your teams to consume packages from.
{{< tabs >}}
{{< tab title="Maven projects" >}}
- Configure your `pom.xml` to access packages from the top-level group:
```xml
<!-- Any project's pom.xml -->
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab.example.com/api/v4/groups/company/-/packages/maven</url>
</repository>
</repositories>
```
{{< /tab >}}
{{< tab title="npm projects" >}}
- Configure your `.npmrc` file:
```shell
# Any project's .npmrc
@company:registry=https://gitlab.example.com/api/v4/groups/company/-/packages/npm/
```
{{< /tab >}}
{{< /tabs >}}
This configuration automatically provides access to all packages across your organization while maintaining the benefits of project-based publishing.
## Add deploy tokens
Next, we'll add a read-only deploy token. This token provides access to the packages stored in the subgroups and projects of the organization,
so your teams can use them for development.
1. In your top-level group, on the left sidebar, select **Settings > Repository**.
1. Expand **Deploy tokens**.
1. Select **Add token**.
1. Complete the fields, and set the scope to `read_repository`.
1. Select **Create deploy token**.
You can add as many deploy tokens to your top-level group as you need.
Remember to rotate your tokens periodically. If you suspect a token has been exposed, revoke and replace it immediately.
## Use packages with CI/CD
When CI/CD jobs need to access the package registry, they authenticate with the predefined CI/CD variable
`CI_JOB_TOKEN`. This authentication happens automatically, so you don't need to do any extra configuration:
```yaml
publish:
script:
- mvn deploy # For Maven packages
# or
- npm publish # For npm packages
# CI_JOB_TOKEN provides automatic authentication
```
## Summary and next steps
Organizing your GitLab projects under one top-level group confers several benfits:
- **Simplified configuration**
- One URL for all package access
- Consistent setup across teams
- Easy token rotation
- **Clear ownership**
- Packages stay with their source code
- Teams maintain control over publishing
- Version history is tied to project activity
- **Natural organization**
- Your groups match your company structure
- Teams can collaborate while remaining autonomous
The GitLab package registry model offers a powerful solution for enterprise package management. By combining project-based publishing with top-level group consumption,
you get the best of both worlds: clear ownership and simplified access.
This approach scales naturally with your organization while maintaining security and ease of use.
Start by implementing this model with a single team or division, and expand as you see the benefits of this integrated approach.
Remember that while this tutorial focused on Maven and npm, the same principles apply to all package types supported by GitLab.

View File

@ -104,7 +104,7 @@ When you select a description template, its content is copied to the description
To discard any changes to the description you've made after selecting the template: expand the **Choose a template** dropdown list and select **Reset template**.
![Choosing a description template in an issue](img/description_templates_v17-10.png)
![Choosing a description template in an issue](img/description_templates_v17_10.png)
{{< alert type="note" >}}

Some files were not shown because too many files have changed in this diff Show More