Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
fdc5ce9759
commit
6200f12079
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
# Cop supports --autocorrect.
|
||||
Lint/RedundantSafeNavigation:
|
||||
Exclude:
|
||||
- 'app/presenters/packages/nuget/version_helpers.rb'
|
||||
- 'lib/gitlab/ci/jwt_v2/claim_mapper.rb'
|
||||
- 'lib/security/ci_configuration/sast_build_action.rb'
|
||||
2
Gemfile
2
Gemfile
|
|
@ -480,7 +480,7 @@ group :development do
|
|||
|
||||
gem 'listen', '~> 3.7' # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
|
||||
gem 'ruby-lsp', "~> 0.19.0", require: false, feature_category: :tooling
|
||||
gem 'ruby-lsp', "~> 0.21.0", require: false, feature_category: :tooling
|
||||
|
||||
gem 'ruby-lsp-rails', "~> 0.3.6", feature_category: :tooling
|
||||
|
||||
|
|
|
|||
|
|
@ -510,7 +510,7 @@
|
|||
{"name":"premailer","version":"1.23.0","platform":"ruby","checksum":"f0d7f6ba299559c96ddf982aa5263f85e5617c86437c8d8ffff120813b2d7efb"},
|
||||
{"name":"premailer-rails","version":"1.12.0","platform":"ruby","checksum":"c13815d161b9bc7f7d3d81396b0bb0a61a90fa9bd89931548bf4e537c7710400"},
|
||||
{"name":"prime","version":"0.1.2","platform":"ruby","checksum":"d4e956cadfaf04de036dc7dc74f95bf6a285a62cc509b28b7a66b245d19fe3a4"},
|
||||
{"name":"prism","version":"1.1.0","platform":"ruby","checksum":"45f0d269eb09d0e2d9380fe41a96955386f7990c8e8d65de64a0b6a5a6be9b7b"},
|
||||
{"name":"prism","version":"1.2.0","platform":"ruby","checksum":"24ff9cd3232346e68052659f14c9a618022ea98935f774df465206aba5c06d2f"},
|
||||
{"name":"proc_to_ast","version":"0.1.0","platform":"ruby","checksum":"92a73fa66e2250a83f8589f818b0751bcf227c68f85916202df7af85082f8691"},
|
||||
{"name":"prometheus-client-mmap","version":"1.1.1","platform":"aarch64-linux","checksum":"35fd23296854a1888c58198cc5776a99e5f5a729bc4262327cd1c44219e7dda2"},
|
||||
{"name":"prometheus-client-mmap","version":"1.1.1","platform":"arm64-darwin","checksum":"1fc09a3f76cb3c69fde085dc63a986524e2606b2e36cc64122b49836ee6b1779"},
|
||||
|
|
@ -550,7 +550,7 @@
|
|||
{"name":"rb-fsevent","version":"0.11.2","platform":"ruby","checksum":"43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe"},
|
||||
{"name":"rb-inotify","version":"0.10.1","platform":"ruby","checksum":"050062d4f31d307cca52c3f6a7f4b946df8de25fc4bd373e1a5142e41034a7ca"},
|
||||
{"name":"rb_sys","version":"0.9.94","platform":"ruby","checksum":"8a35bed8e7906867b958be58772c779fc4afacacc86ceab921149cccb9eb4cca"},
|
||||
{"name":"rbs","version":"3.5.1","platform":"ruby","checksum":"8ed89f6b088796e67ebc88141eb5b0f1a61a6a76cb63a499fdf119c58219cbae"},
|
||||
{"name":"rbs","version":"3.6.1","platform":"ruby","checksum":"ed7273d018556844583d1785ac54194e67eec594d68e317d57fa90ad035532c0"},
|
||||
{"name":"rbtrace","version":"0.5.1","platform":"ruby","checksum":"e8cba64d462bfb8ba102d7be2ecaacc789247d52ac587d8003549d909cb9c5dc"},
|
||||
{"name":"rchardet","version":"1.8.0","platform":"ruby","checksum":"693acd5253d5ade81a51940697955f6dd4bb2f0d245bda76a8e23deec70a52c7"},
|
||||
{"name":"re2","version":"2.7.0","platform":"aarch64-linux","checksum":"778921298b6e8aba26a6230dd298c9b361b92e45024f81fa6aee788060fa307c"},
|
||||
|
|
@ -615,9 +615,9 @@
|
|||
{"name":"rubocop-rspec","version":"3.0.5","platform":"ruby","checksum":"c6a8e29fb1b00d227c32df159e92f5ebb9e0ff734e52955fb13aff5c74977e0f"},
|
||||
{"name":"rubocop-rspec_rails","version":"2.30.0","platform":"ruby","checksum":"888112e83f9d7ef7ad2397e9d69a0b9614a4bae24f072c399804a180f80c4c46"},
|
||||
{"name":"ruby-fogbugz","version":"0.3.0","platform":"ruby","checksum":"5e04cde474648f498a71cf1e1a7ab42c66b953862fbe224f793ec0a7a1d5f657"},
|
||||
{"name":"ruby-lsp","version":"0.19.1","platform":"ruby","checksum":"d013f937a6a3e03f19026c5234d7f22f219e45f3fdb39a80a3e816b0a2148ced"},
|
||||
{"name":"ruby-lsp-rails","version":"0.3.17","platform":"ruby","checksum":"24e80e313b2a8990e1fe37a4165b3877b3b587ef1de931ae89338512502d1fd1"},
|
||||
{"name":"ruby-lsp-rspec","version":"0.1.15","platform":"ruby","checksum":"d1eed4aa9d16f41ab04943ca881f7ce5389958fb8c88da2d3a1df9cefdffbd9d"},
|
||||
{"name":"ruby-lsp","version":"0.21.3","platform":"ruby","checksum":"51c4e327740ce2f09e59e241fe6e67242ba8fc6fb200dddfedd4cb57d9dd5ec1"},
|
||||
{"name":"ruby-lsp-rails","version":"0.3.26","platform":"ruby","checksum":"f58e92c17a78a7df27bd563b32cc1557400fcd5e7f1d0c782ca272b9b34b6351"},
|
||||
{"name":"ruby-lsp-rspec","version":"0.1.18","platform":"ruby","checksum":"4e6e892f52eb4f548cb43e61c59de43bcc9d785f588f137e61601bb7271dc461"},
|
||||
{"name":"ruby-magic","version":"0.6.0","platform":"ruby","checksum":"7b2138877b7d23aff812c95564eba6473b74b815ef85beb0eb792e729a2b6101"},
|
||||
{"name":"ruby-openai","version":"3.7.0","platform":"ruby","checksum":"fb735d4c055e282ade264cab9864944c05a8a10e0cddd45a0551e8a9851b1850"},
|
||||
{"name":"ruby-progressbar","version":"1.11.0","platform":"ruby","checksum":"cc127db3866dc414ffccbf92928a241e585b3aa2b758a5563e74a6ee0f57d50a"},
|
||||
|
|
@ -684,7 +684,7 @@
|
|||
{"name":"snaky_hash","version":"2.0.0","platform":"ruby","checksum":"fe8b2e39e8ff69320f7812af73ea06401579e29ff1734a7009567391600687de"},
|
||||
{"name":"snowplow-tracker","version":"0.8.0","platform":"ruby","checksum":"7ba6f4f1443a829845fd28e63eda72d9d3d247f485310ddcccaebbc52b734a38"},
|
||||
{"name":"solargraph","version":"0.47.2","platform":"ruby","checksum":"87ca4b799b9155c2c31c15954c483e952fdacd800f52d6709b901dd447bcac6a"},
|
||||
{"name":"sorbet-runtime","version":"0.5.11266","platform":"ruby","checksum":"deb2c3054811fbcce0a888682d820f691895b84e3d8ac7bc7959e988ca0c58bb"},
|
||||
{"name":"sorbet-runtime","version":"0.5.11647","platform":"ruby","checksum":"64b65112f2e6a5323310ca9ac0d7d9a6be63aade5a62a6225fe066042ff4fdb6"},
|
||||
{"name":"spamcheck","version":"1.3.0","platform":"ruby","checksum":"a46082752257838d8484c844736e309ec499f85dcc51283a5f973b33f1c994f5"},
|
||||
{"name":"spring","version":"4.1.0","platform":"ruby","checksum":"f17f080fb0df558d663c897a6229ed3d5cc54819ab51876ea6eef49a67f0a3cb"},
|
||||
{"name":"spring-commands-rspec","version":"1.0.4","platform":"ruby","checksum":"6202e54fa4767452e3641461a83347645af478bf45dddcca9737b43af0dd1a2c"},
|
||||
|
|
|
|||
20
Gemfile.lock
20
Gemfile.lock
|
|
@ -1431,7 +1431,7 @@ GEM
|
|||
prime (0.1.2)
|
||||
forwardable
|
||||
singleton
|
||||
prism (1.1.0)
|
||||
prism (1.2.0)
|
||||
proc_to_ast (0.1.0)
|
||||
coderay
|
||||
parser
|
||||
|
|
@ -1519,7 +1519,7 @@ GEM
|
|||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rb_sys (0.9.94)
|
||||
rbs (3.5.1)
|
||||
rbs (3.6.1)
|
||||
logger
|
||||
rbtrace (0.5.1)
|
||||
ffi (>= 1.0.6)
|
||||
|
|
@ -1658,15 +1658,15 @@ GEM
|
|||
ruby-fogbugz (0.3.0)
|
||||
crack (~> 0.4)
|
||||
multipart-post (~> 2.0)
|
||||
ruby-lsp (0.19.1)
|
||||
ruby-lsp (0.21.3)
|
||||
language_server-protocol (~> 3.17.0)
|
||||
prism (>= 1.1, < 2.0)
|
||||
prism (>= 1.2, < 2.0)
|
||||
rbs (>= 3, < 4)
|
||||
sorbet-runtime (>= 0.5.10782)
|
||||
ruby-lsp-rails (0.3.17)
|
||||
ruby-lsp (>= 0.19.0, < 0.20.0)
|
||||
ruby-lsp-rspec (0.1.15)
|
||||
ruby-lsp (~> 0.19.0)
|
||||
ruby-lsp-rails (0.3.26)
|
||||
ruby-lsp (>= 0.21.2, < 0.22.0)
|
||||
ruby-lsp-rspec (0.1.18)
|
||||
ruby-lsp (~> 0.21.0)
|
||||
ruby-magic (0.6.0)
|
||||
mini_portile2 (~> 2.8)
|
||||
ruby-openai (3.7.0)
|
||||
|
|
@ -1765,7 +1765,7 @@ GEM
|
|||
thor (~> 1.0)
|
||||
tilt (~> 2.0)
|
||||
yard (~> 0.9, >= 0.9.24)
|
||||
sorbet-runtime (0.5.11266)
|
||||
sorbet-runtime (0.5.11647)
|
||||
spamcheck (1.3.0)
|
||||
grpc (~> 1.0)
|
||||
spring (4.1.0)
|
||||
|
|
@ -2262,7 +2262,7 @@ DEPENDENCIES
|
|||
rspec_profiling (~> 0.0.9)
|
||||
rubocop
|
||||
ruby-fogbugz (~> 0.3.0)
|
||||
ruby-lsp (~> 0.19.0)
|
||||
ruby-lsp (~> 0.21.0)
|
||||
ruby-lsp-rails (~> 0.3.6)
|
||||
ruby-lsp-rspec (~> 0.1.10)
|
||||
ruby-magic (~> 0.6)
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@
|
|||
{"name":"premailer","version":"1.23.0","platform":"ruby","checksum":"f0d7f6ba299559c96ddf982aa5263f85e5617c86437c8d8ffff120813b2d7efb"},
|
||||
{"name":"premailer-rails","version":"1.12.0","platform":"ruby","checksum":"c13815d161b9bc7f7d3d81396b0bb0a61a90fa9bd89931548bf4e537c7710400"},
|
||||
{"name":"prime","version":"0.1.2","platform":"ruby","checksum":"d4e956cadfaf04de036dc7dc74f95bf6a285a62cc509b28b7a66b245d19fe3a4"},
|
||||
{"name":"prism","version":"1.1.0","platform":"ruby","checksum":"45f0d269eb09d0e2d9380fe41a96955386f7990c8e8d65de64a0b6a5a6be9b7b"},
|
||||
{"name":"prism","version":"1.2.0","platform":"ruby","checksum":"24ff9cd3232346e68052659f14c9a618022ea98935f774df465206aba5c06d2f"},
|
||||
{"name":"proc_to_ast","version":"0.1.0","platform":"ruby","checksum":"92a73fa66e2250a83f8589f818b0751bcf227c68f85916202df7af85082f8691"},
|
||||
{"name":"prometheus-client-mmap","version":"1.1.1","platform":"aarch64-linux","checksum":"35fd23296854a1888c58198cc5776a99e5f5a729bc4262327cd1c44219e7dda2"},
|
||||
{"name":"prometheus-client-mmap","version":"1.1.1","platform":"arm64-darwin","checksum":"1fc09a3f76cb3c69fde085dc63a986524e2606b2e36cc64122b49836ee6b1779"},
|
||||
|
|
@ -561,10 +561,10 @@
|
|||
{"name":"rb-fsevent","version":"0.11.2","platform":"ruby","checksum":"43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe"},
|
||||
{"name":"rb-inotify","version":"0.10.1","platform":"ruby","checksum":"050062d4f31d307cca52c3f6a7f4b946df8de25fc4bd373e1a5142e41034a7ca"},
|
||||
{"name":"rb_sys","version":"0.9.94","platform":"ruby","checksum":"8a35bed8e7906867b958be58772c779fc4afacacc86ceab921149cccb9eb4cca"},
|
||||
{"name":"rbs","version":"3.5.1","platform":"ruby","checksum":"8ed89f6b088796e67ebc88141eb5b0f1a61a6a76cb63a499fdf119c58219cbae"},
|
||||
{"name":"rbs","version":"3.6.1","platform":"ruby","checksum":"ed7273d018556844583d1785ac54194e67eec594d68e317d57fa90ad035532c0"},
|
||||
{"name":"rbtrace","version":"0.5.1","platform":"ruby","checksum":"e8cba64d462bfb8ba102d7be2ecaacc789247d52ac587d8003549d909cb9c5dc"},
|
||||
{"name":"rchardet","version":"1.8.0","platform":"ruby","checksum":"693acd5253d5ade81a51940697955f6dd4bb2f0d245bda76a8e23deec70a52c7"},
|
||||
{"name":"rdoc","version":"6.7.0","platform":"ruby","checksum":"b17d5f0f57b0853d7b880d4360a32c7caf8dbb81f8503a36426df809e617f379"},
|
||||
{"name":"rdoc","version":"6.8.1","platform":"ruby","checksum":"0128002d1bfc4892bdd780940841e4ca41275f63781fd832d11bc8ba4461462c"},
|
||||
{"name":"re2","version":"2.7.0","platform":"aarch64-linux","checksum":"778921298b6e8aba26a6230dd298c9b361b92e45024f81fa6aee788060fa307c"},
|
||||
{"name":"re2","version":"2.7.0","platform":"arm-linux","checksum":"d328b5286d83ae265e13b855da8e348a976f80f91b748045b52073a570577954"},
|
||||
{"name":"re2","version":"2.7.0","platform":"arm64-darwin","checksum":"7d993f27a1afac4001c539a829e2af211ced62604930c90df32a307cf74cb4a4"},
|
||||
|
|
@ -628,9 +628,9 @@
|
|||
{"name":"rubocop-rspec","version":"3.0.5","platform":"ruby","checksum":"c6a8e29fb1b00d227c32df159e92f5ebb9e0ff734e52955fb13aff5c74977e0f"},
|
||||
{"name":"rubocop-rspec_rails","version":"2.30.0","platform":"ruby","checksum":"888112e83f9d7ef7ad2397e9d69a0b9614a4bae24f072c399804a180f80c4c46"},
|
||||
{"name":"ruby-fogbugz","version":"0.3.0","platform":"ruby","checksum":"5e04cde474648f498a71cf1e1a7ab42c66b953862fbe224f793ec0a7a1d5f657"},
|
||||
{"name":"ruby-lsp","version":"0.19.1","platform":"ruby","checksum":"d013f937a6a3e03f19026c5234d7f22f219e45f3fdb39a80a3e816b0a2148ced"},
|
||||
{"name":"ruby-lsp-rails","version":"0.3.17","platform":"ruby","checksum":"24e80e313b2a8990e1fe37a4165b3877b3b587ef1de931ae89338512502d1fd1"},
|
||||
{"name":"ruby-lsp-rspec","version":"0.1.15","platform":"ruby","checksum":"d1eed4aa9d16f41ab04943ca881f7ce5389958fb8c88da2d3a1df9cefdffbd9d"},
|
||||
{"name":"ruby-lsp","version":"0.21.3","platform":"ruby","checksum":"51c4e327740ce2f09e59e241fe6e67242ba8fc6fb200dddfedd4cb57d9dd5ec1"},
|
||||
{"name":"ruby-lsp-rails","version":"0.3.26","platform":"ruby","checksum":"f58e92c17a78a7df27bd563b32cc1557400fcd5e7f1d0c782ca272b9b34b6351"},
|
||||
{"name":"ruby-lsp-rspec","version":"0.1.18","platform":"ruby","checksum":"4e6e892f52eb4f548cb43e61c59de43bcc9d785f588f137e61601bb7271dc461"},
|
||||
{"name":"ruby-magic","version":"0.6.0","platform":"ruby","checksum":"7b2138877b7d23aff812c95564eba6473b74b815ef85beb0eb792e729a2b6101"},
|
||||
{"name":"ruby-openai","version":"3.7.0","platform":"ruby","checksum":"fb735d4c055e282ade264cab9864944c05a8a10e0cddd45a0551e8a9851b1850"},
|
||||
{"name":"ruby-progressbar","version":"1.11.0","platform":"ruby","checksum":"cc127db3866dc414ffccbf92928a241e585b3aa2b758a5563e74a6ee0f57d50a"},
|
||||
|
|
@ -697,7 +697,7 @@
|
|||
{"name":"snaky_hash","version":"2.0.0","platform":"ruby","checksum":"fe8b2e39e8ff69320f7812af73ea06401579e29ff1734a7009567391600687de"},
|
||||
{"name":"snowplow-tracker","version":"0.8.0","platform":"ruby","checksum":"7ba6f4f1443a829845fd28e63eda72d9d3d247f485310ddcccaebbc52b734a38"},
|
||||
{"name":"solargraph","version":"0.47.2","platform":"ruby","checksum":"87ca4b799b9155c2c31c15954c483e952fdacd800f52d6709b901dd447bcac6a"},
|
||||
{"name":"sorbet-runtime","version":"0.5.11266","platform":"ruby","checksum":"deb2c3054811fbcce0a888682d820f691895b84e3d8ac7bc7959e988ca0c58bb"},
|
||||
{"name":"sorbet-runtime","version":"0.5.11647","platform":"ruby","checksum":"64b65112f2e6a5323310ca9ac0d7d9a6be63aade5a62a6225fe066042ff4fdb6"},
|
||||
{"name":"spamcheck","version":"1.3.0","platform":"ruby","checksum":"a46082752257838d8484c844736e309ec499f85dcc51283a5f973b33f1c994f5"},
|
||||
{"name":"spring","version":"4.1.0","platform":"ruby","checksum":"f17f080fb0df558d663c897a6229ed3d5cc54819ab51876ea6eef49a67f0a3cb"},
|
||||
{"name":"spring-commands-rspec","version":"1.0.4","platform":"ruby","checksum":"6202e54fa4767452e3641461a83347645af478bf45dddcca9737b43af0dd1a2c"},
|
||||
|
|
|
|||
|
|
@ -1446,7 +1446,7 @@ GEM
|
|||
prime (0.1.2)
|
||||
forwardable
|
||||
singleton
|
||||
prism (1.1.0)
|
||||
prism (1.2.0)
|
||||
proc_to_ast (0.1.0)
|
||||
coderay
|
||||
parser
|
||||
|
|
@ -1541,14 +1541,14 @@ GEM
|
|||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rb_sys (0.9.94)
|
||||
rbs (3.5.1)
|
||||
rbs (3.6.1)
|
||||
logger
|
||||
rbtrace (0.5.1)
|
||||
ffi (>= 1.0.6)
|
||||
msgpack (>= 0.4.3)
|
||||
optimist (>= 3.0.0)
|
||||
rchardet (1.8.0)
|
||||
rdoc (6.7.0)
|
||||
rdoc (6.8.1)
|
||||
psych (>= 4.0.0)
|
||||
re2 (2.7.0)
|
||||
mini_portile2 (~> 2.8.5)
|
||||
|
|
@ -1684,15 +1684,15 @@ GEM
|
|||
ruby-fogbugz (0.3.0)
|
||||
crack (~> 0.4)
|
||||
multipart-post (~> 2.0)
|
||||
ruby-lsp (0.19.1)
|
||||
ruby-lsp (0.21.3)
|
||||
language_server-protocol (~> 3.17.0)
|
||||
prism (>= 1.1, < 2.0)
|
||||
prism (>= 1.2, < 2.0)
|
||||
rbs (>= 3, < 4)
|
||||
sorbet-runtime (>= 0.5.10782)
|
||||
ruby-lsp-rails (0.3.17)
|
||||
ruby-lsp (>= 0.19.0, < 0.20.0)
|
||||
ruby-lsp-rspec (0.1.15)
|
||||
ruby-lsp (~> 0.19.0)
|
||||
ruby-lsp-rails (0.3.26)
|
||||
ruby-lsp (>= 0.21.2, < 0.22.0)
|
||||
ruby-lsp-rspec (0.1.18)
|
||||
ruby-lsp (~> 0.21.0)
|
||||
ruby-magic (0.6.0)
|
||||
mini_portile2 (~> 2.8)
|
||||
ruby-openai (3.7.0)
|
||||
|
|
@ -1791,7 +1791,7 @@ GEM
|
|||
thor (~> 1.0)
|
||||
tilt (~> 2.0)
|
||||
yard (~> 0.9, >= 0.9.24)
|
||||
sorbet-runtime (0.5.11266)
|
||||
sorbet-runtime (0.5.11647)
|
||||
spamcheck (1.3.0)
|
||||
grpc (~> 1.0)
|
||||
spring (4.1.0)
|
||||
|
|
@ -2289,7 +2289,7 @@ DEPENDENCIES
|
|||
rspec_profiling (~> 0.0.9)
|
||||
rubocop
|
||||
ruby-fogbugz (~> 0.3.0)
|
||||
ruby-lsp (~> 0.19.0)
|
||||
ruby-lsp (~> 0.21.0)
|
||||
ruby-lsp-rails (~> 0.3.6)
|
||||
ruby-lsp-rspec (~> 0.1.10)
|
||||
ruby-magic (~> 0.6)
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ export const DEFAULT_FIELDS = [
|
|||
export const JOBS_DEFAULT_FIELDS = DEFAULT_FIELDS.filter((field) => field.key !== 'stage');
|
||||
export const JOBS_TAB_FIELDS = DEFAULT_FIELDS.filter((field) => field.key !== 'pipeline');
|
||||
|
||||
export const POLL_INTERVAL = 10000;
|
||||
export const JOBS_PER_PAGE = 30;
|
||||
export const DEFAULT_PAGINATION = {
|
||||
first: JOBS_PER_PAGE,
|
||||
|
|
|
|||
|
|
@ -19,14 +19,8 @@ export default (containerId = 'js-jobs-table') => {
|
|||
return false;
|
||||
}
|
||||
|
||||
const {
|
||||
fullPath,
|
||||
jobStatuses,
|
||||
pipelineEditorPath,
|
||||
emptyStateSvgPath,
|
||||
admin,
|
||||
graphqlResourceEtag,
|
||||
} = containerEl.dataset;
|
||||
const { fullPath, jobStatuses, pipelineEditorPath, emptyStateSvgPath, admin } =
|
||||
containerEl.dataset;
|
||||
|
||||
return new Vue({
|
||||
el: containerEl,
|
||||
|
|
@ -37,7 +31,6 @@ export default (containerId = 'js-jobs-table') => {
|
|||
pipelineEditorPath,
|
||||
jobStatuses: JSON.parse(jobStatuses),
|
||||
admin: parseBoolean(admin),
|
||||
graphqlResourceEtag,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(JobsTableApp);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import { GlAlert, GlKeysetPagination } from '@gitlab/ui';
|
||||
import { toggleQueryPollingByVisibility, etagQueryHeaders } from '~/graphql_shared/utils';
|
||||
import { __ } from '~/locale';
|
||||
import { createAlert } from '~/alert';
|
||||
import { setUrlParams, updateHistory, queryToObject } from '~/lib/utils/url_utility';
|
||||
|
|
@ -14,7 +13,7 @@ import GetJobsCount from './graphql/queries/get_jobs_count.query.graphql';
|
|||
import JobsTable from './components/jobs_table.vue';
|
||||
import JobsTableEmptyState from './components/jobs_table_empty_state.vue';
|
||||
import JobsTableTabs from './components/jobs_table_tabs.vue';
|
||||
import { RAW_TEXT_WARNING, DEFAULT_PAGINATION, JOBS_PER_PAGE, POLL_INTERVAL } from './constants';
|
||||
import { RAW_TEXT_WARNING, DEFAULT_PAGINATION, JOBS_PER_PAGE } from './constants';
|
||||
|
||||
export default {
|
||||
name: 'JobsPageApp',
|
||||
|
|
@ -35,13 +34,10 @@ export default {
|
|||
JobsSkeletonLoader,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
inject: ['fullPath', 'graphqlResourceEtag'],
|
||||
inject: ['fullPath'],
|
||||
apollo: {
|
||||
jobs: {
|
||||
query: GetJobs,
|
||||
context() {
|
||||
return etagQueryHeaders('jobs_table', this.graphqlResourceEtag);
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.fullPath,
|
||||
|
|
@ -60,13 +56,9 @@ export default {
|
|||
this.error = this.$options.i18n.jobsFetchErrorMsg;
|
||||
reportToSentry(this.$options.name, error);
|
||||
},
|
||||
pollInterval: POLL_INTERVAL,
|
||||
},
|
||||
jobsCount: {
|
||||
query: GetJobsCount,
|
||||
context() {
|
||||
return etagQueryHeaders('jobs_table', this.graphqlResourceEtag);
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.fullPath,
|
||||
|
|
@ -80,7 +72,6 @@ export default {
|
|||
this.error = this.$options.i18n.jobsCountErrorMsg;
|
||||
reportToSentry(this.$options.name, error);
|
||||
},
|
||||
pollInterval: POLL_INTERVAL,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
|
@ -138,10 +129,6 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
toggleQueryPollingByVisibility(this.$apollo.queries.jobs);
|
||||
toggleQueryPollingByVisibility(this.$apollo.queries.jobsCount);
|
||||
},
|
||||
methods: {
|
||||
resetRequestData() {
|
||||
if (this.glFeatures.populateAndUseBuildNamesTable) {
|
||||
|
|
|
|||
|
|
@ -13,9 +13,5 @@ module Routing
|
|||
def graphql_etag_project_on_demand_scan_counts_path(project)
|
||||
[api_graphql_path, "on_demand_scan/counts/#{project.full_path}"].join(':')
|
||||
end
|
||||
|
||||
def graphql_etag_jobs_path(project)
|
||||
[api_graphql_path, "projects/#{project.full_path}/jobs"].join(':')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1702,17 +1702,6 @@ class MergeRequest < ApplicationRecord
|
|||
has_ci? || project.has_ci?
|
||||
end
|
||||
|
||||
def mergeable_ci_state?
|
||||
# When using MWCP auto merge strategy, the ci must be mergeable, regardless of the project setting
|
||||
return true unless only_allow_merge_if_pipeline_succeeds? || (auto_merge_strategy == ::AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS && has_ci_enabled?)
|
||||
return false unless diff_head_pipeline
|
||||
return false if pipeline_creating?
|
||||
|
||||
return true if project.allow_merge_on_skipped_pipeline?(inherit_group_setting: true) && diff_head_pipeline.skipped?
|
||||
|
||||
diff_head_pipeline.success?
|
||||
end
|
||||
|
||||
def environments_in_head_pipeline(deployment_status: nil)
|
||||
diff_head_pipeline&.environments_in_self_and_project_descendants(deployment_status: deployment_status) || Environment.none
|
||||
end
|
||||
|
|
@ -2437,10 +2426,6 @@ class MergeRequest < ApplicationRecord
|
|||
)
|
||||
end
|
||||
|
||||
def pipeline_creating?
|
||||
Ci::PipelineCreation::Requests.pipeline_creating_for_merge_request?(self)
|
||||
end
|
||||
|
||||
def merge_base_pipelines
|
||||
return ::Ci::Pipeline.none unless diff_head_pipeline&.target_sha
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ module Packages
|
|||
|
||||
def compare_core_parts(a_core_parts, b_core_parts)
|
||||
while a_core_parts.any? || b_core_parts.any?
|
||||
a_part = a_core_parts.shift&.to_i || 0
|
||||
b_part = b_core_parts.shift&.to_i || 0
|
||||
a_part = a_core_parts.shift.to_i
|
||||
b_part = b_core_parts.shift.to_i
|
||||
return a_part <=> b_part if a_part != b_part
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,9 +7,10 @@ module MergeRequests
|
|||
description 'Checks whether CI has passed'
|
||||
|
||||
def execute
|
||||
return inactive unless merge_request.auto_merge_enabled? || merge_request.only_allow_merge_if_pipeline_succeeds?
|
||||
return inactive unless merge_request.auto_merge_enabled? ||
|
||||
merge_request.only_allow_merge_if_pipeline_succeeds?
|
||||
|
||||
if merge_request.mergeable_ci_state?
|
||||
if mergeable_ci_state?
|
||||
success
|
||||
else
|
||||
failure
|
||||
|
|
@ -23,6 +24,32 @@ module MergeRequests
|
|||
def cacheable?
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def mergeable_ci_state?
|
||||
return true unless pipeline_must_succeed?
|
||||
return false unless merge_request.diff_head_pipeline
|
||||
return false if pipeline_creating?
|
||||
return true if can_skip_diff_head_pipeline?
|
||||
|
||||
merge_request.diff_head_pipeline.success?
|
||||
end
|
||||
|
||||
def pipeline_creating?
|
||||
Ci::PipelineCreation::Requests.pipeline_creating_for_merge_request?(merge_request)
|
||||
end
|
||||
|
||||
def pipeline_must_succeed?
|
||||
merge_request.only_allow_merge_if_pipeline_succeeds? ||
|
||||
(merge_request.auto_merge_strategy == ::AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS &&
|
||||
merge_request.has_ci_enabled?)
|
||||
end
|
||||
|
||||
def can_skip_diff_head_pipeline?
|
||||
merge_request.project.allow_merge_on_skipped_pipeline?(inherit_group_setting: true) &&
|
||||
merge_request.diff_head_pipeline.skipped?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@
|
|||
- add_page_specific_style 'page_bundles/merge_request'
|
||||
- admin = local_assigns.fetch(:admin, false)
|
||||
|
||||
#js-jobs-table{ data: { admin: admin, full_path: @project.full_path, job_statuses: job_statuses.to_json, pipeline_editor_path: project_ci_pipeline_editor_path(@project), empty_state_svg_path: image_path('illustrations/empty-state/empty-pipeline-md.svg'), graphql_resource_etag: graphql_etag_jobs_path(@project) } }
|
||||
#js-jobs-table{ data: { admin: admin, full_path: @project.full_path, job_statuses: job_statuses.to_json, pipeline_editor_path: project_ci_pipeline_editor_path(@project), empty_state_svg_path: image_path('illustrations/empty-state/empty-pipeline-md.svg') } }
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142339
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/440185
|
||||
milestone: '17.0'
|
||||
type: development
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: prompt_migration_ci_editor_assistant
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/475051
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/167401
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/issues/595
|
||||
milestone: '17.6'
|
||||
group: group::custom models
|
||||
type: experiment
|
||||
default_enabled: false
|
||||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93179
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369441
|
||||
milestone: '15.3'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76509
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347151
|
||||
milestone: '14.10'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/435848
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161075
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/474908
|
||||
milestone: '17.3'
|
||||
group: group::pipeline execution
|
||||
group: group::pipeline security
|
||||
type: ops
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124112
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415503
|
||||
milestone: '16.2'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/435051
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/140318
|
||||
rollout_issue_url:
|
||||
milestone: '16.7'
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
type: ops
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124112
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415503
|
||||
milestone: '16.2'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124112
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415503
|
||||
milestone: '16.2'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84701
|
|||
rollout_issue_url:
|
||||
milestone: '15.1'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84701
|
|||
rollout_issue_url:
|
||||
milestone: '15.8'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84701
|
|||
rollout_issue_url:
|
||||
milestone: '15.8'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50922
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/296772
|
||||
milestone: '13.8'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111147
|
|||
rollout_issue_url:
|
||||
milestone: '15.9'
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -11,9 +11,15 @@
|
|||
- major: 9
|
||||
minor: 5
|
||||
|
||||
- major: 10
|
||||
minor: 0
|
||||
|
||||
- major: 10
|
||||
minor: 8
|
||||
|
||||
- major: 11
|
||||
minor: 0
|
||||
|
||||
- major: 11
|
||||
minor: 11
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ feature_category: infrastructure_as_code
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/155438
|
||||
milestone: '17.1'
|
||||
queued_migration_version: 20240605132810
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
finalized_by: '20241118232838'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
migration_job_name: BackfillVulnerabilityNamespaceHistoricalStatistics
|
||||
description: Fills historical vulnerability statistics data aggregated by namespace and traversal ids
|
||||
feature_category: vulnerability_management
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/165928
|
||||
milestone: '17.7'
|
||||
queued_migration_version: 20241113144244
|
||||
|
|
@ -12,6 +12,9 @@ class AddPersonalNamespaceIdToEvents2 < Gitlab::Database::Migration[2.2]
|
|||
return if column_exists?(:events, :personal_namespace_id)
|
||||
|
||||
with_lock_retries(raise_on_exhaustion: true) do
|
||||
# Doing DDL in post-deployment migration is discouraged in general,
|
||||
# this is done as a workaround to prevent production incidents when
|
||||
# changing the schema for very high-traffic table
|
||||
add_column :events, :personal_namespace_id, :bigint
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class QueueBackfillVulnerabilityNamespaceHistoricalStatistics < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.7'
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_sec
|
||||
|
||||
MIGRATION = "BackfillVulnerabilityNamespaceHistoricalStatistics"
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 5000
|
||||
SUB_BATCH_SIZE = 500
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:vulnerability_historical_statistics,
|
||||
:id,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
delete_batched_background_migration(MIGRATION, :vulnerability_historical_statistics, :id, [])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeBackfillTerraformStateVersionsProjectId < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.6'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'BackfillTerraformStateVersionsProjectId',
|
||||
table_name: :terraform_state_versions,
|
||||
column_name: :id,
|
||||
job_arguments: [:project_id, :terraform_states, :project_id, :terraform_state_id],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
6ba2138029af433b964e5c729c3f2a8a606ae6183402f5c9f2ba9779e2fb84f2
|
||||
|
|
@ -0,0 +1 @@
|
|||
f5bb4c59fcfd891e4a9793355ed9499b79b2ee9ef7ca4d74399b602db38f1705
|
||||
|
|
@ -571,6 +571,21 @@ If you are using the Linux package installation, something might have failed dur
|
|||
This can be caused by orphaned records in the project registry. They are being cleaned
|
||||
periodically using a registry worker, so give it some time to fix it itself.
|
||||
|
||||
### Failed checksums on primary site
|
||||
|
||||
Failed checksums identified by the Geo Primary Verification information screen can be caused by missing files or mismatched checksums. You can find error messages like `"Repository cannot be checksummed because it does not exist"` or `"File is not checksummable"` in the `gitlab-rails/geo.log` file.
|
||||
|
||||
For additional information about failed items, run the [integrity check Rake tasks](../../../raketasks/check.md#uploaded-files-integrity):
|
||||
|
||||
```ruby
|
||||
sudo gitlab-rake gitlab:artifacts:check
|
||||
sudo gitlab-rake gitlab:ci_secure_files:check
|
||||
sudo gitlab-rake gitlab:lfs:check
|
||||
sudo gitlab-rake gitlab:uploads:check
|
||||
```
|
||||
|
||||
For detailed information about individual errors, use the `VERBOSE=1` variable.
|
||||
|
||||
### Secondary site shows "Unhealthy" in UI
|
||||
|
||||
If you have updated the value of `external_url` in `/etc/gitlab/gitlab.rb` for the primary site or changed the protocol from `http` to `https`, you may see that secondary sites are shown as `Unhealthy`. You may also find the following error in `geo.log`:
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ in the `Gitlab::Access` module as `access_level`.
|
|||
|
||||
The `group_saml_identity` attribute is only visible to group owners for [SSO-enabled groups](../user/group/saml_sso/index.md).
|
||||
|
||||
The `email` attribute is only visible to group owners for [enterprise users](../user/enterprise_user/index.md) of the group when an API request is sent to the group itself, or that group's subgroups or projects.
|
||||
The `email` attribute is only visible to group owners for [enterprise users](../user/enterprise_user/index.md)
|
||||
of the group when an API request is sent to the group itself, or that group's subgroups or projects.
|
||||
|
||||
## List all members of a group or project
|
||||
|
||||
|
|
@ -42,17 +43,19 @@ GET /groups/:id/members
|
|||
GET /projects/:id/members
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths) |
|
||||
| `query` | string | no | A query string to search for members |
|
||||
| `user_ids` | array of integers | no | Filter the results on the given user IDs |
|
||||
| `skip_users` | array of integers | no | Filter skipped users out of the results |
|
||||
| `show_seat_info` | boolean | no | Show seat information for users |
|
||||
| Attribute | Type | Required | Description |
|
||||
|------------------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths). |
|
||||
| `query` | string | no | Filters results based on a given name, email, or username. Use partial values to widen the scope of the query. |
|
||||
| `user_ids` | array of integers | no | Filter the results on the given user IDs. |
|
||||
| `skip_users` | array of integers | no | Filter skipped users out of the results. |
|
||||
| `show_seat_info` | boolean | no | Show seat information for users. |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/members"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/projects/:id/members"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -137,17 +140,19 @@ GET /groups/:id/members/all
|
|||
GET /projects/:id/members/all
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths). |
|
||||
| `query` | string | no | A query string to search for members. |
|
||||
| `user_ids` | array of integers | no | Filter the results on the given user IDs. |
|
||||
| `show_seat_info` | boolean | no | Show seat information for users. |
|
||||
| `state` | string | no | Filter results by member state, one of `awaiting` or `active`. Premium and Ultimate only. |
|
||||
| Attribute | Type | Required | Description |
|
||||
|------------------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths). |
|
||||
| `query` | string | no | Filters results based on a given name, email, or username. Use partial values to widen the scope of the query. |
|
||||
| `user_ids` | array of integers | no | Filter the results on the given user IDs. |
|
||||
| `show_seat_info` | boolean | no | Show seat information for users. |
|
||||
| `state` | string | no | Filter results by member state, one of `awaiting` or `active`. Premium and Ultimate only. |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/all"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/members/all"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/all"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/projects/:id/members/all"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -231,14 +236,16 @@ GET /groups/:id/members/:user_id
|
|||
GET /projects/:id/members/:user_id
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths) |
|
||||
| `user_id` | integer | yes | The user ID of the member |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the member. |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/:user_id"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/members/:user_id"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/:user_id"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/projects/:id/members/:user_id"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -288,12 +295,14 @@ GET /projects/:id/members/all/:user_id
|
|||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths) |
|
||||
| `user_id` | integer | yes | The user ID of the member |
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the member. |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/all/:user_id"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/members/all/:user_id"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/all/:user_id"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/projects/:id/members/all/:user_id"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -324,27 +333,26 @@ Example response:
|
|||
|
||||
## List all billable members of a group
|
||||
|
||||
Gets a list of group members that count as billable. The list includes members in subgroups and projects.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role to access the API endpoint for billing permissions, as shown in [billing permissions](../user/free_user_limit.md).
|
||||
|
||||
Gets a list of group members that count as billable. The list includes members in subgroups and projects.
|
||||
|
||||
This API endpoint works on top-level groups only. It does not work on subgroups.
|
||||
- This API endpoint works on top-level groups only. It does not work on subgroups.
|
||||
|
||||
This function takes [pagination](rest/index.md#pagination) parameters `page` and `per_page` to restrict the list of users.
|
||||
|
||||
Use the `search` parameter to search for billable group members by name and `sort` to sort the results.
|
||||
Use the `search` parameter to search for billable group members by name, and `sort` to sort the results.
|
||||
|
||||
```plaintext
|
||||
GET /groups/:id/billable_members
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| ----------------------------- | --------------- | --------- |-------------------------------------------------------------------------------------------------------------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths) |
|
||||
| `search` | string | no | A query string to search for group members by name, username, or public email. |
|
||||
| `sort` | string | no | A query string containing parameters that specify the sort attribute and order. See supported values below. |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths). |
|
||||
| `search` | string | no | A query string to search for group members by name, username, or public email. |
|
||||
| `sort` | string | no | A query string containing parameters that specify the sort attribute and order. See supported values below. |
|
||||
|
||||
The supported values for the `sort` attribute are:
|
||||
|
||||
|
|
@ -362,7 +370,8 @@ The supported values for the `sort` attribute are:
|
|||
| `last_activity_on_desc` | Last active date, descending |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/billable_members"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/billable_members"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -416,28 +425,32 @@ Example response:
|
|||
|
||||
Gets a list of memberships for a billable member of a group.
|
||||
|
||||
Lists all projects and groups a user is a member of. Only projects and groups within the group hierarchy are included.
|
||||
For instance, if the requested group is `Root Group`, and the requested user is a direct member of both `Root Group / Sub Group One` and `Other Group / Sub Group Two`, then only `Root Group / Sub Group One` will be returned, because `Other Group / Sub Group Two` is not within the `Root Group` hierarchy.
|
||||
Prerequisites:
|
||||
|
||||
The response represents only direct memberships. Inherited memberships are not included.
|
||||
- The response represents only direct memberships. Inherited memberships are not included.
|
||||
- This API endpoint works on top-level groups only. It does not work on subgroups.
|
||||
- This API endpoint requires permission to administer memberships for the group.
|
||||
|
||||
This API endpoint works on top-level groups only. It does not work on subgroups.
|
||||
Lists all projects and groups a user is a member of. Only projects and groups in the group hierarchy
|
||||
are included. For instance, if the requested group is `Root Group`, and the requested user is a direct member
|
||||
of both `Root Group / Sub Group One` and `Other Group / Sub Group Two`, then only `Root Group / Sub Group One`
|
||||
is returned, because `Other Group / Sub Group Two` is not in the `Root Group` hierarchy.
|
||||
|
||||
This API endpoint requires permission to administer memberships for the group.
|
||||
|
||||
This API endpoint takes [pagination](rest/index.md#pagination) parameters `page` and `per_page` to restrict the list of memberships.
|
||||
This API endpoint takes [pagination](rest/index.md#pagination) parameters `page` and `per_page` to restrict
|
||||
the list of memberships.
|
||||
|
||||
```plaintext
|
||||
GET /groups/:id/billable_members/:user_id/memberships
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths) |
|
||||
| `user_id` | integer | yes | The user ID of the billable member |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the billable member. |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/billable_members/:user_id/memberships"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/billable_members/:user_id/memberships"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -480,28 +493,30 @@ DETAILS:
|
|||
|
||||
Gets a list of indirect memberships for a billable member of a group.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- This API endpoint works on top-level groups only. It does not work on subgroups.
|
||||
- This API endpoint requires permission to administer memberships for the group.
|
||||
|
||||
Lists all projects and groups that a user is a member of, that have been invited to the requested root group.
|
||||
For instance, if the requested group is `Root Group`, and the requested user is a direct member of `Other Group / Sub Group Two`, which was invited to `Root Group`, then only `Other Group / Sub Group Two` is returned.
|
||||
|
||||
The response lists only indirect memberships. Direct memberships are not included.
|
||||
|
||||
This API endpoint works on top-level groups only. It does not work on subgroups.
|
||||
|
||||
This API endpoint requires permission to administer memberships for the group.
|
||||
|
||||
This API endpoint takes [pagination](rest/index.md#pagination) parameters `page` and `per_page` to restrict the list of memberships.
|
||||
|
||||
```plaintext
|
||||
GET /groups/:id/billable_members/:user_id/indirect
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths) |
|
||||
| `user_id` | integer | yes | The user ID of the billable member |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the billable member. |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/billable_members/:user_id/indirect"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/billable_members/:user_id/indirect"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -528,20 +543,21 @@ Example response:
|
|||
Removes a billable member from a group and its subgroups and projects.
|
||||
|
||||
The user does not need to be a group member to qualify for removal.
|
||||
For example, if the user was added directly to a project within the group, you can
|
||||
For example, if the user was added directly to a project in the group, you can
|
||||
still use this API to remove them.
|
||||
|
||||
```plaintext
|
||||
DELETE /groups/:id/billable_members/:user_id
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths) |
|
||||
| `user_id` | integer | yes | The user ID of the member |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the member. |
|
||||
|
||||
```shell
|
||||
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/billable_members/:user_id"
|
||||
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/billable_members/:user_id"
|
||||
```
|
||||
|
||||
## Change membership state of a user in a group
|
||||
|
|
@ -549,21 +565,24 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
|
|||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86705) in GitLab 15.0.
|
||||
|
||||
Changes the membership state of a user in a group.
|
||||
When a user is over [the free user limit](../user/free_user_limit.md), changing their membership state for a group or project to `awaiting` or `active` can allow them to
|
||||
access that group or project. The change is applied to applied to all subgroups and projects.
|
||||
|
||||
When a user is over [the free user limit](../user/free_user_limit.md), changing their membership state
|
||||
for a group or project to `awaiting` or `active` can allow them to access that group or project. The change
|
||||
is applied to applied to all subgroups and projects.
|
||||
|
||||
```plaintext
|
||||
PUT /groups/:id/members/:user_id/state
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the member. |
|
||||
| `state` | string | yes | The new state for the user. State is either `awaiting` or `active`. |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the member. |
|
||||
| `state` | string | yes | The new state for the user. State is either `awaiting` or `active`. |
|
||||
|
||||
```shell
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/:user_id/state?state=active"
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/:user_id/state?state=active"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -583,15 +602,15 @@ POST /groups/:id/members
|
|||
POST /projects/:id/members
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer/string | yes, if `username` is not provided | The user ID of the new member or multiple IDs separated by commas. |
|
||||
| `username` | string | yes, if `user_id` is not provided | The username of the new member or multiple usernames separated by commas. |
|
||||
| `access_level` | integer | yes | [A valid access level](access_requests.md#valid-access-levels). |
|
||||
| `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY`. |
|
||||
| `invite_source` | string | no | The source of the invitation that starts the member creation process. GitLab team members can view more information in this confidential issue: `https://gitlab.com/gitlab-org/gitlab/-/issues/327120>`. |
|
||||
| `member_role_id` | integer | no | The ID of a member role. Ultimate only. |
|
||||
| Attribute | Type | Required | Description |
|
||||
|------------------|-------------------|------------------------------------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer or string | yes, if `username` is not provided | The user ID of the new member or multiple IDs separated by commas. |
|
||||
| `username` | string | yes, if `user_id` is not provided | The username of the new member or multiple usernames separated by commas. |
|
||||
| `access_level` | integer | yes | [A valid access level](access_requests.md#valid-access-levels). |
|
||||
| `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY`. |
|
||||
| `invite_source` | string | no | The source of the invitation that starts the member creation process. GitLab team members can view more information in this confidential issue: `https://gitlab.com/gitlab-org/gitlab/-/issues/327120>`. |
|
||||
| `member_role_id` | integer | no | The ID of a member role. Ultimate only. |
|
||||
|
||||
```shell
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
|
|
@ -677,17 +696,19 @@ PUT /groups/:id/members/:user_id
|
|||
PUT /projects/:id/members/:user_id
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths) |
|
||||
| `user_id` | integer | yes | The user ID of the member |
|
||||
| `access_level` | integer | yes | A [valid access level](access_requests.md#valid-access-levels) |
|
||||
| `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY` |
|
||||
| `member_role_id` | integer | no | The ID of a member role. Ultimate only. |
|
||||
| Attribute | Type | Required | Description |
|
||||
|------------------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the member. |
|
||||
| `access_level` | integer | yes | A [valid access level](access_requests.md#valid-access-levels). |
|
||||
| `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY`. |
|
||||
| `member_role_id` | integer | no | The ID of a member role. Ultimate only. |
|
||||
|
||||
```shell
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/:user_id?access_level=40"
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/members/:user_id?access_level=40"
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/:user_id?access_level=40"
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/projects/:id/members/:user_id?access_level=40"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -741,13 +762,14 @@ by LDAP through Group Sync. You can allow access level overrides by calling this
|
|||
POST /groups/:id/members/:user_id/override
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths) |
|
||||
| `user_id` | integer | yes | The user ID of the member |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the member. |
|
||||
|
||||
```shell
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/:user_id/override"
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/:user_id/override"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -785,13 +807,14 @@ level to the LDAP-prescribed value.
|
|||
DELETE /groups/:id/members/:user_id/override
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths) |
|
||||
| `user_id` | integer | yes | The user ID of the member |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the member. |
|
||||
|
||||
```shell
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/:user_id/override"
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/:user_id/override"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
@ -825,7 +848,7 @@ Example response:
|
|||
Removes a user from a group or project where the user has been explicitly assigned a role.
|
||||
|
||||
The user needs to be a group member to qualify for removal.
|
||||
For example, if the user was added directly to a project within the group but not this
|
||||
For example, if the user was added directly to a project in the group but not this
|
||||
group explicitly, you cannot use this API to remove them. See
|
||||
[Remove a billable member from a group](#remove-a-billable-member-from-a-group) for an alternative approach.
|
||||
|
||||
|
|
@ -834,18 +857,20 @@ DELETE /groups/:id/members/:user_id
|
|||
DELETE /projects/:id/members/:user_id
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths) |
|
||||
| `user_id` | integer | yes | The user ID of the member |
|
||||
| `skip_subresources` | boolean | false | Whether the deletion of direct memberships of the removed member in subgroups and projects should be skipped. Default is `false`. |
|
||||
| `unassign_issuables` | boolean | false | Whether the removed member should be unassigned from any issues or merge requests inside a given group or project. Default is `false`. |
|
||||
| Attribute | Type | Required | Description |
|
||||
|----------------------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-paths). |
|
||||
| `user_id` | integer | yes | The user ID of the member. |
|
||||
| `skip_subresources` | boolean | false | Whether the deletion of direct memberships of the removed member in subgroups and projects should be skipped. Default is `false`. |
|
||||
| `unassign_issuables` | boolean | false | Whether the removed member should be unassigned from any issues or merge requests inside a given group or project. Default is `false`. |
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/:user_id"
|
||||
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/members/:user_id"
|
||||
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/:user_id"
|
||||
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/projects/:id/members/:user_id"
|
||||
```
|
||||
|
||||
## Approve a member for a group
|
||||
|
|
@ -856,15 +881,16 @@ Approves a pending user for a group and its subgroups and projects.
|
|||
PUT /groups/:id/members/:member_id/approve
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the root group](rest/index.md#namespaced-paths) |
|
||||
| `member_id` | integer | yes | The ID of the member |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-------------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the root group](rest/index.md#namespaced-paths). |
|
||||
| `member_id` | integer | yes | The ID of the member. |
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/:member_id/approve"
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/:member_id/approve"
|
||||
```
|
||||
|
||||
## Approve all pending members for a group
|
||||
|
|
@ -875,40 +901,44 @@ Approves all pending users for a group and its subgroups and projects.
|
|||
POST /groups/:id/members/approve_all
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the root group](rest/index.md#namespaced-paths) |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the root group](rest/index.md#namespaced-paths). |
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/approve_all"
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/members/approve_all"
|
||||
```
|
||||
|
||||
## List pending members of a group and its subgroups and projects
|
||||
|
||||
For a group and its subgroups and projects, get a list of all members in an `awaiting` state and those who are invited but do not have a GitLab account.
|
||||
For a group and its subgroups and projects, get a list of all members in an `awaiting` state and those
|
||||
who are invited but do not have a GitLab account.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- This API endpoint works on top-level groups only. It does not work on subgroups.
|
||||
- This API endpoint requires permission to administer members for the group.
|
||||
|
||||
This request returns all matching group and project members from all groups and projects in the root group's hierarchy.
|
||||
|
||||
When the member is an invited user that has not signed up for a GitLab account yet, the invited email address is returned.
|
||||
|
||||
This API endpoint works on top-level groups only. It does not work on subgroups.
|
||||
|
||||
This API endpoint requires permission to administer members for the group.
|
||||
|
||||
This API endpoint takes [pagination](rest/index.md#pagination) parameters `page` and `per_page` to restrict the list of members.
|
||||
|
||||
```plaintext
|
||||
GET /groups/:id/pending_members
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths) |
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|-------------------|----------|-------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-paths). |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/pending_members"
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/groups/:id/pending_members"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
class BackfillVulnerabilityNamespaceHistoricalStatistics < BatchedMigrationJob
|
||||
feature_category :vulnerability_management
|
||||
|
||||
def perform
|
||||
# no-op. The logic is defined in EE module.
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Gitlab::BackgroundMigration::BackfillVulnerabilityNamespaceHistoricalStatistics.prepend_mod
|
||||
|
|
@ -16,7 +16,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def to_h
|
||||
mapper&.to_h || {}
|
||||
mapper.to_h
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -13,11 +13,6 @@ module Gitlab
|
|||
'pipelines_graph',
|
||||
'continuous_integration'
|
||||
],
|
||||
[
|
||||
%r{\Aprojects/.+/.+/jobs\z},
|
||||
'jobs_table',
|
||||
'continuous_integration'
|
||||
],
|
||||
[
|
||||
%r(\Apipelines/sha/\w{#{Gitlab::Git::Commit::MIN_SHA_LENGTH},#{Gitlab::Git::Commit::MAX_SHA_LENGTH}}\z)o,
|
||||
'ci_editor',
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ module Security
|
|||
end
|
||||
|
||||
def collect_values(config, key)
|
||||
global_variables = config[:global]&.to_h { |k| [k[:field], k[key]] } || {}
|
||||
pipeline_variables = config[:pipeline]&.to_h { |k| [k[:field], k[key]] } || {}
|
||||
global_variables = config[:global].to_h { |k| [k[:field], k[key]] }
|
||||
pipeline_variables = config[:pipeline].to_h { |k| [k[:field], k[key]] }
|
||||
|
||||
analyzer_variables = collect_analyzer_values(config, key)
|
||||
|
||||
|
|
|
|||
|
|
@ -14082,6 +14082,9 @@ msgstr ""
|
|||
msgid "CompareRevisions|View open merge request"
|
||||
msgstr ""
|
||||
|
||||
msgid "Comparison pipelines"
|
||||
msgstr ""
|
||||
|
||||
msgid "Complete"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -49386,6 +49389,9 @@ msgstr ""
|
|||
msgid "Security dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security policy"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security policy bot cannot be added as a group member"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -50540,6 +50546,9 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|You already have the maximum %{maximumAllowed} %{policyType} %{instance}."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|You can add a maximum of %{rulesCount} %{rules}."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|You can select this option only once."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -53201,6 +53210,9 @@ msgstr ""
|
|||
msgid "Source branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Source branch (%{branch})"
|
||||
msgstr ""
|
||||
|
||||
msgid "Source branch does not exist"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -54724,6 +54736,9 @@ msgstr ""
|
|||
msgid "Target branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Target branch (%{branch})"
|
||||
msgstr ""
|
||||
|
||||
msgid "Target branch: %{target_branch}"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@
|
|||
"@gitlab/fonts": "^1.3.0",
|
||||
"@gitlab/query-language": "^0.0.5-a-20241112",
|
||||
"@gitlab/svgs": "3.121.0",
|
||||
"@gitlab/ui": "102.1.0",
|
||||
"@gitlab/ui": "103.1.0",
|
||||
"@gitlab/vue-router-vue3": "npm:vue-router@4.1.6",
|
||||
"@gitlab/vuex-vue3": "npm:vuex@4.0.0",
|
||||
"@gitlab/web-ide": "^0.0.1-dev-20240909013227",
|
||||
|
|
|
|||
|
|
@ -250,7 +250,6 @@ spec/frontend/ide/ide_router_spec.js
|
|||
spec/frontend/ide/sync_router_and_store_spec.js
|
||||
spec/frontend/import_entities/import_projects/components/import_projects_table_spec.js
|
||||
spec/frontend/integrations/beyond_identity/components/exclusions_list_spec.js
|
||||
spec/frontend/integrations/edit/components/integration_form_spec.js
|
||||
spec/frontend/integrations/edit/components/sections/connection_spec.js
|
||||
spec/frontend/invite_members/components/members_token_select_spec.js
|
||||
spec/frontend/issuable/components/issuable_by_email_spec.js
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ RSpec.describe 'UpgradePath', feature_category: :shared do
|
|||
upgrade_path = YAML.safe_load_file(Rails.root.join('config/upgrade_path.yml'))
|
||||
|
||||
expect(upgrade_path.first).to eq({ "major" => 8, "minor" => 11 })
|
||||
expect(upgrade_path[13]).to eq({ "major" => 14, "minor" => 0,
|
||||
expect(upgrade_path[15]).to eq({ "major" => 14, "minor" => 0,
|
||||
"comments" => "**Migrations can take a long time!**" })
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@ RSpec.describe 'Editing file blob', :js, feature_category: :source_code_manageme
|
|||
# there may be no diff and nothing to render.
|
||||
fill_editor(content: "class NextFeature#{object_id}\\nend\\n")
|
||||
|
||||
if commit_changes
|
||||
click_button 'Commit changes'
|
||||
end
|
||||
click_button 'Commit changes' if commit_changes
|
||||
end
|
||||
|
||||
def fill_editor(content: 'class NextFeature\\nend\\n')
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import Vue from 'vue';
|
|||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { toggleQueryPollingByVisibility } from '~/graphql_shared/utils';
|
||||
import { TEST_HOST } from 'spec/test_constants';
|
||||
import { createAlert } from '~/alert';
|
||||
import getJobsQuery from '~/ci/jobs_page/graphql/queries/get_jobs.query.graphql';
|
||||
|
|
@ -21,12 +20,7 @@ import {
|
|||
mockFailedSearchToken,
|
||||
mockJobsCountResponse,
|
||||
} from 'jest/ci/jobs_mock_data';
|
||||
import {
|
||||
RAW_TEXT_WARNING,
|
||||
DEFAULT_PAGINATION,
|
||||
JOBS_PER_PAGE,
|
||||
POLL_INTERVAL,
|
||||
} from '~/ci/jobs_page/constants';
|
||||
import { RAW_TEXT_WARNING, DEFAULT_PAGINATION, JOBS_PER_PAGE } from '~/ci/jobs_page/constants';
|
||||
|
||||
const projectPath = 'gitlab-org/gitlab';
|
||||
Vue.use(VueApollo);
|
||||
|
|
@ -71,7 +65,6 @@ describe('Job table app', () => {
|
|||
wrapper = mountFn(JobsTableApp, {
|
||||
provide: {
|
||||
fullPath: projectPath,
|
||||
graphqlResourceEtag: '/etag',
|
||||
glFeatures: {
|
||||
populateAndUseBuildNamesTable: flagState,
|
||||
},
|
||||
|
|
@ -442,37 +435,6 @@ describe('Job table app', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('polling', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
it('polls for project jobs and job count', async () => {
|
||||
expect(successHandler).toHaveBeenCalledTimes(1);
|
||||
expect(countSuccessHandler).toHaveBeenCalledTimes(1);
|
||||
|
||||
jest.advanceTimersByTime(POLL_INTERVAL);
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(successHandler).toHaveBeenCalledTimes(2);
|
||||
expect(countSuccessHandler).toHaveBeenCalledTimes(2);
|
||||
|
||||
jest.advanceTimersByTime(POLL_INTERVAL);
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(successHandler).toHaveBeenCalledTimes(3);
|
||||
expect(countSuccessHandler).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('should set up a toggle visibility', () => {
|
||||
expect(toggleQueryPollingByVisibility).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('pagination', () => {
|
||||
it('displays keyset pagination', async () => {
|
||||
createComponent();
|
||||
|
|
|
|||
|
|
@ -220,30 +220,27 @@ describe('IntegrationForm', () => {
|
|||
});
|
||||
|
||||
describe.each`
|
||||
formActive | novalidate
|
||||
${true} | ${undefined}
|
||||
${false} | ${'true'}
|
||||
`(
|
||||
'when `toggle-integration-active` is emitted with $formActive',
|
||||
({ formActive, novalidate }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
customStateProps: {
|
||||
sections: [mockSectionConnection],
|
||||
manualActivation: true,
|
||||
initialActivated: false,
|
||||
},
|
||||
});
|
||||
|
||||
const section = findAllSections().at(0);
|
||||
section.vm.$emit('toggle-integration-active', formActive);
|
||||
formActive | method
|
||||
${true} | ${'toBeUndefined'}
|
||||
${false} | ${'toBeDefined'}
|
||||
`('when `toggle-integration-active` is emitted with $formActive', ({ formActive, method }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
customStateProps: {
|
||||
sections: [mockSectionConnection],
|
||||
manualActivation: true,
|
||||
initialActivated: false,
|
||||
},
|
||||
});
|
||||
|
||||
it(`sets noValidate to ${novalidate}`, () => {
|
||||
expect(findGlForm().attributes('novalidate')).toBe(novalidate);
|
||||
});
|
||||
},
|
||||
);
|
||||
const section = findAllSections().at(0);
|
||||
section.vm.$emit('toggle-integration-active', formActive);
|
||||
});
|
||||
|
||||
it(`checks noValidate ${method}`, () => {
|
||||
expect(findGlForm().attributes('novalidate'))[method]();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when section emits `request-jira-issue-types` event', () => {
|
||||
beforeEach(() => {
|
||||
|
|
@ -285,28 +282,25 @@ describe('IntegrationForm', () => {
|
|||
});
|
||||
|
||||
describe.each`
|
||||
formActive | novalidate
|
||||
${true} | ${undefined}
|
||||
${false} | ${'true'}
|
||||
`(
|
||||
'when `toggle-integration-active` is emitted with $formActive',
|
||||
({ formActive, novalidate }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
customStateProps: {
|
||||
manualActivation: true,
|
||||
initialActivated: false,
|
||||
},
|
||||
});
|
||||
|
||||
findActiveCheckbox().vm.$emit('toggle-integration-active', formActive);
|
||||
formActive | method
|
||||
${true} | ${'toBeUndefined'}
|
||||
${false} | ${'toBeDefined'}
|
||||
`('when `toggle-integration-active` is emitted with $formActive', ({ formActive, method }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
customStateProps: {
|
||||
manualActivation: true,
|
||||
initialActivated: false,
|
||||
},
|
||||
});
|
||||
|
||||
it(`sets noValidate to ${novalidate}`, () => {
|
||||
expect(findGlForm().attributes('novalidate')).toBe(novalidate);
|
||||
});
|
||||
},
|
||||
);
|
||||
findActiveCheckbox().vm.$emit('toggle-integration-active', formActive);
|
||||
});
|
||||
|
||||
it(`checks noValidate ${method}`, () => {
|
||||
expect(findGlForm().attributes('novalidate'))[method]();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Response to the "save" event (form submission)', () => {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ exports[`packages_list_app renders 1`] = `
|
|||
You have no Terraform modules in your project
|
||||
</h1>
|
||||
<p
|
||||
class="gl-mb-0 gl-mt-4"
|
||||
class="gl-mb-0 gl-mt-4 gl-text-subtle"
|
||||
>
|
||||
Learn how to
|
||||
<b-link-stub
|
||||
|
|
|
|||
|
|
@ -375,9 +375,5 @@ RSpec.describe GitlabRoutingHelper do
|
|||
expect(graphql_etag_pipeline_path(pipeline)).to eq('/api/graphql:pipelines/id/5')
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns an ETag path for jobs' do
|
||||
expect(graphql_etag_jobs_path(project)).to eq("/api/graphql:projects/#{project.full_path}/jobs")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,15 +25,6 @@ RSpec.describe Gitlab::EtagCaching::Router do
|
|||
expect(result.urgency).to eq ::Gitlab::EndpointAttributes::DEFAULT_URGENCY
|
||||
end
|
||||
|
||||
it 'matches jobs endpoint' do
|
||||
result = match_route('/api/graphql', 'projects/a/b/jobs')
|
||||
|
||||
expect(result).to be_present
|
||||
expect(result.name).to eq 'jobs_table'
|
||||
expect(result.router).to eq Gitlab::EtagCaching::Router::Graphql
|
||||
expect(result.urgency).to eq ::Gitlab::EndpointAttributes::DEFAULT_URGENCY
|
||||
end
|
||||
|
||||
it 'matches pipeline sha endpoint' do
|
||||
result = match_route('/api/graphql', 'pipelines/sha/4asd12lla2jiwjdqw9as32glm8is8hiu8s2c5jsw')
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe QueueBackfillVulnerabilityNamespaceHistoricalStatistics, feature_category: :vulnerability_management do
|
||||
let!(:batched_migration) { described_class::MIGRATION }
|
||||
|
||||
it 'schedules a new batched migration' do
|
||||
reversible_migration do |migration|
|
||||
migration.before -> {
|
||||
expect(batched_migration).not_to have_scheduled_batched_migration
|
||||
}
|
||||
|
||||
migration.after -> {
|
||||
expect(batched_migration).to have_scheduled_batched_migration(
|
||||
gitlab_schema: :gitlab_sec,
|
||||
table_name: :vulnerability_historical_statistics,
|
||||
column_name: :id,
|
||||
interval: described_class::DELAY_INTERVAL,
|
||||
batch_size: described_class::BATCH_SIZE,
|
||||
sub_batch_size: described_class::SUB_BATCH_SIZE
|
||||
)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -3845,7 +3845,9 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
|
||||
with_them do
|
||||
it 'overrides mergeable_ci_state?' do
|
||||
allow(subject).to receive(:mergeable_ci_state?) { mergeable_ci_state }
|
||||
allow_next_instance_of(MergeRequests::Mergeability::CheckCiStatusService) do |check|
|
||||
allow(check).to receive(:mergeable_ci_state?).and_return(mergeable_ci_state)
|
||||
end
|
||||
|
||||
expect(subject.mergeable?(skip_ci_check: skip_ci_check)).to eq(expected_mergeable)
|
||||
end
|
||||
|
|
@ -4016,7 +4018,9 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
subject { create(:merge_request) }
|
||||
|
||||
it 'checks if merge request can be merged' do
|
||||
allow(subject).to receive(:mergeable_ci_state?) { true }
|
||||
allow_next_instance_of(MergeRequests::Mergeability::CheckCiStatusService) do |check|
|
||||
allow(check).to receive(:mergeable_ci_state?).and_return(true)
|
||||
end
|
||||
expect(subject).to receive(:check_mergeability)
|
||||
|
||||
subject.mergeable?
|
||||
|
|
@ -4060,7 +4064,9 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
context 'when #mergeable_ci_state? is false' do
|
||||
before do
|
||||
allow(subject.project).to receive(:only_allow_merge_if_pipeline_succeeds?) { true }
|
||||
allow(subject).to receive(:mergeable_ci_state?) { false }
|
||||
allow_next_instance_of(MergeRequests::Mergeability::CheckCiStatusService) do |check|
|
||||
allow(check).to receive(:mergeable_ci_state?).and_return(false)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
|
|
@ -4237,193 +4243,6 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
end
|
||||
end
|
||||
|
||||
describe '#mergeable_ci_state?' do
|
||||
let(:pipeline) { build(:ci_empty_pipeline) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:head_pipeline) { pipeline }
|
||||
end
|
||||
|
||||
context 'when the auto merge strategy is merge when checks pass and project has ci' do
|
||||
subject { build(:merge_request, source_project: project, auto_merge_strategy: ::AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS, auto_merge_enabled: true) }
|
||||
|
||||
let(:project) { build(:project, :auto_devops, only_allow_merge_if_pipeline_succeeds: false) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:has_ci_enabled?).and_return(true)
|
||||
end
|
||||
|
||||
context 'and a failed pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'failed'
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_falsey }
|
||||
end
|
||||
|
||||
context 'and a successful pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'success'
|
||||
allow(subject).to receive(:head_pipeline) { pipeline }
|
||||
end
|
||||
|
||||
context 'and no pipelines are being created' do
|
||||
it { expect(subject.mergeable_ci_state?).to be_truthy }
|
||||
end
|
||||
|
||||
context 'and pipelines are being created' do
|
||||
let!(:creation) { Ci::PipelineCreation::Requests.start_for_merge_request(subject) }
|
||||
|
||||
after do
|
||||
Ci::PipelineCreation::Requests.succeeded(creation, pipeline.id)
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_falsey }
|
||||
end
|
||||
end
|
||||
|
||||
context 'and a skipped pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'skipped'
|
||||
allow(subject).to receive(:head_pipeline).and_return(pipeline)
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_falsey }
|
||||
|
||||
context 'when project allows skipped pipelines' do
|
||||
before do
|
||||
project.allow_merge_on_skipped_pipeline = true
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_truthy }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no pipeline is associated' do
|
||||
before do
|
||||
allow(subject).to receive(:head_pipeline).and_return(nil)
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_falsey }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is only allowed to merge when build is green' do
|
||||
subject { build(:merge_request, source_project: project) }
|
||||
|
||||
let(:project) { build(:project, :repository, only_allow_merge_if_pipeline_succeeds: true) }
|
||||
|
||||
context 'and a failed pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'failed'
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_falsey }
|
||||
end
|
||||
|
||||
context 'and a successful pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'success'
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_truthy }
|
||||
end
|
||||
|
||||
context 'and a skipped pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'skipped'
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_falsey }
|
||||
end
|
||||
|
||||
context 'when no pipeline is associated' do
|
||||
before do
|
||||
allow(subject).to receive(:head_pipeline).and_return(nil)
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_falsey }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is only allowed to merge when build is green or skipped' do
|
||||
let(:project) { build(:project, :repository, only_allow_merge_if_pipeline_succeeds: true, allow_merge_on_skipped_pipeline: true) }
|
||||
|
||||
subject { build(:merge_request, source_project: project) }
|
||||
|
||||
context 'and a failed pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'failed'
|
||||
allow(subject).to receive(:head_pipeline).and_return(pipeline)
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_falsey }
|
||||
end
|
||||
|
||||
context 'and a successful pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'success'
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_truthy }
|
||||
end
|
||||
|
||||
context 'and a skipped pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'skipped'
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_truthy }
|
||||
end
|
||||
|
||||
context 'when no pipeline is associated' do
|
||||
before do
|
||||
allow(subject).to receive(:head_pipeline).and_return(nil)
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_falsey }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when merges are not restricted to green builds' do
|
||||
let(:project) { build(:project, :repository, only_allow_merge_if_pipeline_succeeds: false) }
|
||||
|
||||
subject { build(:merge_request, source_project: project) }
|
||||
|
||||
context 'and a failed pipeline is associated' do
|
||||
before do
|
||||
pipeline.statuses << build(:commit_status, status: 'failed', project: project)
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_truthy }
|
||||
end
|
||||
|
||||
context 'when no pipeline is associated' do
|
||||
before do
|
||||
allow(subject).to receive(:head_pipeline) { nil }
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_truthy }
|
||||
end
|
||||
|
||||
context 'and a skipped pipeline is associated' do
|
||||
before do
|
||||
pipeline.status = 'skipped'
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_truthy }
|
||||
end
|
||||
|
||||
context 'when no pipeline is associated' do
|
||||
before do
|
||||
allow(subject).to receive(:head_pipeline).and_return(nil)
|
||||
end
|
||||
|
||||
it { expect(subject.mergeable_ci_state?).to be_truthy }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#mergeable_discussions_state?' do
|
||||
let(:merge_request) { create(:merge_request_with_diff_notes, source_project: project) }
|
||||
|
||||
|
|
|
|||
|
|
@ -213,7 +213,9 @@ RSpec.describe AutoMerge::MergeWhenChecksPassService, feature_category: :code_re
|
|||
context 'when the pipeline has succeeded' do
|
||||
before do
|
||||
allow(mr_merge_if_green_enabled).to receive(:diff_head_pipeline_success?).and_return(true)
|
||||
allow(mr_merge_if_green_enabled).to receive(:mergeable_ci_state?).and_return(true)
|
||||
allow_next_instance_of(MergeRequests::Mergeability::CheckCiStatusService) do |check|
|
||||
allow(check).to receive(:mergeable_ci_state?).and_return(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the merge request is mergable' do
|
||||
|
|
|
|||
|
|
@ -743,7 +743,9 @@ RSpec.describe MergeRequests::MergeService, feature_category: :code_review_workf
|
|||
context 'with failing CI' do
|
||||
before do
|
||||
allow(merge_request.project).to receive(:only_allow_merge_if_pipeline_succeeds) { true }
|
||||
allow(merge_request).to receive(:mergeable_ci_state?) { false }
|
||||
allow_next_instance_of(MergeRequests::Mergeability::CheckCiStatusService) do |check|
|
||||
allow(check).to receive(:mergeable_ci_state?).and_return(false)
|
||||
end
|
||||
end
|
||||
|
||||
it 'logs and saves error' do
|
||||
|
|
|
|||
|
|
@ -5,94 +5,139 @@ require 'spec_helper'
|
|||
RSpec.describe MergeRequests::Mergeability::CheckCiStatusService, feature_category: :code_review_workflow do
|
||||
subject(:check_ci_status) { described_class.new(merge_request: merge_request, params: params) }
|
||||
|
||||
let_it_be(:project) { build(:project) }
|
||||
let_it_be(:merge_request) { build(:merge_request, source_project: project) }
|
||||
let(:project) do
|
||||
build(:project,
|
||||
auto_devops_status,
|
||||
only_allow_merge_if_pipeline_succeeds: only_allow_merge_if_pipeline_succeeds,
|
||||
allow_merge_on_skipped_pipeline: allow_merge_on_skipped_pipeline)
|
||||
end
|
||||
|
||||
let(:merge_request) do
|
||||
build(:merge_request,
|
||||
source_project: project,
|
||||
auto_merge_strategy: auto_merge_strategy,
|
||||
auto_merge_enabled: auto_merge_enabled)
|
||||
end
|
||||
|
||||
let(:allow_merge_on_skipped_pipeline) { false }
|
||||
let(:only_allow_merge_if_pipeline_succeeds) { false }
|
||||
let(:auto_merge_strategy) { nil }
|
||||
let(:auto_merge_enabled) { false }
|
||||
let(:auto_devops_status) { :auto_devops_disabled }
|
||||
|
||||
let(:params) { { skip_ci_check: skip_check } }
|
||||
let(:skip_check) { false }
|
||||
|
||||
let(:result) { check_ci_status.execute }
|
||||
|
||||
it_behaves_like 'mergeability check service', :ci_must_pass, 'Checks whether CI has passed'
|
||||
|
||||
describe '#execute' do
|
||||
let(:result) { check_ci_status.execute }
|
||||
|
||||
before do
|
||||
allow(merge_request)
|
||||
.to receive(:only_allow_merge_if_pipeline_succeeds?)
|
||||
.and_return(only_allow_merge_if_pipeline_succeeds)
|
||||
|
||||
allow(merge_request)
|
||||
.to receive(:auto_merge_enabled?)
|
||||
.and_return(auto_merge_enabled?)
|
||||
shared_examples 'a valid diff head pipeline is required' do
|
||||
context 'when there is no diff head pipeline' do
|
||||
it 'is failure' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::FAILED_STATUS
|
||||
end
|
||||
end
|
||||
|
||||
context 'when only_allow_merge_if_pipeline_succeeds is true' do
|
||||
context 'when there is a diff head pipeline' do
|
||||
let(:pipeline) { create(:ci_empty_pipeline, sha: '1982309812309812') }
|
||||
|
||||
before do
|
||||
merge_request.update_attribute(:head_pipeline_id, pipeline.id)
|
||||
end
|
||||
|
||||
context 'when there is a pipeline being created' do
|
||||
before do
|
||||
allow(Ci::PipelineCreation::Requests).to receive(:pipeline_creating_for_merge_request?).and_return(true)
|
||||
end
|
||||
|
||||
it 'is failure' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::FAILED_STATUS
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is no pipeline being created' do
|
||||
before do
|
||||
allow(Ci::PipelineCreation::Requests).to receive(:pipeline_creating_for_merge_request?).and_return(false)
|
||||
end
|
||||
|
||||
context 'when the diff head pipeline is skipped' do
|
||||
before do
|
||||
pipeline.update_attribute(:status, :skipped)
|
||||
end
|
||||
|
||||
context 'when it is allowed to be skipped' do
|
||||
let(:allow_merge_on_skipped_pipeline) { true }
|
||||
|
||||
it 'is success' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::SUCCESS_STATUS
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is not allowed to be skipped' do
|
||||
let(:allow_merge_on_skipped_pipeline) { false }
|
||||
|
||||
it 'is failed' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::FAILED_STATUS
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the diff head pipeline is successful' do
|
||||
before do
|
||||
pipeline.update_attribute(:status, :success)
|
||||
end
|
||||
|
||||
it 'is success' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::SUCCESS_STATUS
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the diff head pipeline is not skipped or successful' do
|
||||
it 'is failed' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::FAILED_STATUS
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when a successful pipeline is required for merge' do
|
||||
let(:only_allow_merge_if_pipeline_succeeds) { true }
|
||||
|
||||
context 'when merge_request.auto_merge_enabled? is false' do
|
||||
let(:auto_merge_enabled?) { false }
|
||||
|
||||
before do
|
||||
expect(merge_request).to receive(:mergeable_ci_state?).and_return(mergeable)
|
||||
end
|
||||
|
||||
context 'when the merge request is in a mergeable state' do
|
||||
let(:mergeable) { true }
|
||||
|
||||
it 'returns a check result with status success' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::SUCCESS_STATUS
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the merge request is not in a mergeable state' do
|
||||
let(:mergeable) { false }
|
||||
|
||||
it 'returns a check result with status failed' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::FAILED_STATUS
|
||||
expect(result.payload[:identifier]).to eq :ci_must_pass
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when merge_request.auto_merge_enabled? is true ' do
|
||||
let(:auto_merge_enabled?) { true }
|
||||
|
||||
before do
|
||||
expect(merge_request).to receive(:mergeable_ci_state?).and_return(mergeable)
|
||||
end
|
||||
|
||||
context 'when the merge request is in a mergeable state' do
|
||||
let(:mergeable) { true }
|
||||
|
||||
it 'returns a check result with status success' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::SUCCESS_STATUS
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the merge request is not in a mergeable state' do
|
||||
let(:mergeable) { false }
|
||||
|
||||
it 'returns a check result with status failed' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::FAILED_STATUS
|
||||
expect(result.payload[:identifier]).to eq :ci_must_pass
|
||||
end
|
||||
end
|
||||
end
|
||||
it_behaves_like 'a valid diff head pipeline is required'
|
||||
end
|
||||
|
||||
context 'when only_allow_merge_if_pipeline_succeeds is false' do
|
||||
let(:only_allow_merge_if_pipeline_succeeds) { false }
|
||||
let(:auto_merge_enabled?) { false }
|
||||
|
||||
context 'when merge_request.auto_merge_enabled? is false' do
|
||||
it 'returns a check result with inactive status' do
|
||||
context 'when a successful pipeline is not required for merge' do
|
||||
context 'when auto merge is not enabled' do
|
||||
it 'is inactive' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::INACTIVE_STATUS
|
||||
end
|
||||
end
|
||||
|
||||
context 'when auto merge is enabled' do
|
||||
let(:auto_merge_enabled) { true }
|
||||
let(:auto_merge_strategy) { ::AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS }
|
||||
|
||||
context 'when the auto merge strategy is STATEGY_MERGE_WHEN_CHECKS_PASS and ci is disabled' do
|
||||
it 'is success' do
|
||||
expect(result.status).to eq Gitlab::MergeRequests::Mergeability::CheckResult::SUCCESS_STATUS
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the auto merge strategy is STATEGY_MERGE_WHEN_CHECKS_PASS and ci is enabled' do
|
||||
let(:auto_merge_strategy) { ::AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS }
|
||||
let(:auto_devops_status) { :auto_devops }
|
||||
|
||||
it_behaves_like 'a valid diff head pipeline is required'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#skip?' do
|
||||
context 'when skip check is true' do
|
||||
context 'when skip check is present in the params' do
|
||||
let(:skip_check) { true }
|
||||
|
||||
it 'returns true' do
|
||||
|
|
@ -100,7 +145,7 @@ RSpec.describe MergeRequests::Mergeability::CheckCiStatusService, feature_catego
|
|||
end
|
||||
end
|
||||
|
||||
context 'when skip check is false' do
|
||||
context 'when skip check is not present in the params' do
|
||||
let(:skip_check) { false }
|
||||
|
||||
it 'returns false' do
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples "set_current_context" do
|
||||
RSpec.shared_examples 'set_current_context' do
|
||||
it 'sets the metadata of the request in the context' do |example|
|
||||
raise('this shared example should be used in a request spec only') unless example.metadata[:type] == :request
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ const glob = require('glob');
|
|||
const sass = require('sass');
|
||||
const webpack = require('webpack');
|
||||
const { red } = require('chalk');
|
||||
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
||||
const IS_EE = require('../../config/helpers/is_ee_env');
|
||||
const IS_JH = require('../../config/helpers/is_jh_env');
|
||||
const gitlabWebpackConfig = require('../../config/webpack.config');
|
||||
|
|
@ -178,11 +179,35 @@ module.exports = function storybookWebpackConfig({ config }) {
|
|||
include: /node_modules/,
|
||||
type: 'javascript/auto',
|
||||
},
|
||||
{
|
||||
test: /\.(js|cjs)$/,
|
||||
include: (modulePath) =>
|
||||
/node_modules\/(jsonc-parser|monaco-editor|monaco-worker-manager|monaco-marker-data-provider)/.test(
|
||||
modulePath,
|
||||
) || /node_modules\/yaml/.test(modulePath),
|
||||
use: transpileDependencyConfig,
|
||||
},
|
||||
];
|
||||
|
||||
// Silence webpack warnings about moment/pikaday not being able to resolve.
|
||||
config.plugins.push(new webpack.IgnorePlugin(/moment/, /pikaday/));
|
||||
|
||||
config.plugins.push(
|
||||
new MonacoWebpackPlugin({
|
||||
filename: '[name].[contenthash:8].worker.js',
|
||||
customLanguages: [
|
||||
{
|
||||
label: 'yaml',
|
||||
entry: 'monaco-yaml',
|
||||
worker: {
|
||||
id: 'monaco-yaml/yamlWorker',
|
||||
entry: 'monaco-yaml/yaml.worker',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
if (!IS_EE) {
|
||||
config.plugins.push(
|
||||
new webpack.NormalModuleReplacementPlugin(/^ee_component\/(.*)\.vue/, (resource) => {
|
||||
|
|
|
|||
|
|
@ -1429,10 +1429,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.121.0.tgz#57cacc895929aef4320632396373797a64b230ff"
|
||||
integrity sha512-ZekVjdMZrjrNEjdrOHsJYCu7A+ea3AkuNUxWIZ3FaNgJj4Oh21RlTP7bQKnRSXVhBbV1jg1PgzQ1ANEoCW8t4g==
|
||||
|
||||
"@gitlab/ui@102.1.0":
|
||||
version "102.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-102.1.0.tgz#ea52d414b56e28cdd7e1bd572d7e5c057238384a"
|
||||
integrity sha512-8A2qNm2JYf9/xEF0Sh0XVVrZlp7YzFws+sPOQ4CVdwyoyBtXU4cACxBfb+/t1OvTrzX42gKnHjIbolN80E51NA==
|
||||
"@gitlab/ui@103.1.0":
|
||||
version "103.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-103.1.0.tgz#7b446e72873ed9608211482b1f80419a0def3d4c"
|
||||
integrity sha512-KpmJHY1+armClHecG1FoLrERpYgDK4GesbB82HsYEF1EydSZeyQPrrQEYdY83rqF1POYXBHOEzugmteOA5nUvg==
|
||||
dependencies:
|
||||
"@floating-ui/dom" "1.4.3"
|
||||
echarts "^5.3.2"
|
||||
|
|
|
|||
Loading…
Reference in New Issue