New upstream version 13.3.8

This commit is contained in:
Pirate Praveen 2020-10-24 23:57:45 +05:30
parent 529b513274
commit c7883f9ba0
6677 changed files with 425729 additions and 86073 deletions

View file

@ -27,7 +27,6 @@ rules:
- ignore: - ignore:
# https://gitlab.com/gitlab-org/gitlab/issues/38226 # https://gitlab.com/gitlab-org/gitlab/issues/38226
- '^ee_component/' - '^ee_component/'
import/order: off
# Disabled for now, to make the airbnb-base 12.1.0 -> 13.1.0 update smoother # Disabled for now, to make the airbnb-base 12.1.0 -> 13.1.0 update smoother
no-else-return: no-else-return:
- error - error

510
.gitignore vendored
View file

@ -77,7 +77,6 @@ eslint-report.html
/locale/**/LC_MESSAGES /locale/**/LC_MESSAGES
/locale/**/*.time_stamp /locale/**/*.time_stamp
/.rspec /.rspec
/.gitlab_pages_secret
/.gitlab_smime_key /.gitlab_smime_key
/.gitlab_smime_cert /.gitlab_smime_cert
package-lock.json package-lock.json
@ -95,3 +94,512 @@ webpack-dev-server.json
apollo.config.js apollo.config.js
/tmp/matching_foss_tests.txt /tmp/matching_foss_tests.txt
ee/changelogs/unreleased-ee ee/changelogs/unreleased-ee
# Likely anything 2017 was removed in bac4d96dcfc, 381b706559b, or cfae6ec2647
db/schema_migrations/2014*
db/schema_migrations/2015*
db/schema_migrations/2016*
db/schema_migrations/2017*
# Removed in 02ea9bc792b9236ea8854154ea5caef1a03b07b4
db/schema_migrations/20171230123729
db/schema_migrations/20180101160629
db/schema_migrations/20180101160630
db/schema_migrations/20180102220145
db/schema_migrations/20180103123548
db/schema_migrations/20180104131052
db/schema_migrations/20180105212544
db/schema_migrations/20180109183319
db/schema_migrations/20180113220114
db/schema_migrations/20180115094742
db/schema_migrations/20180115113902
db/schema_migrations/20180115201419
db/schema_migrations/20180116193854
db/schema_migrations/20180119121225
db/schema_migrations/20180119135717
db/schema_migrations/20180119160751
db/schema_migrations/20180122154930
db/schema_migrations/20180122162010
db/schema_migrations/20180125214301
db/schema_migrations/20180129193323
db/schema_migrations/20180201102129
db/schema_migrations/20180201110056
db/schema_migrations/20180201145907
db/schema_migrations/20180204200836
db/schema_migrations/20180206200543
db/schema_migrations/20180208183958
db/schema_migrations/20180209115333
db/schema_migrations/20180209165249
db/schema_migrations/20180212030105
db/schema_migrations/20180212101828
db/schema_migrations/20180212101928
db/schema_migrations/20180212102028
db/schema_migrations/20180213131630
db/schema_migrations/20180214093516
db/schema_migrations/20180214155405
db/schema_migrations/20180215181245
db/schema_migrations/20180216120000
db/schema_migrations/20180216120010
db/schema_migrations/20180216120020
db/schema_migrations/20180216120030
db/schema_migrations/20180216120040
db/schema_migrations/20180216120050
db/schema_migrations/20180216121020
db/schema_migrations/20180216121030
db/schema_migrations/20180219153455
db/schema_migrations/20180220150310
db/schema_migrations/20180221151752
db/schema_migrations/20180222043024
db/schema_migrations/20180223120443
db/schema_migrations/20180223124427
db/schema_migrations/20180223144945
db/schema_migrations/20180226050030
db/schema_migrations/20180227182112
db/schema_migrations/20180228172924
db/schema_migrations/20180301010859
db/schema_migrations/20180301084653
db/schema_migrations/20180302152117
db/schema_migrations/20180305095250
db/schema_migrations/20180305100050
db/schema_migrations/20180305144721
db/schema_migrations/20180306074045
db/schema_migrations/20180306134842
db/schema_migrations/20180306164012
db/schema_migrations/20180307012445
db/schema_migrations/20180308052825
db/schema_migrations/20180308125206
db/schema_migrations/20180309121820
db/schema_migrations/20180309160427
db/schema_migrations/20180314100728
db/schema_migrations/20180314145917
db/schema_migrations/20180315160435
db/schema_migrations/20180319190020
db/schema_migrations/20180320182229
db/schema_migrations/20180323150945
db/schema_migrations/20180326202229
db/schema_migrations/20180327101207
db/schema_migrations/20180330121048
db/schema_migrations/20180403035759
db/schema_migrations/20180405101928
db/schema_migrations/20180405142733
db/schema_migrations/20180408143354
db/schema_migrations/20180408143355
db/schema_migrations/20180409170809
db/schema_migrations/20180413022611
db/schema_migrations/20180416155103
db/schema_migrations/20180417090132
db/schema_migrations/20180417101040
db/schema_migrations/20180417101940
db/schema_migrations/20180418053107
db/schema_migrations/20180420010016
db/schema_migrations/20180420010616
db/schema_migrations/20180420080616
db/schema_migrations/20180423204600
db/schema_migrations/20180424090541
db/schema_migrations/20180424134533
db/schema_migrations/20180424151928
db/schema_migrations/20180424160449
db/schema_migrations/20180425075446
db/schema_migrations/20180425131009
db/schema_migrations/20180425205249
db/schema_migrations/20180426102016
db/schema_migrations/20180430101916
db/schema_migrations/20180430143705
db/schema_migrations/20180502122856
db/schema_migrations/20180503131624
db/schema_migrations/20180503141722
db/schema_migrations/20180503150427
db/schema_migrations/20180503175053
db/schema_migrations/20180503175054
db/schema_migrations/20180503193542
db/schema_migrations/20180503193953
db/schema_migrations/20180503200320
db/schema_migrations/20180504195842
db/schema_migrations/20180507083701
db/schema_migrations/20180508055821
db/schema_migrations/20180508100222
db/schema_migrations/20180508102840
db/schema_migrations/20180508135515
db/schema_migrations/20180511090724
db/schema_migrations/20180511131058
db/schema_migrations/20180511174224
db/schema_migrations/20180512061621
db/schema_migrations/20180514161336
db/schema_migrations/20180515005612
db/schema_migrations/20180515121227
db/schema_migrations/20180517082340
db/schema_migrations/20180523042841
db/schema_migrations/20180523125103
db/schema_migrations/20180524132016
db/schema_migrations/20180529093006
db/schema_migrations/20180529152628
db/schema_migrations/20180530135500
db/schema_migrations/20180531185349
db/schema_migrations/20180531220618
db/schema_migrations/20180601213245
db/schema_migrations/20180603190921
db/schema_migrations/20180604123514
db/schema_migrations/20180607071808
db/schema_migrations/20180608091413
db/schema_migrations/20180608110058
db/schema_migrations/20180608201435
db/schema_migrations/20180612103626
db/schema_migrations/20180613081317
db/schema_migrations/20180625113853
db/schema_migrations/20180626125654
db/schema_migrations/20180628124813
db/schema_migrations/20180629153018
db/schema_migrations/20180629191052
db/schema_migrations/20180702120647
db/schema_migrations/20180702124358
db/schema_migrations/20180702134423
db/schema_migrations/20180704145007
db/schema_migrations/20180704204006
db/schema_migrations/20180705160945
db/schema_migrations/20180706223200
db/schema_migrations/20180710162338
db/schema_migrations/20180711103851
db/schema_migrations/20180711103922
db/schema_migrations/20180713092803
db/schema_migrations/20180717125853
db/schema_migrations/20180718005113
db/schema_migrations/20180720023512
db/schema_migrations/20180722103201
db/schema_migrations/20180723135214
db/schema_migrations/20180726172057
db/schema_migrations/20180807153545
db/schema_migrations/20180808162000
db/schema_migrations/20180809195358
db/schema_migrations/20180813101999
db/schema_migrations/20180813102000
db/schema_migrations/20180814153625
db/schema_migrations/20180815040323
db/schema_migrations/20180815160409
db/schema_migrations/20180815170510
db/schema_migrations/20180815175440
db/schema_migrations/20180816161409
db/schema_migrations/20180816193530
db/schema_migrations/20180824202952
db/schema_migrations/20180826111825
db/schema_migrations/20180831164905
db/schema_migrations/20180831164907
db/schema_migrations/20180831164908
db/schema_migrations/20180831164909
db/schema_migrations/20180831164910
db/schema_migrations/20180901171833
db/schema_migrations/20180901200537
db/schema_migrations/20180902070406
db/schema_migrations/20180906101639
db/schema_migrations/20180907015926
db/schema_migrations/20180910115836
db/schema_migrations/20180910153412
db/schema_migrations/20180910153413
db/schema_migrations/20180912111628
db/schema_migrations/20180913142237
db/schema_migrations/20180914162043
db/schema_migrations/20180914201132
db/schema_migrations/20180916011959
db/schema_migrations/20180917172041
db/schema_migrations/20180924141949
db/schema_migrations/20180924190739
db/schema_migrations/20180924201039
db/schema_migrations/20180925200829
db/schema_migrations/20180927073410
db/schema_migrations/20181002172433
db/schema_migrations/20181005110927
db/schema_migrations/20181005125926
db/schema_migrations/20181006004100
db/schema_migrations/20181008145341
db/schema_migrations/20181008145359
db/schema_migrations/20181008200441
db/schema_migrations/20181009190428
db/schema_migrations/20181010133639
db/schema_migrations/20181010235606
db/schema_migrations/20181013005024
db/schema_migrations/20181014203236
db/schema_migrations/20181015155839
db/schema_migrations/20181016141739
db/schema_migrations/20181016152238
db/schema_migrations/20181017001059
db/schema_migrations/20181019032400
db/schema_migrations/20181019032408
db/schema_migrations/20181019105553
db/schema_migrations/20181022135539
db/schema_migrations/20181022173835
db/schema_migrations/20181023104858
db/schema_migrations/20181023144439
db/schema_migrations/20181025115728
db/schema_migrations/20181026091631
db/schema_migrations/20181026143227
db/schema_migrations/20181027114222
db/schema_migrations/20181028120717
db/schema_migrations/20181030135124
db/schema_migrations/20181030154446
db/schema_migrations/20181031145139
db/schema_migrations/20181031190558
db/schema_migrations/20181031190559
db/schema_migrations/20181101091005
db/schema_migrations/20181101091124
db/schema_migrations/20181101144347
db/schema_migrations/20181101191341
db/schema_migrations/20181105201455
db/schema_migrations/20181106135939
db/schema_migrations/20181107054254
db/schema_migrations/20181108091549
db/schema_migrations/20181112103239
db/schema_migrations/20181115140140
db/schema_migrations/20181116050532
db/schema_migrations/20181116141415
db/schema_migrations/20181116141504
db/schema_migrations/20181119081539
db/schema_migrations/20181119132520
db/schema_migrations/20181120082911
db/schema_migrations/20181120091639
db/schema_migrations/20181120151656
db/schema_migrations/20181121101842
db/schema_migrations/20181121101843
db/schema_migrations/20181121111200
db/schema_migrations/20181122160027
db/schema_migrations/20181123042307
db/schema_migrations/20181123135036
db/schema_migrations/20181123144235
db/schema_migrations/20181126150622
db/schema_migrations/20181126153547
db/schema_migrations/20181128123704
db/schema_migrations/20181129104854
db/schema_migrations/20181129104944
db/schema_migrations/20181130102132
db/schema_migrations/20181203002526
db/schema_migrations/20181205171941
db/schema_migrations/20181211092510
db/schema_migrations/20181211092514
db/schema_migrations/20181212104941
db/schema_migrations/20181212171634
db/schema_migrations/20181219130552
db/schema_migrations/20181219145520
db/schema_migrations/20181219145521
# Removed in 71a3b0e470c64fccbb902390b1f856ee1547a978
db/schema_migrations/20190225160300
# Removed in 44f9d16edca328e5bb234b853f0d670ee0b30a26
db/schema_migrations/20200615101135
# Removed in cfae6ec2647
db/schema_migrations/20180502134117
db/schema_migrations/20180521162137
db/schema_migrations/20180619121030
db/schema_migrations/20180723130817
db/schema_migrations/20180906051323
db/schema_migrations/20180913051323
db/schema_migrations/20180916014356
db/schema_migrations/20181014121030
db/schema_migrations/20181204154019
db/schema_migrations/20180103234731
db/schema_migrations/20180104001824
db/schema_migrations/20180105233807
db/schema_migrations/20180109150457
db/schema_migrations/20180115013218
db/schema_migrations/20180126165535
db/schema_migrations/20180131104538
db/schema_migrations/20180201101405
db/schema_migrations/20180201192230
db/schema_migrations/20180206184810
db/schema_migrations/20180215143644
db/schema_migrations/20180225180932
db/schema_migrations/20180302230551
db/schema_migrations/20180307164427
db/schema_migrations/20180308234102
db/schema_migrations/20180314174825
db/schema_migrations/20180317020334
db/schema_migrations/20180320142552
db/schema_migrations/20180325034910
db/schema_migrations/20180329230151
db/schema_migrations/20180401213713
db/schema_migrations/20180416112831
db/schema_migrations/20180416205949
db/schema_migrations/20180419031622
db/schema_migrations/20180419171038
db/schema_migrations/20180423165301
db/schema_migrations/20180502124117
db/schema_migrations/20180502125859
db/schema_migrations/20180503154922
db/schema_migrations/20180520211048
db/schema_migrations/20180524115107
db/schema_migrations/20180531031410
db/schema_migrations/20180531221734
db/schema_migrations/20180607154422
db/schema_migrations/20180607154516
db/schema_migrations/20180607154645
db/schema_migrations/20180612175636
db/schema_migrations/20180615152524
db/schema_migrations/20180621100024
db/schema_migrations/20180621100025
db/schema_migrations/20180623053658
db/schema_migrations/20180626171125
db/schema_migrations/20180702114215
db/schema_migrations/20180702181530
db/schema_migrations/20180709153607
db/schema_migrations/20180709183353
db/schema_migrations/20180709184533
db/schema_migrations/20180711014025
db/schema_migrations/20180711014026
db/schema_migrations/20180718100455
db/schema_migrations/20180719161844
db/schema_migrations/20180720082636
db/schema_migrations/20180720120716
db/schema_migrations/20180720120726
db/schema_migrations/20180720121404
db/schema_migrations/20180723023517
db/schema_migrations/20180723081631
db/schema_migrations/20180723134433
db/schema_migrations/20180724161450
db/schema_migrations/20180803001726
db/schema_migrations/20180803041220
db/schema_migrations/20180806145747
db/schema_migrations/20180823132905
db/schema_migrations/20180831134049
db/schema_migrations/20180831152625
db/schema_migrations/20180910104020
db/schema_migrations/20180910105100
db/schema_migrations/20180912113336
db/schema_migrations/20180917145556
db/schema_migrations/20180917171038
db/schema_migrations/20180917171533
db/schema_migrations/20180917171534
db/schema_migrations/20180917171535
db/schema_migrations/20180917213751
db/schema_migrations/20180917214204
db/schema_migrations/20180920043317
db/schema_migrations/20180924070647
db/schema_migrations/20180926101838
db/schema_migrations/20180926140319
db/schema_migrations/20180930171532
db/schema_migrations/20181001172126
db/schema_migrations/20181001172651
db/schema_migrations/20181004131020
db/schema_migrations/20181004131025
db/schema_migrations/20181012151642
db/schema_migrations/20181017131623
db/schema_migrations/20181022131445
db/schema_migrations/20181025000427
db/schema_migrations/20181025030732
db/schema_migrations/20181026085436
db/schema_migrations/20181028092114
db/schema_migrations/20181028092115
db/schema_migrations/20181105122803
db/schema_migrations/20181114163403
db/schema_migrations/20181121174028
db/schema_migrations/20181121175359
db/schema_migrations/20181123090058
db/schema_migrations/20181123100058
db/schema_migrations/20181126125616
db/schema_migrations/20181127130125
db/schema_migrations/20181127133629
db/schema_migrations/20181127203117
db/schema_migrations/20181201151856
db/schema_migrations/20181203154104
db/schema_migrations/20181204031328
db/schema_migrations/20181204031329
db/schema_migrations/20181204031330
db/schema_migrations/20181204031331
db/schema_migrations/20181204135519
db/schema_migrations/20181204135932
db/schema_migrations/20181205093951
db/schema_migrations/20181206121338
db/schema_migrations/20181220163029
db/schema_migrations/20181221135205
db/schema_migrations/20181228140935
db/schema_migrations/20190110200434
db/schema_migrations/20190111183834
db/schema_migrations/20190114040404
db/schema_migrations/20190114040405
db/schema_migrations/20190121140418
db/schema_migrations/20190121140658
db/schema_migrations/20190122101816
db/schema_migrations/20190123211816
db/schema_migrations/20190128104236
db/schema_migrations/20190128172533
db/schema_migrations/20190129013538
db/schema_migrations/20190130164903
db/schema_migrations/20190218031401
db/schema_migrations/20190218144405
db/schema_migrations/20190219134239
db/schema_migrations/20190219210244
db/schema_migrations/20190220112238
db/schema_migrations/20190222105948
db/schema_migrations/20190222110418
db/schema_migrations/20190225173106
db/schema_migrations/20190226154144
db/schema_migrations/20190228134845
db/schema_migrations/20190301095211
db/schema_migrations/20190301182031
db/schema_migrations/20190302144241
db/schema_migrations/20190304020812
db/schema_migrations/20190304223216
db/schema_migrations/20190304223220
db/schema_migrations/20190305162221
db/schema_migrations/20190318020549
db/schema_migrations/20190318021429
db/schema_migrations/20190318120957
db/schema_migrations/20190320162221
db/schema_migrations/20190321103531
db/schema_migrations/20190322145954
db/schema_migrations/20190327085945
db/schema_migrations/20190328210840
db/schema_migrations/20190401150745
db/schema_migrations/20190401150746
db/schema_migrations/20190402112450
db/schema_migrations/20180309215236
db/schema_migrations/20180314172513
db/schema_migrations/20180417102933
db/schema_migrations/20180502130136
db/schema_migrations/20180509091305
db/schema_migrations/20180605213516
db/schema_migrations/20180608150653
db/schema_migrations/20180618193715
db/schema_migrations/20180713171825
db/schema_migrations/20180815043102
db/schema_migrations/20180914195058
db/schema_migrations/20181014131030
db/schema_migrations/20181115140251
db/schema_migrations/20181116100917
db/schema_migrations/20181204040404
db/schema_migrations/20181206121340
db/schema_migrations/20181215161939
db/schema_migrations/20181220165848
db/schema_migrations/20190111231855
# Removed in ef1efa0f650
db/schema_migrations/20180406204716
db/schema_migrations/20180521171529
db/schema_migrations/20180831164904
# Removed in 28ac2d30498
db/schema_migrations/20180202111106
# Removed in b87dcc238a8
db/schema_migrations/20181218192239
# Removed in various revert commits
db/schema_migrations/20180115094742
db/schema_migrations/20180115113902
db/schema_migrations/20190107151029
db/schema_migrations/20190114184258
db/schema_migrations/20190228092516
db/schema_migrations/20190311132500
db/schema_migrations/20190311132527
db/schema_migrations/20190703001116
db/schema_migrations/20190703001120
db/schema_migrations/20190724091326
db/schema_migrations/20190801072937
db/schema_migrations/20191004134055
db/schema_migrations/20191029060358
db/schema_migrations/20191029061556
db/schema_migrations/20191220102807
db/schema_migrations/20200123092602
db/schema_migrations/20200123101859
db/schema_migrations/20200127111953
db/schema_migrations/20200127131953
db/schema_migrations/20200127141953
db/schema_migrations/20200127151953
db/schema_migrations/20200206111847
db/schema_migrations/20200214173000
db/schema_migrations/20200214174519
db/schema_migrations/20200214174607
db/schema_migrations/20200309105539
db/schema_migrations/20200615203153

View file

@ -10,12 +10,13 @@ stages:
- qa - qa
- post-qa - post-qa
- pages - pages
- notify
# always use `gitlab-org` runners, however # always use `gitlab-org` runners, however
# in cases where jobs require Docker-in-Docker, the job # in cases where jobs require Docker-in-Docker, the job
# definition must be extended with `.use-docker-in-docker` # definition must be extended with `.use-docker-in-docker`
default: default:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34"
tags: tags:
- gitlab-org - gitlab-org
# All jobs are interruptible by default # All jobs are interruptible by default
@ -62,6 +63,27 @@ variables:
ELASTIC_URL: "http://elastic:changeme@elasticsearch:9200" ELASTIC_URL: "http://elastic:changeme@elasticsearch:9200"
DOCKER_VERSION: "19.03.0" DOCKER_VERSION: "19.03.0"
# Preparing custom clone path to reduce space used by all random forks
# on GitLab.com's Shared Runners. Our main forks - especially the security
# ones - will have this variable overwritten in the project settings, so that
# a security-related code or code using our protected variables will be never
# stored on the same path as the community forks.
# Part of the solution for the `no space left on device` problem described at
# https://gitlab.com/gitlab-org/gitlab/issues/197876.
#
# For this purpose the https://gitlab.com/gitlab-org-forks group was created
# to host a placeholder for the `/builds/gitlab-org-forks` path and ensure
# that no legitimate project will ever use it and - by mistake - execute its
# job on a shared working directory. It also requires proper configuration of
# the Runner that executes the job (which was prepared for our shared runners
# by https://ops.gitlab.net/gitlab-cookbooks/chef-repo/-/merge_requests/3977).
#
# Because of all of that PLEASE DO NOT CHANGE THE PATH.
#
# For more details and reasoning that brought this change please check
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24887
GIT_CLONE_PATH: "/builds/gitlab-org-forks/${CI_PROJECT_NAME}"
include: include:
- local: .gitlab/ci/build-images.gitlab-ci.yml - local: .gitlab/ci/build-images.gitlab-ci.yml
- local: .gitlab/ci/cache-repo.gitlab-ci.yml - local: .gitlab/ci/cache-repo.gitlab-ci.yml
@ -81,3 +103,4 @@ include:
- local: .gitlab/ci/test-metadata.gitlab-ci.yml - local: .gitlab/ci/test-metadata.gitlab-ci.yml
- local: .gitlab/ci/yaml.gitlab-ci.yml - local: .gitlab/ci/yaml.gitlab-ci.yml
- local: .gitlab/ci/releases.gitlab-ci.yml - local: .gitlab/ci/releases.gitlab-ci.yml
- local: .gitlab/ci/notify.gitlab-ci.yml

View file

@ -2,13 +2,12 @@
# project here: https://gitlab.com/gitlab-org/gitlab/-/project_members # project here: https://gitlab.com/gitlab-org/gitlab/-/project_members
# As described in https://docs.gitlab.com/ee/user/project/code_owners.html # As described in https://docs.gitlab.com/ee/user/project/code_owners.html
# Backend Maintainers are the default for all ruby files [Backend]
*.rb @gitlab-org/maintainers/rails-backend *.rb @gitlab-org/maintainers/rails-backend
*.rake @gitlab-org/maintainers/rails-backend *.rake @gitlab-org/maintainers/rails-backend
# Technical writing team are the default reviewers for all markdown docs [Documentation]
/doc/ @gl-docsteam /doc/ @gl-docsteam
# Doc subpaths
/doc/administration/monitoring/ @aqualls /doc/administration/monitoring/ @aqualls
/doc/development/ @marcia @mjang1 /doc/development/ @marcia @mjang1
/doc/development/documentation/ @mikelewis /doc/development/documentation/ @mikelewis
@ -19,7 +18,127 @@
/doc/user/project/clusters @aqualls /doc/user/project/clusters @aqualls
/doc/.vale/ @marcel.amirault @eread @aqualls @mikelewis /doc/.vale/ @marcel.amirault @eread @aqualls @mikelewis
# Frontend maintainers should see everything in `app/assets/` [Docs Create]
/doc/user/project/merge_requests/allow_collaboration.md @marcia
/doc/user/project/merge_requests/authorization_for_merge_requests.md @marcia
/doc/user/project/merge_requests/cherry_pick_changes.md @marcia
/doc/user/project/merge_requests/creating_merge_requests.md @marcia
/doc/user/project/merge_requests/fast_forward_merge.md @marcia
/doc/user/project/merge_requests/getting_started.md @marcia
/doc/user/project/merge_requests/index.md @marcia
/doc/user/project/merge_requests/merge_request_approvals.md @marcia
/doc/user/project/merge_requests/merge_request_dependencies.md @marcia
/doc/user/project/merge_requests/resolve_conflicts.md @marcia
/doc/user/project/merge_requests/revert_changes.md @marcia
/doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md @marcia
/doc/user/project/merge_requests/squash_and_merge.md @marcia
/doc/user/project/merge_requests/work_in_progress_merge_requests.md @marcia
/doc/user/project/repository/file_finder.md @marcia
/doc/user/project/repository/forking_workflow.md @marcia
/doc/user/project/repository/git_blame.md @marcia
/doc/user/project/repository/git_history.md @marcia
/doc/user/project/repository/index.md @marcia
/doc/user/project/repository/repository_mirroring.md @marcia
/doc/user/project/repository/web_editor.md @marcia
/doc/user/project/autocomplete_characters.md @marcia
/doc/user/project/badges.md @marcia
/doc/user/project/code_intelligence.md @marcia
/doc/user/project/code_owners.md @marcia
/doc/user/project/file_lock.md @marcia
/doc/user/project/git_attributes.md @marcia
/doc/user/project/highlighting.md @marcia
/doc/user/project/index.md @marcia
/doc/user/project/protected_branches.md @marcia
/doc/user/project/protected_tags.md @marcia
/doc/user/project/push_options.md @marcia
/doc/user/project/repository/branches/index.md @marcia
/doc/user/project/repository/gpg_signed_commits/index.md @marcia
/doc/user/project/repository/jupyter_notebooks/index.md @marcia
/doc/user/project/repository/x509_signed_commits/index.md @marcia
/doc/user/project/settings/import_export.md @marcia
/doc/user/project/settings/index.md @marcia
/doc/user/project/settings/project_access_tokens.md @marcia
/doc/user/project/static_site_editor/index.md @marcia
/doc/user/project/web_ide/index.md @marcia
/doc/user/project/wiki/index.md @marcia
/doc/gitlab-basics/README.md @marcia
/doc/gitlab-basics/add-file.md @marcia
/doc/gitlab-basics/command-line-commands.md @marcia
/doc/gitlab-basics/create-branch.md @marcia
/doc/gitlab-basics/create-project.md @marcia
/doc/gitlab-basics/create-your-ssh-keys.md @marcia
/doc/gitlab-basics/feature_branch_workflow.md @marcia
/doc/gitlab-basics/fork-project.md @marcia
/doc/gitlab-basics/start-using-git.md @marcia
/doc/integration/sourcegraph.md @marcia
/doc/intro/README.md @marcia
/doc/push_rules/push_rules.md @marcia
/doc/ssh/README.md @marcia
/doc/topics/git/feature_branch_development.md @marcia
/doc/topics/git/how_to_install_git/index.md @marcia
/doc/topics/git/index.md @marcia
/doc/topics/git/lfs/index.md @marcia
/doc/topics/git/lfs/migrate_from_git_annex_to_git_lfs.md @marcia
/doc/topics/git/numerous_undo_possibilities_in_git/index.md @marcia
/doc/topics/git/partial_clone.md @marcia
/doc/topics/git/troubleshooting_git.md @marcia
/doc/topics/git/useful_git_commands.md @marcia
/doc/topics/gitlab_flow.md @marcia
/doc/user/index.md @marcia
/doc/user/snippets.md @marcia
/doc/administration/issue_closing_pattern.md @marcia
/doc/user/asciidoc.md @marcia
/doc/user/markdown.md @marcia
/doc/user/search/advanced_global_search.md @marcia
/doc/user/search/advanced_search_syntax.md @marcia
/doc/user/search/index.md @marcia
/doc/administration/file_hooks.md @marcia
/doc/administration/git_annex.md @marcia
/doc/administration/git_protocol.md @marcia
/doc/administration/integration/plantuml.md @marcia
/doc/administration/invalidate_markdown_cache.md @marcia
/doc/administration/issue_closing_pattern.md @marcia
/doc/administration/lfs/index.md @marcia
/doc/administration/merge_request_diffs.md @marcia
/doc/administration/repository_checks.md @marcia
/doc/administration/snippets/index.md @marcia
/doc/administration/static_objects_external_storage.md @marcia
/doc/api/access_requests.md @marcia
/doc/api/branches.md @marcia
/doc/api/commits.md @marcia
/doc/api/discussions.md @marcia
/doc/api/group_wikis.md @marcia
/doc/api/keys.md @marcia
/doc/api/markdown.md @marcia
/doc/api/merge_request_approvals.md @marcia
/doc/api/merge_request_context_commits.md @marcia
/doc/api/merge_requests.md @marcia
/doc/api/project_aliases.md @marcia
/doc/api/project_badges.md @marcia
/doc/api/project_import_export.md @marcia
/doc/api/project_level_variables.md @marcia
/doc/api/project_snippets.md @marcia
/doc/api/project_statistics.md @marcia
/doc/api/project_templates.md @marcia
/doc/api/project_vulnerabilities.md @marcia
/doc/api/protected_branches.md @marcia
/doc/api/protected_tags.md @marcia
/doc/api/remote_mirrors.md @marcia
/doc/api/repositories.md @marcia
/doc/api/repository_files.md @marcia
/doc/api/repository_submodules.md @marcia
/doc/api/search.md @marcia
/doc/api/snippets.md @marcia
/doc/api/suggestions.md @marcia
/doc/api/tags.md @marcia
/doc/api/visual_review_discussions.md @marcia
/doc/api/wikis.md @marcia
/doc/user/admin_area/settings/account_and_limit_settings.md @marcia
/doc/user/admin_area/settings/instance_template_repository.md @marcia
/doc/user/admin_area/settings/push_event_activities_limit.md @marcia
/doc/user/admin_area/settings/visibility_and_access_controls.md @marcia
[Frontend]
*.scss @annabeldunstone @gitlab-org/maintainers/frontend *.scss @annabeldunstone @gitlab-org/maintainers/frontend
*.js @gitlab-org/maintainers/frontend *.js @gitlab-org/maintainers/frontend
/app/assets/ @gitlab-org/maintainers/frontend /app/assets/ @gitlab-org/maintainers/frontend
@ -29,7 +148,7 @@
/spec/frontend/ @gitlab-org/maintainers/frontend /spec/frontend/ @gitlab-org/maintainers/frontend
/ee/spec/frontend/ @gitlab-org/maintainers/frontend /ee/spec/frontend/ @gitlab-org/maintainers/frontend
# Database maintainers should review changes in `db/` [Database]
/db/ @gitlab-org/maintainers/database /db/ @gitlab-org/maintainers/database
/ee/db/ @gitlab-org/maintainers/database /ee/db/ @gitlab-org/maintainers/database
/lib/gitlab/background_migration/ @gitlab-org/maintainers/database /lib/gitlab/background_migration/ @gitlab-org/maintainers/database
@ -41,19 +160,7 @@
/app/finders/ @gitlab-org/maintainers/database /app/finders/ @gitlab-org/maintainers/database
/ee/app/finders/ @gitlab-org/maintainers/database /ee/app/finders/ @gitlab-org/maintainers/database
# Feature specific owners [Engineering Productivity]
/ee/lib/ee/gitlab/auth/ldap/ @dblessing @mkozono
/lib/gitlab/auth/ldap/ @dblessing @mkozono
/lib/gitlab/ci/templates/ @nolith @dosuken123
/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah
/lib/gitlab/ci/templates/Security/ @plafoucriere @gonzoyumo @twoodham @sethgitlab
/ee/app/models/project_alias.rb @patrickbajao
/ee/lib/api/project_aliases.rb @patrickbajao
# Quality owned files
/qa/ @gl-quality
# Engineering Productivity owned files
/.gitlab-ci.yml @gl-quality/eng-prod /.gitlab-ci.yml @gl-quality/eng-prod
/.gitlab/ci/ @gl-quality/eng-prod /.gitlab/ci/ @gl-quality/eng-prod
/.gitlab/ci/docs.gitlab-ci.yml @gl-quality/eng-prod @gl-docsteam /.gitlab/ci/docs.gitlab-ci.yml @gl-quality/eng-prod @gl-docsteam
@ -66,16 +173,45 @@ Dangerfile @gl-quality/eng-prod
/scripts/frontend/ @gl-quality/eng-prod @gitlab-org/maintainers/frontend /scripts/frontend/ @gl-quality/eng-prod @gitlab-org/maintainers/frontend
.editorconfig @gl-quality/eng-prod .editorconfig @gl-quality/eng-prod
# Telemetry owner files [End-to-end]
/ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/telemetry /qa/ @gl-quality
/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/telemetry
/lib/gitlab/grafana_embed_usage_data.rb @gitlab-org/growth/telemetry [LDAP]
/lib/gitlab/usage_data.rb @gitlab-org/growth/telemetry /ee/lib/ee/gitlab/auth/ldap/ @dblessing @mkozono
/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/telemetry /lib/gitlab/auth/ldap/ @dblessing @mkozono
/lib/gitlab/usage_data_counters/ @gitlab-org/growth/telemetry
[Templates]
/lib/gitlab/ci/templates/ @nolith @dosuken123
/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah
/lib/gitlab/ci/templates/Security/ @plafoucriere @gonzoyumo @twoodham @sethgitlab
[Project Alias]
/ee/app/models/project_alias.rb @patrickbajao
/ee/lib/api/project_aliases.rb @patrickbajao
# Secure & Threat Management ownership delineation
# https://about.gitlab.com/handbook/engineering/development/threat-management/delineate-secure-threat-management.html#technical-boundaries
[Secure]
/ee/app/models/vulnerability.rb @gitlab-org/secure/threat-insights-backend-team
/ee/app/models/security/ @gitlab-org/secure/threat-insights-backend-team
/ee/app/models/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team
/ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be
/ee/lib/gitlab/ci/parsers/security/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis-be @gitlab-org/secure/static-analysis-be @gitlab-org/secure/fuzzing-be
/ee/lib/gitlab/ci/reports/coverage_fuzzing/ @gitlab-org/secure/fuzzing-be
/ee/lib/gitlab/ci/reports/dependency_list/ @gitlab-org/secure/composition-analysis-be
/ee/lib/gitlab/ci/reports/license_scanning/ @gitlab-org/secure/composition-analysis-be
/ee/lib/gitlab/ci/reports/security/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis-be @gitlab-org/secure/static-analysis-be @gitlab-org/secure/fuzzing-be
[Code Owners] [Code Owners]
/ee/lib/gitlab/code_owners.rb @reprazent @kerrizor @garyh /ee/lib/gitlab/code_owners.rb @reprazent @kerrizor @garyh
/ee/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh /ee/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
/ee/spec/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh /ee/spec/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
/doc/user/project/code_owners.md @reprazent @kerrizor @garyh /doc/user/project/code_owners.md @reprazent @kerrizor @garyh
[Telemetry]
/ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/telemetry/engineers
/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/telemetry/engineers
/lib/gitlab/grafana_embed_usage_data.rb @gitlab-org/growth/telemetry/engineers
/lib/gitlab/usage_data.rb @gitlab-org/growth/telemetry/engineers
/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/telemetry/engineers
/lib/gitlab/usage_data_counters/ @gitlab-org/growth/telemetry/engineers

View file

@ -27,7 +27,7 @@
review-docs-deploy: review-docs-deploy:
extends: .review-docs extends: .review-docs
script: script:
- ./scripts/trigger-build-docs deploy - ./scripts/trigger-build docs deploy
# Cleanup remote environment of gitlab-docs # Cleanup remote environment of gitlab-docs
review-docs-cleanup: review-docs-cleanup:
@ -36,7 +36,7 @@ review-docs-cleanup:
name: review-docs/$DOCS_GITLAB_REPO_SUFFIX-$CI_MERGE_REQUEST_IID name: review-docs/$DOCS_GITLAB_REPO_SUFFIX-$CI_MERGE_REQUEST_IID
action: stop action: stop
script: script:
- ./scripts/trigger-build-docs cleanup - ./scripts/trigger-build docs cleanup
docs lint: docs lint:
extends: extends:

View file

@ -11,7 +11,7 @@
extends: extends:
- .frontend-base - .frontend-base
- .assets-compile-cache - .assets-compile-cache
image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-git-2.27-lfs-2.9-node-12.x-yarn-1.21-graphicsmagick-1.3.34 image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-git-2.28-lfs-2.9-node-12.x-yarn-1.21-graphicsmagick-1.3.34
variables: variables:
WEBPACK_VENDOR_DLL: "true" WEBPACK_VENDOR_DLL: "true"
stage: prepare stage: prepare

View file

@ -64,39 +64,39 @@
policy: pull policy: pull
.use-pg11: .use-pg11:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34"
services: services:
- name: postgres:11.6 - name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:4.0-alpine
variables: variables:
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
.use-pg12: .use-pg12:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34"
services: services:
- name: postgres:12 - name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:4.0-alpine
variables: variables:
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
.use-pg11-ee: .use-pg11-ee:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34"
services: services:
- name: postgres:11.6 - name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:4.0-alpine
- name: elasticsearch:6.4.2 - name: elasticsearch:6.4.2
variables: variables:
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
.use-pg12-ee: .use-pg12-ee:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34"
services: services:
- name: postgres:12 - name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:4.0-alpine
- name: elasticsearch:6.4.2 - name: elasticsearch:6.4.2
variables: variables:
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust

View file

@ -0,0 +1,23 @@
.notify-slack:
image: alpine
stage: notify
dependencies: []
cache: {}
before_script:
- apk update && apk add git curl bash
notify-update-gitaly:
extends:
- .notify-slack
rules:
- if: '$CI_MERGE_REQUEST_IID && $CI_COMMIT_BRANCH == $GITALY_UPDATE_BRANCH'
when: on_failure
allow_failure: true
variables:
NOTIFY_CHANNEL: g_create_gitaly
GITALY_UPDATE_BRANCH: release-tools/update-gitaly
MERGE_REQUEST_URL: ${CI_MERGE_REQUEST_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}
script:
- echo "NOTIFY_CHANNEL is ${NOTIFY_CHANNEL}"
- echo "CI_PIPELINE_URL is ${CI_PIPELINE_URL}"
- scripts/slack ${NOTIFY_CHANNEL} "☠️ \`${GITALY_UPDATE_BRANCH}\` failed! ☠️ See ${CI_PIPELINE_URL} (triggered from ${MERGE_REQUEST_URL})" ci_failing

View file

@ -59,6 +59,10 @@ package-and-qa:
extends: extends:
- .package-and-qa-base - .package-and-qa-base
- .qa:rules:package-and-qa - .qa:rules:package-and-qa
# This job often times out, so temporarily use private runners and a long timeout: https://gitlab.com/gitlab-org/gitlab/-/issues/238563
tags:
- prm
timeout: 4h
needs: needs:
- job: build-qa-image - job: build-qa-image
artifacts: false artifacts: false

View file

@ -70,7 +70,6 @@
- run_timed_command "scripts/gitaly-test-build" - run_timed_command "scripts/gitaly-test-build"
- run_timed_command "scripts/gitaly-test-spawn" - run_timed_command "scripts/gitaly-test-spawn"
- source scripts/rspec_helpers.sh - source scripts/rspec_helpers.sh
- scripts/prepare_postgres_fdw.sh
- rspec_paralellized_job "--tag ~quarantine --tag geo" - rspec_paralellized_job "--tag ~quarantine --tag geo"
.rspec-ee-base-geo-pg11: .rspec-ee-base-geo-pg11:

View file

@ -15,7 +15,7 @@ code_quality:
stage: test stage: test
needs: [] needs: []
variables: variables:
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.10" CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.10-gitlab.1"
script: script:
- | - |
if ! docker info &>/dev/null; then if ! docker info &>/dev/null; then
@ -58,7 +58,7 @@ code_quality:
SAST_ANALYZER_IMAGE_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers" SAST_ANALYZER_IMAGE_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
SAST_ANALYZER_IMAGE_TAG: 2 SAST_ANALYZER_IMAGE_TAG: 2
SAST_BRAKEMAN_LEVEL: 2 # GitLab-specific SAST_BRAKEMAN_LEVEL: 2 # GitLab-specific
SAST_EXCLUDED_PATHS: qa,spec,doc,ee/spec # GitLab-specific SAST_EXCLUDED_PATHS: qa,spec,doc,ee/spec,config/gitlab.yml.example # GitLab-specific
SAST_DISABLE_BABEL: "true" SAST_DISABLE_BABEL: "true"
script: script:
- /analyzer run - /analyzer run
@ -150,35 +150,35 @@ dependency_scanning:
## We need to duplicate this job's definition because it seems it's impossible to ## We need to duplicate this job's definition because it seems it's impossible to
## override an included `only.refs`. ## override an included `only.refs`.
## See https://gitlab.com/gitlab-org/gitlab/issues/31371. ## See https://gitlab.com/gitlab-org/gitlab/issues/31371.
#dast: # dast:
# extends: # extends:
# - .default-retry # - .default-retry
# - .reports:rules:dast # - .reports:rules:dast
# # This is needed so that manual jobs with needs don't block the pipeline. # # This is needed so that manual jobs with needs don't block the pipeline.
# # See https://gitlab.com/gitlab-org/gitlab/-/issues/199979. # # See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
# dependencies: ["review-deploy"] # dependencies: ["review-deploy"]
# stage: qa # GitLab-specific # stage: qa # GitLab-specific
# image: # image:
# name: "registry.gitlab.com/gitlab-org/security-products/dast:$DAST_VERSION" # name: "registry.gitlab.com/gitlab-org/security-products/dast:$DAST_VERSION"
# variables: # variables:
# # To be done in a later iteration # # To be done in a later iteration
# # DAST_USERNAME: "root" # # DAST_USERNAME: "root"
# # DAST_USERNAME_FIELD: "user[login]" # # DAST_USERNAME_FIELD: "user[login]"
# # DAST_PASSWORD_FIELD: "user[passowrd]" # # DAST_PASSWORD_FIELD: "user[passowrd]"
# DAST_VERSION: 1 # DAST_VERSION: 1
# script: # script:
# - 'export DAST_WEBSITE="${DAST_WEBSITE:-$(cat environment_url.txt)}"' # - 'export DAST_WEBSITE="${DAST_WEBSITE:-$(cat environment_url.txt)}"'
# # To be done in a later iteration # # To be done in a later iteration
# # - 'export DAST_AUTH_URL="${DAST_WEBSITE}/users/sign_in"' # # - 'export DAST_AUTH_URL="${DAST_WEBSITE}/users/sign_in"'
# # - 'export DAST_PASSWORD="${REVIEW_APPS_ROOT_PASSWORD}"' # # - 'export DAST_PASSWORD="${REVIEW_APPS_ROOT_PASSWORD}"'
# - /analyze -t $DAST_WEBSITE # - /analyze -t $DAST_WEBSITE
# timeout: 4h # timeout: 4h
# artifacts: # artifacts:
# paths: # paths:
# - gl-dast-report.json # GitLab-specific # - gl-dast-report.json # GitLab-specific
# reports: # reports:
# dast: gl-dast-report.json # dast: gl-dast-report.json
# expire_in: 1 week # GitLab-specific # expire_in: 1 week # GitLab-specific
# To be done in a later iteration: https://gitlab.com/gitlab-org/gitlab/issues/31160#note_278188255 # To be done in a later iteration: https://gitlab.com/gitlab-org/gitlab/issues/31160#note_278188255
# schedule:dast: # schedule:dast:

View file

@ -125,6 +125,7 @@
.db-patterns: &db-patterns .db-patterns: &db-patterns
- "{,ee/}{,spec/}{db,migrations}/**/*" - "{,ee/}{,spec/}{db,migrations}/**/*"
- "{,ee/}{,spec/}lib/{,ee/}gitlab/background_migration/**/*" - "{,ee/}{,spec/}lib/{,ee/}gitlab/background_migration/**/*"
- "config/prometheus/common_metrics.yml" # Used by Gitlab::DatabaseImporters::CommonMetrics::Importer
.backstage-patterns: &backstage-patterns .backstage-patterns: &backstage-patterns
- "Dangerfile" - "Dangerfile"

View file

@ -3,7 +3,7 @@
<!-- NOTE: Please add a DevOps stage label (format `devops:<stage_name>`) <!-- NOTE: Please add a DevOps stage label (format `devops:<stage_name>`)
and assign the technical writer who is and assign the technical writer who is
[listed for that stage](https://about.gitlab.com/handbook/product/categories/#devops-stages). --> [listed for that stage](https://about.gitlab.com/handbook/product/product-categories/#devops-stages). -->
## References ## References

View file

@ -24,7 +24,7 @@
* Any concepts, procedures, reference info we could add to make it easier to successfully use GitLab? * Any concepts, procedures, reference info we could add to make it easier to successfully use GitLab?
* Include use cases, benefits, and/or goals for this work. * Include use cases, benefits, and/or goals for this work.
* If adding content: What audience is it intended for? (What roles and scenarios?) * If adding content: What audience is it intended for? (What roles and scenarios?)
For ideas, see personas at https://design.gitlab.com/research/personas or the persona labels at For ideas, see personas at https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/ or the persona labels at
https://gitlab.com/groups/gitlab-org/-/labels?utf8=%E2%9C%93&subscribed=&search=persona%3A https://gitlab.com/groups/gitlab-org/-/labels?utf8=%E2%9C%93&subscribed=&search=persona%3A
--> -->

View file

@ -12,7 +12,7 @@ Remove the `:feature_name` feature flag ...
## Expectations ## Expectations
### What are we expecting to happen? ### What are we expecting to happen?
### What might happen if this goes wrong? ### What might happen if this goes wrong?

View file

@ -1,8 +1,8 @@
<!-- The first four sections: "Problem to solve", "Intended users", "User experience goal", and "Proposal", are strongly recommended, while the rest of the sections can be filled out during the problem validation or breakdown phase. However, keep in mind that providing complete and relevant information early helps our product team validate the problem and start working on a solution. --> <!-- The first four sections: "Problem to solve", "Intended users", "User experience goal", and "Proposal", are strongly recommended, while the rest of the sections can be filled out during the problem validation or breakdown phase. However, keep in mind that providing complete and relevant information early helps our product team validate the problem and start working on a solution. -->
### Problem to solve ### Problem to solve
<!-- What problem do we solve? Try to define the who/what/why of the opportunity as a user story. For example, "As a (who), I want (what), so I can (why/value)." --> <!-- What problem do we solve? Try to define the who/what/why of the opportunity as a user story. For example, "As a (who), I want (what), so I can (why/value)." -->
### Intended users ### Intended users
@ -78,7 +78,7 @@ See the test engineering planning process and reach out to your counterpart Soft
### What is the type of buyer? ### What is the type of buyer?
<!-- What is the buyer persona for this feature? See https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/buyer-persona/ <!-- What is the buyer persona for this feature? See https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/buyer-persona/
In which enterprise tier should this feature go? See https://about.gitlab.com/handbook/product/pricing/#four-tiers --> In which enterprise tier should this feature go? See https://about.gitlab.com/handbook/product/pricing/#four-tiers -->
### Is this a cross-stage feature? ### Is this a cross-stage feature?
@ -87,4 +87,7 @@ In which enterprise tier should this feature go? See https://about.gitlab.com/ha
### Links / references ### Links / references
<!-- Label reminders - you should have one of each of the following labels if you can figure out the correct ones -->
/label ~devops:: ~group: ~Category:
/label ~feature /label ~feature

View file

@ -68,10 +68,10 @@ a nightly pipeline, select ~"found:nightly".
<!-- <!--
https://about.gitlab.com/handbook/engineering/quality/guidelines/#priorities: https://about.gitlab.com/handbook/engineering/quality/guidelines/#priorities:
- ~P1: Tests that are needed to verify fundamental GitLab functionality. - ~P::1: Tests that are needed to verify fundamental GitLab functionality.
- ~P2: Tests that deal with external integrations which may take a longer time to debug and fix. - ~P::2: Tests that deal with external integrations which may take a longer time to debug and fix.
--> -->
/label ~P /label ~P::
<!-- Select the current milestone if ~P1 or the next milestone if ~P2. --> <!-- Select the current milestone if ~P::1 or the next milestone if ~P::2. -->
/milestone % /milestone %

View file

@ -38,4 +38,12 @@ If you are aware of tests that need to be written or adjusted apart from unit te
please list them here. please list them here.
--> -->
/label ~backstage <!--
Please select the appropriate label from the following:
~"feature::addition"
~"feature::maintenance"
~"tooling::pipelines"
~"tooling::workflow"
-->
/label ~"feature::maintenance"

View file

@ -8,12 +8,6 @@ Set the title to: `Security Release: 12.2.X, 12.1.X, and 12.0.X`
------- -------
## Releases tasks
- https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/release-manager.md
- https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md
- https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/security-engineer.md
## Version issues: ## Version issues:
12.2.X, 12.1.X, 12.0.X: {release task link} 12.2.X, 12.1.X, 12.0.X: {release task link}
@ -25,11 +19,15 @@ your security issues as related to this release tracking issue. You can do this
in the "Linked issues" section below this issue description. in the "Linked issues" section below this issue description.
:warning: If your security issues are not marked as related to this release :warning: If your security issues are not marked as related to this release
tracking issue, their merge requests may not be included in the security tracking issue, their merge requests will not be included in the security
release. release.
## QA ### Branches to target in GitLab Security
{QA issue link}
Your Security Implementation Issue should have `4` merge requests associated:
- [master and 3 backports](https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/developer.md#backports)
- Backports should target the stable branches for the versions mentioned included in this Security Release
## Blog post ## Blog post

View file

@ -28,8 +28,8 @@ After your merge request has been approved according to our [approval guidelines
* You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation] * You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation]
- [ ] Create each MR targeting the stable branch `X-Y-stable`, using the [Security Release merge request template]. - [ ] Create each MR targeting the stable branch `X-Y-stable`, using the [Security Release merge request template].
* Every merge request will have its own set of TODOs, so make sure to complete those. * Every merge request will have its own set of TODOs, so make sure to complete those.
- [ ] On the "Related merge requests" section, ensure all MRs are linked to this issue. - [ ] On the "Related merge requests" section, ensure that `4` merge requests are associated: The one targeting `master` and the `3` backports.
* This section should only list the merge requests created for this issue: One targeting `master` and the 3 backports. - [ ] If this issue requires less than `4` merge requests, post a message on the Security Release Tracking Issue and ping the Release Managers.
## Documentation and final details ## Documentation and final details
@ -62,7 +62,6 @@ After your merge request has been approved according to our [approval guidelines
[security process for developers]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md [security process for developers]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md
[secpick documentation]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/utilities/secpick_script.md [secpick documentation]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/utilities/secpick_script.md
[security Release merge request template]: https://gitlab.com/gitlab-org/security/gitlab/blob/master/.gitlab/merge_request_templates/Security%20Release.md [security Release merge request template]: https://gitlab.com/gitlab-org/security/gitlab/blob/master/.gitlab/merge_request_templates/Security%20Release.md
[code review process]: https://docs.gitlab.com/ee/development/code_review.html
[approval guidelines]: https://docs.gitlab.com/ee/development/code_review.html#approval-guidelines [approval guidelines]: https://docs.gitlab.com/ee/development/code_review.html#approval-guidelines
[issue as related]: https://docs.gitlab.com/ee/user/project/issues/related_issues.html#adding-a-related-issue [issue as related]: https://docs.gitlab.com/ee/user/project/issues/related_issues.html#adding-a-related-issue

View file

@ -0,0 +1,31 @@
## Actionable Insights
Actionable insights always have a follow-up action that needs to take place as a result of the research observation or data, and a clear recommendation or action associated with it. An actionable insight both defines the insight and clearly calls out the next step. These insights are tracked over time.
#### Link
- [ ] Provide the link to the Dovetail actionable insight you created earlier (this should contain all the essential details)
- [ ] If applicable, link this actionable insight issue back to the original Research Issue in the GitLab UX Research project
#### Assign
- [ ] Assign this issue to the appropriate Product Manager, Product Designer, or UX Researcher
#### Description
- [ ] Provide some brief detials on the actionable insight and the action to take
-------------------------------------------------------------------------------
| | PLEASE COMPLETE THE BELOW |
| ------ | ------ |
| Dovetail link: | (URL goes here) |
| Details: | (details go here) |
| Action to take: | (action goes here) |
~"Actionable Insight"

View file

@ -113,7 +113,6 @@ linters:
- "app/views/help/instance_configuration.html.haml" - "app/views/help/instance_configuration.html.haml"
- "app/views/help/instance_configuration/_gitlab_ci.html.haml" - "app/views/help/instance_configuration/_gitlab_ci.html.haml"
- "app/views/help/instance_configuration/_gitlab_pages.html.haml" - "app/views/help/instance_configuration/_gitlab_pages.html.haml"
- "app/views/help/ui.html.haml"
- "app/views/import/bitbucket/status.html.haml" - "app/views/import/bitbucket/status.html.haml"
- "app/views/import/bitbucket_server/status.html.haml" - "app/views/import/bitbucket_server/status.html.haml"
- "app/views/invites/show.html.haml" - "app/views/invites/show.html.haml"

View file

@ -7,6 +7,7 @@
"ul-style": { "ul-style": {
"style": "dash" "style": "dash"
}, },
"no-trailing-spaces": false,
"line-length": false, "line-length": false,
"no-duplicate-header": { "no-duplicate-header": {
"allow_different_nesting": true "allow_different_nesting": true

View file

@ -44,6 +44,22 @@ PreCommit:
# on_warn: fail # Treat all warnings as failures # on_warn: fail # Treat all warnings as failures
ScssLint: ScssLint:
enabled: true enabled: true
MarkdownLint:
enabled: true
description: 'Lint documentation for Markdown errors'
required_executable: 'node_modules/.bin/markdownlint'
flags: ['--config', '.markdownlint.json', 'doc/**/*.md']
install_command: 'yarn install'
include:
- 'doc/**/*.md'
Vale:
enabled: true
description: 'Lint documentation for grammatical and formatting errors'
required_executable: 'vale'
flags: ['--config', '.vale.ini', '--minAlertLevel', 'error', 'doc']
install_command: 'brew install vale # (or use another package manager)'
include:
- 'doc/**/*.md'
CommitMsg: CommitMsg:
TextWidth: TextWidth:

View file

@ -9,6 +9,7 @@ require:
inherit_from: inherit_from:
- .rubocop_todo.yml - .rubocop_todo.yml
- ./rubocop/rubocop-migrations.yml - ./rubocop/rubocop-migrations.yml
- ./rubocop/rubocop-usage-data.yml
inherit_mode: inherit_mode:
merge: merge:
@ -335,6 +336,15 @@ Graphql/AuthorizeTypes:
- 'spec/**/*.rb' - 'spec/**/*.rb'
- 'ee/spec/**/*.rb' - 'ee/spec/**/*.rb'
Graphql/JSONType:
Enabled: true
Include:
- 'app/graphql/**/*'
- 'ee/app/graphql/**/*'
Exclude:
- 'spec/**/*.rb'
- 'ee/spec/**/*.rb'
RSpec/EnvAssignment: RSpec/EnvAssignment:
Enable: true Enable: true
Include: Include:
@ -433,6 +443,11 @@ RSpec/HaveGitlabHttpStatus:
Style/MultilineWhenThen: Style/MultilineWhenThen:
Enabled: false Enabled: false
# We use EnforcedStyle of comparison here due to it being better
# performing code as seen in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36221#note_375659681
Style/NumericPredicate:
EnforcedStyle: comparison
Style/FloatDivision: Style/FloatDivision:
Enabled: false Enabled: false
@ -455,8 +470,10 @@ Rails/TimeZone:
Include: Include:
- 'app/controllers/**/*' - 'app/controllers/**/*'
- 'app/services/**/*' - 'app/services/**/*'
- 'lib/**/*'
- 'spec/controllers/**/*' - 'spec/controllers/**/*'
- 'spec/services/**/*' - 'spec/services/**/*'
- 'spec/lib/**/*'
- 'ee/app/controllers/**/*' - 'ee/app/controllers/**/*'
- 'ee/app/services/**/*' - 'ee/app/services/**/*'
- 'ee/spec/controllers/**/*' - 'ee/spec/controllers/**/*'
@ -469,7 +486,8 @@ Rails/TimeZone:
- 'spec/workers/**/*' - 'spec/workers/**/*'
- 'ee/app/workers/**/*' - 'ee/app/workers/**/*'
- 'ee/spec/workers/**/*' - 'ee/spec/workers/**/*'
- 'ee/lib/**/*'
- 'ee/spec/lib/**/*'
# WIP: See https://gitlab.com/gitlab-org/gitlab/-/issues/220040 # WIP: See https://gitlab.com/gitlab-org/gitlab/-/issues/220040
Rails/SaveBang: Rails/SaveBang:
@ -481,3 +499,13 @@ Rails/SaveBang:
- 'ee/spec/**/*.rb' - 'ee/spec/**/*.rb'
- 'qa/spec/**/*.rb' - 'qa/spec/**/*.rb'
- 'qa/qa/specs/**/*.rb' - 'qa/qa/specs/**/*.rb'
Cop/PutProjectRoutesUnderScope:
Include:
- 'config/routes/project.rb'
- 'ee/config/routes/project.rb'
Cop/PutGroupRoutesUnderScope:
Include:
- 'config/routes/group.rb'
- 'ee/config/routes/group.rb'

View file

@ -1,6 +1,6 @@
# This configuration was generated by # This configuration was generated by
# `rubocop --auto-gen-config` # `rubocop --auto-gen-config --exclude-limit 10000`
# on 2020-05-20 16:32:14 -0400 using RuboCop version 0.82.0. # on 2020-08-17 21:05:54 +1200 using RuboCop version 0.82.0.
# The point is for the user to remove these configuration records # The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base. # one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new # Note that changes in the inspected code, or installation of new
@ -25,7 +25,6 @@ Layout/ClosingHeredocIndentation:
- 'app/graphql/mutations/merge_requests/set_wip.rb' - 'app/graphql/mutations/merge_requests/set_wip.rb'
- 'ee/db/geo/migrate/20180322062741_migrate_ci_job_artifacts_to_separate_registry.rb' - 'ee/db/geo/migrate/20180322062741_migrate_ci_job_artifacts_to_separate_registry.rb'
- 'ee/lib/gitlab/geo/health_check.rb' - 'ee/lib/gitlab/geo/health_check.rb'
- 'lib/gitlab/background_migration/populate_untracked_uploads.rb'
- 'spec/features/merge_request/user_sees_diff_spec.rb' - 'spec/features/merge_request/user_sees_diff_spec.rb'
- 'spec/lib/gitlab/asciidoc_spec.rb' - 'spec/lib/gitlab/asciidoc_spec.rb'
- 'spec/lib/gitlab/checks/project_moved_spec.rb' - 'spec/lib/gitlab/checks/project_moved_spec.rb'
@ -154,23 +153,6 @@ Layout/SpaceInsideBlockBraces:
Layout/SpaceInsideParens: Layout/SpaceInsideParens:
Enabled: false Enabled: false
# Offense count: 19
Lint/DuplicateMethods:
Exclude:
- 'app/models/commit.rb'
- 'app/models/note.rb'
- 'lib/bitbucket/representation/repo.rb'
- 'lib/declarative_policy/base.rb'
- 'lib/gitlab/auth/ldap/person.rb'
- 'lib/gitlab/auth/o_auth/user.rb'
- 'lib/gitlab/ci/build/artifacts/metadata/entry.rb'
- 'lib/gitlab/cycle_analytics/base_event_fetcher.rb'
- 'lib/gitlab/diff/formatters/base_formatter.rb'
- 'lib/gitlab/git/blob.rb'
- 'lib/gitlab/git/repository.rb'
- 'lib/gitlab/git/tree.rb'
- 'lib/gitlab/git/wiki_page.rb'
# Offense count: 157 # Offense count: 157
# Configuration parameters: MaximumRangeSize. # Configuration parameters: MaximumRangeSize.
Lint/MissingCopEnableDirective: Lint/MissingCopEnableDirective:
@ -275,7 +257,6 @@ Performance/Count:
Exclude: Exclude:
- 'app/helpers/groups_helper.rb' - 'app/helpers/groups_helper.rb'
- 'app/services/merge_requests/add_context_service.rb' - 'app/services/merge_requests/add_context_service.rb'
- 'ee/lib/gitlab/geo/fdw.rb'
- 'ee/lib/gitlab/graphql/aggregations/epics/epic_node.rb' - 'ee/lib/gitlab/graphql/aggregations/epics/epic_node.rb'
- 'ee/spec/controllers/projects/feature_flags_controller_spec.rb' - 'ee/spec/controllers/projects/feature_flags_controller_spec.rb'
- 'ee/spec/requests/api/feature_flags_spec.rb' - 'ee/spec/requests/api/feature_flags_spec.rb'
@ -303,11 +284,6 @@ Performance/Detect:
RSpec/ContextWording: RSpec/ContextWording:
Enabled: false Enabled: false
# Offense count: 626
# Cop supports --auto-correct.
RSpec/EmptyLineAfterLetBlock:
Enabled: false
# Offense count: 1121 # Offense count: 1121
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
@ -472,6 +448,166 @@ Rails/RakeEnvironment:
Rails/SkipsModelValidations: Rails/SkipsModelValidations:
Enabled: false Enabled: false
# Offense count: 308
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: strict, flexible
Rails/TimeZone:
Enabled: true
Exclude:
- 'lib/gitlab/popen.rb'
- 'ee/lib/delay.rb'
- 'ee/lib/gitlab/elastic/helper.rb'
- 'ee/lib/gitlab/elastic/indexer.rb'
- 'ee/lib/gitlab/geo/base_request.rb'
- 'ee/lib/gitlab/geo/event_gap_tracking.rb'
- 'ee/lib/gitlab/geo/log_cursor/events/design_repository_updated_event.rb'
- 'ee/lib/gitlab/geo/log_cursor/events/repository_updated_event.rb'
- 'ee/lib/gitlab/geo/log_cursor/logger.rb'
- 'ee/lib/gitlab/geo/oauth/login_state.rb'
- 'ee/lib/gitlab/prometheus/queries/cluster_query.rb'
- 'ee/lib/gitlab/prometheus/queries/packet_flow_query.rb'
- 'ee/spec/lib/ee/gitlab/checks/push_rules/commit_check_spec.rb'
- 'ee/spec/lib/ee/gitlab/ci/pipeline/quota/job_activity_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/data_collector_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/group/stage_summary_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/group/stage_time_summary_spec.rb'
- 'ee/spec/lib/gitlab/auth/ldap/access_spec.rb'
- 'ee/spec/lib/gitlab/auth/smartcard/san_extension_spec.rb'
- 'ee/spec/lib/gitlab/auth/smartcard/session_spec.rb'
- 'ee/spec/lib/gitlab/background_migration/fix_orphan_promoted_issues_spec.rb'
- 'ee/spec/lib/gitlab/ci/pipeline/chain/limit/job_activity_spec.rb'
- 'ee/spec/lib/gitlab/elastic/client_spec.rb'
- 'ee/spec/lib/gitlab/geo/base_request_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/cache_invalidation_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/container_repository_updated_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/design_repository_updated_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/hashed_storage_attachments_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/hashed_storage_migrated_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/job_artifact_deleted_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/lfs_object_deleted_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/repositories_changed_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_created_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_deleted_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_renamed_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_updated_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/reset_checksum_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/upload_deleted_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/logger_spec.rb'
- 'ee/spec/lib/gitlab/git_access_spec.rb'
- 'ee/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb'
- 'ee/spec/lib/gitlab/prometheus/queries/cluster_query_spec.rb'
- 'ee/spec/lib/gitlab/prometheus/queries/packet_flow_query_spec.rb'
- 'lib/api/helpers.rb'
- 'lib/api/sidekiq_metrics.rb'
- 'lib/backup/manager.rb'
- 'lib/bitbucket_server/representation/base.rb'
- 'lib/gitlab/auth/current_user_mode.rb'
- 'lib/gitlab/auth/ldap/access.rb'
- 'lib/gitlab/chaos.rb'
- 'lib/gitlab/checks/timed_logger.rb'
- 'lib/gitlab/ci/ansi2json/line.rb'
- 'lib/gitlab/ci/pipeline/chain/sequence.rb'
- 'lib/gitlab/ci/pipeline/duration.rb'
- 'lib/gitlab/cycle_analytics/summary/deployment_frequency.rb'
- 'lib/gitlab/database.rb'
- 'lib/gitlab/external_authorization/access.rb'
- 'lib/gitlab/external_authorization/cache.rb'
- 'lib/gitlab/gitaly_client.rb'
- 'lib/gitlab/gitaly_client/ref_service.rb'
- 'lib/gitlab/github_import/representation.rb'
- 'lib/gitlab/grape_logging/loggers/queue_duration_logger.rb'
- 'lib/gitlab/health_checks/base_abstract_check.rb'
- 'lib/gitlab/import_export.rb'
- 'lib/gitlab/instrumentation/elasticsearch_transport.rb'
- 'lib/gitlab/instrumentation/redis_interceptor.rb'
- 'lib/gitlab/instrumentation_helper.rb'
- 'lib/gitlab/kubernetes/helm/certificate.rb'
- 'lib/gitlab/lfs_token.rb'
- 'lib/gitlab/loop_helpers.rb'
- 'lib/gitlab/phabricator_import/representation/task.rb'
- 'lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb'
- 'lib/gitlab/prometheus/queries/matched_metric_query.rb'
- 'lib/gitlab/prometheus_client.rb'
- 'lib/gitlab/sherlock/transaction.rb'
- 'lib/gitlab/task_helpers.rb'
- 'lib/gitlab/x509/tag.rb'
- 'lib/grafana/time_window.rb'
- 'lib/json_web_token/token.rb'
- 'lib/object_storage/direct_upload.rb'
- 'lib/quality/seeders/issues.rb'
- 'lib/rspec_flaky/flaky_example.rb'
- 'lib/rspec_flaky/report.rb'
- 'lib/tasks/gitlab/assets.rake'
- 'lib/tasks/gitlab/backup.rake'
- 'lib/tasks/gitlab/cleanup.rake'
- 'lib/tasks/gitlab/list_repos.rake'
- 'spec/lib/api/helpers_spec.rb'
- 'spec/lib/gitlab/analytics/cycle_analytics/base_query_builder_spec.rb'
- 'spec/lib/gitlab/app_json_logger_spec.rb'
- 'spec/lib/gitlab/app_text_logger_spec.rb'
- 'spec/lib/gitlab/auth/current_user_mode_spec.rb'
- 'spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb'
- 'spec/lib/gitlab/background_migration/wrongfully_confirmed_email_unconfirmer_spec.rb'
- 'spec/lib/gitlab/bitbucket_import/importer_spec.rb'
- 'spec/lib/gitlab/bitbucket_server_import/importer_spec.rb'
- 'spec/lib/gitlab/checks/timed_logger_spec.rb'
- 'spec/lib/gitlab/ci/cron_parser_spec.rb'
- 'spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb'
- 'spec/lib/gitlab/cycle_analytics/usage_data_spec.rb'
- 'spec/lib/gitlab/data_builder/note_spec.rb'
- 'spec/lib/gitlab/database/background_migration_job_spec.rb'
- 'spec/lib/gitlab/database_spec.rb'
- 'spec/lib/gitlab/discussions_diff/file_collection_spec.rb'
- 'spec/lib/gitlab/external_authorization/access_spec.rb'
- 'spec/lib/gitlab/external_authorization/cache_spec.rb'
- 'spec/lib/gitlab/external_authorization/logger_spec.rb'
- 'spec/lib/gitlab/fogbugz_import/importer_spec.rb'
- 'spec/lib/gitlab/git/branch_spec.rb'
- 'spec/lib/gitlab/git/commit_spec.rb'
- 'spec/lib/gitlab/git/repository_spec.rb'
- 'spec/lib/gitlab/git_access_spec.rb'
- 'spec/lib/gitlab/github_import/importer/diff_note_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/issue_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/issues_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/note_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/releases_importer_spec.rb'
- 'spec/lib/gitlab/github_import/representation/diff_note_spec.rb'
- 'spec/lib/gitlab/github_import/representation/issue_spec.rb'
- 'spec/lib/gitlab/github_import/representation/note_spec.rb'
- 'spec/lib/gitlab/github_import/representation/pull_request_spec.rb'
- 'spec/lib/gitlab/grape_logging/formatters/lograge_with_timestamp_spec.rb'
- 'spec/lib/gitlab/grape_logging/loggers/cloudflare_logger_spec.rb'
- 'spec/lib/gitlab/grape_logging/loggers/queue_duration_logger_spec.rb'
- 'spec/lib/gitlab/graphql_logger_spec.rb'
- 'spec/lib/gitlab/graphs/commits_spec.rb'
- 'spec/lib/gitlab/import_export/project/relation_factory_spec.rb'
- 'spec/lib/gitlab/instrumentation_helper_spec.rb'
- 'spec/lib/gitlab/json_logger_spec.rb'
- 'spec/lib/gitlab/lfs_token_spec.rb'
- 'spec/lib/gitlab/log_timestamp_formatter_spec.rb'
- 'spec/lib/gitlab/middleware/rails_queue_duration_spec.rb'
- 'spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb'
- 'spec/lib/gitlab/phabricator_import/issues/task_importer_spec.rb'
- 'spec/lib/gitlab/phabricator_import/representation/task_spec.rb'
- 'spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb'
- 'spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb'
- 'spec/lib/gitlab/prometheus/queries/validate_query_spec.rb'
- 'spec/lib/gitlab/sherlock/transaction_spec.rb'
- 'spec/lib/gitlab/sidekiq_logging/json_formatter_spec.rb'
- 'spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executing_spec.rb'
- 'spec/lib/gitlab/updated_notes_paginator_spec.rb'
- 'spec/lib/gitlab/utils/json_size_estimator_spec.rb'
- 'spec/lib/gitlab/x509/signature_spec.rb'
- 'spec/lib/grafana/time_window_spec.rb'
- 'spec/lib/json_web_token/hmac_token_spec.rb'
- 'spec/lib/rspec_flaky/flaky_example_spec.rb'
- 'spec/lib/rspec_flaky/listener_spec.rb'
- 'spec/lib/rspec_flaky/report_spec.rb'
# Offense count: 8 # Offense count: 8
# Cop supports --auto-correct. # Cop supports --auto-correct.
Security/YAMLLoad: Security/YAMLLoad:
@ -620,123 +756,6 @@ Style/Next:
Style/NumericLiteralPrefix: Style/NumericLiteralPrefix:
Enabled: false Enabled: false
# Offense count: 130
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods.
# SupportedStyles: predicate, comparison
# We use EnforcedStyle of comparison here due to it being better
# performing code as seen https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36221#note_375659681
Style/NumericPredicate:
EnforcedStyle: comparison
Exclude:
- 'spec/**/*'
- 'app/views/**/*'
- 'ee/app/views/**/*'
- 'app/controllers/concerns/issuable_collections.rb'
- 'app/controllers/concerns/paginated_collection.rb'
- 'app/helpers/graph_helper.rb'
- 'app/helpers/timeboxes_helper.rb'
- 'app/models/ci/pipeline.rb'
- 'app/models/ci/stage.rb'
- 'app/models/concerns/update_project_statistics.rb'
- 'app/models/merge_request_diff.rb'
- 'app/models/milestone.rb'
- 'app/models/network/graph.rb'
- 'app/models/postgresql/replication_slot.rb'
- 'app/models/project.rb'
- 'app/models/suggestion.rb'
- 'app/models/user.rb'
- 'app/serializers/merge_request_widget_entity.rb'
- 'app/services/boards/issues/move_service.rb'
- 'app/services/cohorts_service.rb'
- 'app/services/discussions/resolve_service.rb'
- 'app/services/issues/reorder_service.rb'
- 'app/services/notes/create_service.rb'
- 'app/services/packages/nuget/metadata_extraction_service.rb'
- 'app/services/packages/nuget/search_service.rb'
- 'app/services/projects/auto_devops/disable_service.rb'
- 'app/services/projects/update_pages_service.rb'
- 'app/services/search_service.rb'
- 'app/workers/admin_email_worker.rb'
- 'app/workers/gitlab/import/advance_stage.rb'
- 'config/initializers/validate_puma.rb'
- 'ee/app/controllers/security/projects_controller.rb'
- 'ee/app/graphql/mutations/instance_security_dashboard/remove_project.rb'
- 'ee/app/helpers/ee/timeboxes_helper.rb'
- 'ee/app/models/ci/minutes/quota.rb'
- 'ee/app/models/ee/ci/runner.rb'
- 'ee/app/models/geo_node_status.rb'
- 'ee/app/models/license.rb'
- 'ee/app/models/namespace_statistics.rb'
- 'ee/app/services/ee/issues/base_service.rb'
- 'ee/app/services/ee/merge_requests/approval_service.rb'
- 'ee/app/services/ee/quick_actions/target_service.rb'
- 'ee/app/services/elastic/indexing_control_service.rb'
- 'ee/app/services/geo/hashed_storage_migration_service.rb'
- 'ee/app/services/geo/prune_event_log_service.rb'
- 'ee/app/services/security/waf_anomaly_summary_service.rb'
- 'ee/app/services/update_build_minutes_service.rb'
- 'ee/app/workers/geo/container_repository_sync_dispatch_worker.rb'
- 'ee/app/workers/geo/file_download_dispatch_worker.rb'
- 'ee/app/workers/geo/registry_sync_worker.rb'
- 'ee/app/workers/geo/repository_shard_sync_worker.rb'
- 'ee/app/workers/geo/repository_verification/primary/shard_worker.rb'
- 'ee/lib/api/helpers/packages/conan/api_helpers.rb'
- 'ee/lib/ee/gitlab/auth/ldap/person.rb'
- 'ee/lib/ee/gitlab/background_migration/prune_orphaned_geo_events.rb'
- 'ee/lib/ee/gitlab/checks/push_rules/file_size_check.rb'
- 'ee/lib/ee/gitlab/geo_git_access.rb'
- 'ee/lib/gitlab/geo/fdw.rb'
- 'ee/lib/gitlab/geo/log_cursor/lease.rb'
- 'ee/lib/tasks/gitlab/elastic.rake'
- 'lib/api/entities/feature.rb'
- 'lib/api/helpers/pagination_strategies.rb'
- 'lib/backup/files.rb'
- 'lib/banzai/filter/gollum_tags_filter.rb'
- 'lib/bitbucket_server/paginator.rb'
- 'lib/declarative_policy/runner.rb'
- 'lib/gitlab/auth/ldap/adapter.rb'
- 'lib/gitlab/bare_repository_import/importer.rb'
- 'lib/gitlab/ci/config/external/context.rb'
- 'lib/gitlab/ci/reports/accessibility_reports_comparer.rb'
- 'lib/gitlab/cycle_analytics/summary/value.rb'
- 'lib/gitlab/cycle_analytics/summary_helper.rb'
- 'lib/gitlab/danger/teammate.rb'
- 'lib/gitlab/database.rb'
- 'lib/gitlab/database/connection_timer.rb'
- 'lib/gitlab/database/migration_helpers.rb'
- 'lib/gitlab/exclusive_lease.rb'
- 'lib/gitlab/exclusive_lease_helpers/sleeping_lock.rb'
- 'lib/gitlab/experimentation.rb'
- 'lib/gitlab/file_hook.rb'
- 'lib/gitlab/git/commit.rb'
- 'lib/gitlab/git/repository.rb'
- 'lib/gitlab/git/rugged_impl/blob.rb'
- 'lib/gitlab/gitaly_client.rb'
- 'lib/gitlab/github_import/user_finder.rb'
- 'lib/gitlab/hashed_storage/migrator.rb'
- 'lib/gitlab/import_export/command_line_util.rb'
- 'lib/gitlab/multi_collection_paginator.rb'
- 'lib/gitlab/polling_interval.rb'
- 'lib/gitlab/project_search_results.rb'
- 'lib/gitlab/seeder.rb'
- 'lib/gitlab/sidekiq_cluster.rb'
- 'lib/gitlab/sidekiq_daemon/memory_killer.rb'
- 'lib/gitlab/sidekiq_middleware/memory_killer.rb'
- 'lib/gitlab/sidekiq_status.rb'
- 'lib/gitlab/slash_commands/presenters/issue_show.rb'
- 'lib/gitlab/task_helpers.rb'
- 'lib/gitlab/untrusted_regexp.rb'
- 'lib/gitlab/utils.rb'
- 'lib/system_check/sidekiq_check.rb'
- 'lib/tasks/gitlab/gitaly.rake'
- 'lib/tasks/gitlab/snippets.rake'
- 'lib/tasks/gitlab/workhorse.rake'
- 'qa/qa/git/repository.rb'
- 'qa/qa/support/wait_for_requests.rb'
- 'ee/app/models/ee/project.rb'
- 'lib/gitlab/usage_data/topology.rb'
# Offense count: 117 # Offense count: 117
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/ParallelAssignment: Style/ParallelAssignment:
@ -855,35 +874,8 @@ Rails/SaveBang:
Exclude: Exclude:
- 'ee/spec/controllers/projects/merge_requests_controller_spec.rb' - 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
- 'ee/spec/controllers/subscriptions_controller_spec.rb' - 'ee/spec/controllers/subscriptions_controller_spec.rb'
- 'ee/spec/factories/ci/job_artifacts.rb'
- 'ee/spec/factories/epics.rb'
- 'ee/spec/factories/licenses.rb'
- 'ee/spec/factories/merge_requests.rb'
- 'ee/spec/features/admin/admin_users_spec.rb'
- 'ee/spec/features/admin/geo/admin_geo_nodes_spec.rb'
- 'ee/spec/features/admin/licenses/admin_views_license_spec.rb'
- 'ee/spec/features/boards/scoped_issue_board_spec.rb'
- 'ee/spec/features/ci_shared_runner_warnings_spec.rb'
- 'ee/spec/features/dashboards/operations_spec.rb'
- 'ee/spec/features/issues/gfm_autocomplete_ee_spec.rb'
- 'ee/spec/features/merge_request/user_approves_spec.rb'
- 'ee/spec/features/merge_requests/user_views_all_merge_requests_spec.rb'
- 'ee/spec/features/projects/members/invite_group_and_members_spec.rb'
- 'ee/spec/features/projects/merge_requests/user_approves_merge_request_spec.rb'
- 'ee/spec/features/projects/mirror_spec.rb'
- 'ee/spec/features/projects/new_project_spec.rb'
- 'ee/spec/features/projects/settings/user_manages_approval_settings_spec.rb'
- 'ee/spec/features/projects/settings/user_manages_members_spec.rb'
- 'ee/spec/features/search/elastic/global_search_spec.rb'
- 'ee/spec/features/security/project/internal_access_spec.rb'
- 'ee/spec/features/security/project/public_access_spec.rb'
- 'ee/spec/finders/epics_finder_spec.rb'
- 'ee/spec/finders/security/vulnerabilities_finder_spec.rb'
- 'ee/spec/frontend/fixtures/analytics.rb' - 'ee/spec/frontend/fixtures/analytics.rb'
- 'ee/spec/graphql/resolvers/vulnerabilities_resolver_spec.rb' - 'ee/spec/graphql/resolvers/vulnerabilities_resolver_spec.rb'
- 'ee/spec/helpers/application_helper_spec.rb'
- 'ee/spec/helpers/ee/dashboard_helper_spec.rb'
- 'ee/spec/helpers/ee/issues_helper_spec.rb'
- 'ee/spec/initializers/fog_google_https_private_urls_spec.rb' - 'ee/spec/initializers/fog_google_https_private_urls_spec.rb'
- 'ee/spec/lib/analytics/merge_request_metrics_calculator_spec.rb' - 'ee/spec/lib/analytics/merge_request_metrics_calculator_spec.rb'
- 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb' - 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb'
@ -962,11 +954,6 @@ Rails/SaveBang:
- 'ee/spec/models/visible_approvable_spec.rb' - 'ee/spec/models/visible_approvable_spec.rb'
- 'ee/spec/models/vulnerabilities/feedback_spec.rb' - 'ee/spec/models/vulnerabilities/feedback_spec.rb'
- 'ee/spec/models/vulnerabilities/issue_link_spec.rb' - 'ee/spec/models/vulnerabilities/issue_link_spec.rb'
- 'ee/spec/policies/group_policy_spec.rb'
- 'ee/spec/policies/note_policy_spec.rb'
- 'ee/spec/policies/project_policy_spec.rb'
- 'ee/spec/policies/protected_branch_policy_spec.rb'
- 'ee/spec/policies/vulnerabilities/feedback_policy_spec.rb'
- 'ee/spec/presenters/audit_event_presenter_spec.rb' - 'ee/spec/presenters/audit_event_presenter_spec.rb'
- 'ee/spec/presenters/epic_presenter_spec.rb' - 'ee/spec/presenters/epic_presenter_spec.rb'
- 'ee/spec/requests/api/boards_spec.rb' - 'ee/spec/requests/api/boards_spec.rb'
@ -1035,7 +1022,6 @@ Rails/SaveBang:
- 'ee/spec/services/todo_service_spec.rb' - 'ee/spec/services/todo_service_spec.rb'
- 'ee/spec/services/update_build_minutes_service_spec.rb' - 'ee/spec/services/update_build_minutes_service_spec.rb'
- 'ee/spec/services/vulnerability_feedback/create_service_spec.rb' - 'ee/spec/services/vulnerability_feedback/create_service_spec.rb'
- 'ee/spec/support/helpers/ee/geo_helpers.rb'
- 'ee/spec/support/protected_tags/access_control_shared_examples.rb' - 'ee/spec/support/protected_tags/access_control_shared_examples.rb'
- 'ee/spec/support/shared_examples/features/protected_branches_access_control_shared_examples.rb' - 'ee/spec/support/shared_examples/features/protected_branches_access_control_shared_examples.rb'
- 'ee/spec/support/shared_examples/finders/geo/framework_registry_finder_shared_examples.rb' - 'ee/spec/support/shared_examples/finders/geo/framework_registry_finder_shared_examples.rb'
@ -1051,7 +1037,6 @@ Rails/SaveBang:
- 'ee/spec/support/shared_examples/requests/api/project_approval_rules_api_shared_examples.rb' - 'ee/spec/support/shared_examples/requests/api/project_approval_rules_api_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/build_execute_shared_examples.rb' - 'ee/spec/support/shared_examples/services/build_execute_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/issue_epic_shared_examples.rb' - 'ee/spec/support/shared_examples/services/issue_epic_shared_examples.rb'
- 'ee/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb'
- 'ee/spec/workers/adjourned_project_deletion_worker_spec.rb' - 'ee/spec/workers/adjourned_project_deletion_worker_spec.rb'
- 'ee/spec/workers/clear_shared_runners_minutes_worker_spec.rb' - 'ee/spec/workers/clear_shared_runners_minutes_worker_spec.rb'
- 'ee/spec/workers/create_github_webhook_worker_spec.rb' - 'ee/spec/workers/create_github_webhook_worker_spec.rb'
@ -1100,19 +1085,6 @@ Rails/SaveBang:
- 'spec/controllers/sent_notifications_controller_spec.rb' - 'spec/controllers/sent_notifications_controller_spec.rb'
- 'spec/controllers/sessions_controller_spec.rb' - 'spec/controllers/sessions_controller_spec.rb'
- 'spec/controllers/users_controller_spec.rb' - 'spec/controllers/users_controller_spec.rb'
- 'spec/factories/alert_management/alerts.rb'
- 'spec/factories/boards.rb'
- 'spec/factories/ci/pipelines.rb'
- 'spec/factories/design_management/designs.rb'
- 'spec/factories/design_management/versions.rb'
- 'spec/factories/emails.rb'
- 'spec/factories/issues.rb'
- 'spec/factories/labels.rb'
- 'spec/factories/merge_requests.rb'
- 'spec/factories/plans.rb'
- 'spec/factories/projects.rb'
- 'spec/factories/services.rb'
- 'spec/factories/wiki_pages.rb'
- 'spec/factories_spec.rb' - 'spec/factories_spec.rb'
- 'spec/features/admin/admin_appearance_spec.rb' - 'spec/features/admin/admin_appearance_spec.rb'
- 'spec/features/admin/admin_labels_spec.rb' - 'spec/features/admin/admin_labels_spec.rb'
@ -1142,14 +1114,6 @@ Rails/SaveBang:
- 'spec/features/issues/user_filters_issues_spec.rb' - 'spec/features/issues/user_filters_issues_spec.rb'
- 'spec/features/issues/user_sees_live_update_spec.rb' - 'spec/features/issues/user_sees_live_update_spec.rb'
- 'spec/features/issues/user_sorts_issues_spec.rb' - 'spec/features/issues/user_sorts_issues_spec.rb'
- 'spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb'
- 'spec/features/merge_request/user_posts_diff_notes_spec.rb'
- 'spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb'
- 'spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb'
- 'spec/features/merge_request/user_sees_discussions_spec.rb'
- 'spec/features/merge_request/user_sees_merge_widget_spec.rb'
- 'spec/features/merge_request/user_sees_versions_spec.rb'
- 'spec/features/merge_requests/user_mass_updates_spec.rb'
- 'spec/features/profiles/emails_spec.rb' - 'spec/features/profiles/emails_spec.rb'
- 'spec/features/profiles/password_spec.rb' - 'spec/features/profiles/password_spec.rb'
- 'spec/features/profiles/personal_access_tokens_spec.rb' - 'spec/features/profiles/personal_access_tokens_spec.rb'
@ -1176,32 +1140,11 @@ Rails/SaveBang:
- 'spec/features/security/project/public_access_spec.rb' - 'spec/features/security/project/public_access_spec.rb'
- 'spec/features/users/login_spec.rb' - 'spec/features/users/login_spec.rb'
- 'spec/features/users/show_spec.rb' - 'spec/features/users/show_spec.rb'
- 'spec/finders/admin/projects_finder_spec.rb'
- 'spec/finders/autocomplete/move_to_project_finder_spec.rb'
- 'spec/finders/ci/pipelines_for_merge_request_finder_spec.rb'
- 'spec/finders/group_descendants_finder_spec.rb'
- 'spec/finders/group_projects_finder_spec.rb'
- 'spec/finders/issues_finder_spec.rb'
- 'spec/finders/joined_groups_finder_spec.rb'
- 'spec/finders/merge_requests_finder_spec.rb'
- 'spec/finders/personal_projects_finder_spec.rb'
- 'spec/finders/projects_finder_spec.rb'
- 'spec/finders/uploader_finder_spec.rb'
- 'spec/frontend/fixtures/issues.rb' - 'spec/frontend/fixtures/issues.rb'
- 'spec/frontend/fixtures/merge_requests.rb' - 'spec/frontend/fixtures/merge_requests.rb'
- 'spec/graphql/mutations/merge_requests/set_locked_spec.rb' - 'spec/graphql/mutations/merge_requests/set_locked_spec.rb'
- 'spec/graphql/mutations/merge_requests/set_wip_spec.rb' - 'spec/graphql/mutations/merge_requests/set_wip_spec.rb'
- 'spec/graphql/resolvers/boards_resolver_spec.rb' - 'spec/graphql/resolvers/boards_resolver_spec.rb'
- 'spec/helpers/appearances_helper_spec.rb'
- 'spec/helpers/auto_devops_helper_spec.rb'
- 'spec/helpers/issuables_helper_spec.rb'
- 'spec/helpers/issues_helper_spec.rb'
- 'spec/helpers/members_helper_spec.rb'
- 'spec/helpers/notes_helper_spec.rb'
- 'spec/helpers/profiles_helper_spec.rb'
- 'spec/helpers/projects/alert_management_helper_spec.rb'
- 'spec/helpers/projects_helper_spec.rb'
- 'spec/helpers/visibility_level_helper_spec.rb'
- 'spec/initializers/active_record_locking_spec.rb' - 'spec/initializers/active_record_locking_spec.rb'
- 'spec/initializers/fog_google_https_private_urls_spec.rb' - 'spec/initializers/fog_google_https_private_urls_spec.rb'
- 'spec/lib/after_commit_queue_spec.rb' - 'spec/lib/after_commit_queue_spec.rb'
@ -1412,13 +1355,6 @@ Rails/SaveBang:
- 'spec/models/user_status_spec.rb' - 'spec/models/user_status_spec.rb'
- 'spec/models/wiki_page/meta_spec.rb' - 'spec/models/wiki_page/meta_spec.rb'
- 'spec/models/wiki_page_spec.rb' - 'spec/models/wiki_page_spec.rb'
- 'spec/policies/ci/build_policy_spec.rb'
- 'spec/policies/ci/pipeline_policy_spec.rb'
- 'spec/policies/ci/pipeline_schedule_policy_spec.rb'
- 'spec/policies/group_policy_spec.rb'
- 'spec/policies/issue_policy_spec.rb'
- 'spec/policies/merge_request_policy_spec.rb'
- 'spec/policies/project_policy_spec.rb'
- 'spec/presenters/ci/build_runner_presenter_spec.rb' - 'spec/presenters/ci/build_runner_presenter_spec.rb'
- 'spec/presenters/ci/trigger_presenter_spec.rb' - 'spec/presenters/ci/trigger_presenter_spec.rb'
- 'spec/presenters/packages/conan/package_presenter_spec.rb' - 'spec/presenters/packages/conan/package_presenter_spec.rb'
@ -1528,15 +1464,8 @@ Rails/SaveBang:
- 'spec/services/users/repair_ldap_blocked_service_spec.rb' - 'spec/services/users/repair_ldap_blocked_service_spec.rb'
- 'spec/services/verify_pages_domain_service_spec.rb' - 'spec/services/verify_pages_domain_service_spec.rb'
- 'spec/sidekiq/cron/job_gem_dependency_spec.rb' - 'spec/sidekiq/cron/job_gem_dependency_spec.rb'
- 'spec/support/helpers/cycle_analytics_helpers.rb'
- 'spec/support/helpers/design_management_test_helpers.rb'
- 'spec/support/helpers/jira_service_helper.rb'
- 'spec/support/helpers/login_helpers.rb'
- 'spec/support/helpers/notification_helpers.rb'
- 'spec/support/helpers/stub_object_storage.rb'
- 'spec/support/migrations_helpers/cluster_helpers.rb' - 'spec/support/migrations_helpers/cluster_helpers.rb'
- 'spec/support/migrations_helpers/namespaces_helper.rb' - 'spec/support/migrations_helpers/namespaces_helper.rb'
- 'spec/support/migrations_helpers/track_untracked_uploads_helpers.rb'
- 'spec/support/shared_contexts/email_shared_context.rb' - 'spec/support/shared_contexts/email_shared_context.rb'
- 'spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb' - 'spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb'
- 'spec/support/shared_contexts/mailers/notify_shared_context.rb' - 'spec/support/shared_contexts/mailers/notify_shared_context.rb'
@ -1554,7 +1483,6 @@ Rails/SaveBang:
- 'spec/support/shared_examples/models/members_notifications_shared_example.rb' - 'spec/support/shared_examples/models/members_notifications_shared_example.rb'
- 'spec/support/shared_examples/models/mentionable_shared_examples.rb' - 'spec/support/shared_examples/models/mentionable_shared_examples.rb'
- 'spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb' - 'spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb'
- 'spec/support/shared_examples/models/relative_positioning_shared_examples.rb'
- 'spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb' - 'spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb'
- 'spec/support/shared_examples/models/update_project_statistics_shared_examples.rb' - 'spec/support/shared_examples/models/update_project_statistics_shared_examples.rb'
- 'spec/support/shared_examples/models/with_uploads_shared_examples.rb' - 'spec/support/shared_examples/models/with_uploads_shared_examples.rb'
@ -1573,24 +1501,3 @@ Rails/SaveBang:
- 'spec/tasks/gitlab/web_hook_rake_spec.rb' - 'spec/tasks/gitlab/web_hook_rake_spec.rb'
- 'spec/uploaders/file_uploader_spec.rb' - 'spec/uploaders/file_uploader_spec.rb'
- 'spec/uploaders/object_storage_spec.rb' - 'spec/uploaders/object_storage_spec.rb'
- 'spec/views/notify/changed_milestone_email.html.haml_spec.rb'
- 'spec/views/projects/imports/new.html.haml_spec.rb'
- 'spec/views/projects/merge_requests/show.html.haml_spec.rb'
- 'spec/views/shared/_label_row.html.haml_spec.rb'
- 'spec/workers/concerns/project_export_options_spec.rb'
- 'spec/workers/gitlab/import/stuck_project_import_jobs_worker_spec.rb'
- 'spec/workers/gitlab/jira_import/stuck_jira_import_jobs_worker_spec.rb'
- 'spec/workers/migrate_external_diffs_worker_spec.rb'
- 'spec/workers/namespaceless_project_destroy_worker_spec.rb'
- 'spec/workers/namespaces/root_statistics_worker_spec.rb'
- 'spec/workers/pages_domain_verification_worker_spec.rb'
- 'spec/workers/process_commit_worker_spec.rb'
- 'spec/workers/propagate_integration_worker_spec.rb'
- 'spec/workers/propagate_service_template_worker_spec.rb'
- 'spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb'
- 'spec/workers/repository_check/single_repository_worker_spec.rb'
- 'spec/workers/repository_cleanup_worker_spec.rb'
- 'spec/workers/repository_import_worker_spec.rb'
- 'spec/workers/repository_update_remote_mirror_worker_spec.rb'
- 'spec/workers/stuck_ci_jobs_worker_spec.rb'
- 'spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb'

View file

@ -7,6 +7,7 @@ scss_files:
exclude: exclude:
- 'app/assets/stylesheets/pages/emojis.scss' - 'app/assets/stylesheets/pages/emojis.scss'
- 'app/assets/stylesheets/startup/startup-general.scss'
linters: linters:
# Reports when you use improper spacing around ! (the "bang") in !default, # Reports when you use improper spacing around ! (the "bang") in !default,

File diff suppressed because it is too large Load diff

View file

@ -1 +1 @@
13.2.10 13.3.8

View file

@ -1 +1 @@
2.4.0 2.6.0

View file

@ -1 +1 @@
1.21.0 1.22.0

View file

@ -1 +1 @@
13.3.0 13.6.0

View file

@ -1 +1 @@
8.37.0 8.39.0

31
Gemfile
View file

@ -41,7 +41,7 @@ gem 'omniauth-oauth2-generic', '~> 0.2.2'
gem 'omniauth-saml', '~> 1.10' gem 'omniauth-saml', '~> 1.10'
gem 'omniauth-shibboleth', '~> 1.3.0' gem 'omniauth-shibboleth', '~> 1.3.0'
gem 'omniauth-twitter', '~> 1.4' gem 'omniauth-twitter', '~> 1.4'
gem 'omniauth_crowd', '~> 2.2.0' gem 'omniauth_crowd', '~> 2.4.0'
gem 'omniauth-authentiq', '~> 0.3.3' gem 'omniauth-authentiq', '~> 0.3.3'
gem 'omniauth_openid_connect', '~> 0.3.5' gem 'omniauth_openid_connect', '~> 0.3.5'
gem 'omniauth-salesforce', '~> 1.0.5' gem 'omniauth-salesforce', '~> 1.0.5'
@ -69,7 +69,7 @@ gem 'rubyzip', '~> 2.0.0', require: 'zip'
gem 'acme-client', '~> 2.0', '>= 2.0.6' gem 'acme-client', '~> 2.0', '>= 2.0.6'
# Browser detection # Browser detection
gem 'browser', '~> 2.5' gem 'browser', '~> 4.2'
# GPG # GPG
gem 'gpgme', '~> 2.0.19' gem 'gpgme', '~> 2.0.19'
@ -119,6 +119,7 @@ gem 'fog-local', '~> 0.6'
gem 'fog-openstack', '~> 1.0' gem 'fog-openstack', '~> 1.0'
gem 'fog-rackspace', '~> 0.1.1' gem 'fog-rackspace', '~> 0.1.1'
gem 'fog-aliyun', '~> 0.3' gem 'fog-aliyun', '~> 0.3'
gem 'gitlab-fog-azure-rm', '~> 0.7', require: false
# for Google storage # for Google storage
gem 'google-api-client', '~> 0.33' gem 'google-api-client', '~> 0.33'
@ -133,8 +134,10 @@ gem 'seed-fu', '~> 2.3.7'
gem 'elasticsearch-model', '~> 6.1' gem 'elasticsearch-model', '~> 6.1'
gem 'elasticsearch-rails', '~> 6.1', require: 'elasticsearch/rails/instrumentation' gem 'elasticsearch-rails', '~> 6.1', require: 'elasticsearch/rails/instrumentation'
gem 'elasticsearch-api', '~> 6.8' gem 'elasticsearch-api', '~> 6.8'
gem 'aws-sdk' gem 'aws-sdk-core', '~> 3'
gem 'faraday_middleware-aws-signers-v4' gem 'aws-sdk-cloudformation', '~> 1'
gem 'aws-sdk-s3', '~> 1'
gem 'faraday_middleware-aws-sigv4', '~>0.3.0'
# Markdown and HTML processing # Markdown and HTML processing
gem 'html-pipeline', '~> 2.12' gem 'html-pipeline', '~> 2.12'
@ -188,7 +191,7 @@ gem 'acts-as-taggable-on', '~> 6.0'
# Background jobs # Background jobs
gem 'sidekiq', '~> 5.2.7' gem 'sidekiq', '~> 5.2.7'
gem 'sidekiq-cron', '~> 1.0' gem 'sidekiq-cron', '~> 1.0'
gem 'redis-namespace', '~> 1.6.0' gem 'redis-namespace', '~> 1.7.0'
gem 'gitlab-sidekiq-fetcher', '0.5.2', require: 'sidekiq-reliable-fetch' gem 'gitlab-sidekiq-fetcher', '0.5.2', require: 'sidekiq-reliable-fetch'
# Cron Parser # Cron Parser
@ -214,7 +217,7 @@ gem 're2', '~> 1.2.0'
gem 'version_sorter', '~> 2.2.4' gem 'version_sorter', '~> 2.2.4'
# Export Ruby Regex to Javascript # Export Ruby Regex to Javascript
gem 'js_regex', '~> 3.1' gem 'js_regex', '~> 3.4'
# User agent parsing # User agent parsing
gem 'device_detector' gem 'device_detector'
@ -328,7 +331,7 @@ group :metrics do
gem 'method_source', '~> 0.8', require: false gem 'method_source', '~> 0.8', require: false
# Prometheus # Prometheus
gem 'prometheus-client-mmap', '~> 0.10.0' gem 'prometheus-client-mmap', '~> 0.11.0'
gem 'raindrops', '~> 0.18' gem 'raindrops', '~> 0.18'
end end
@ -404,7 +407,7 @@ group :test do
gem 'rspec_profiling', '~> 0.0.5' gem 'rspec_profiling', '~> 0.0.5'
gem 'rspec-parameterized', require: false gem 'rspec-parameterized', require: false
gem 'capybara', '~> 3.22.0' gem 'capybara', '~> 3.33.0'
gem 'capybara-screenshot', '~> 1.0.22' gem 'capybara-screenshot', '~> 1.0.22'
gem 'selenium-webdriver', '~> 3.142' gem 'selenium-webdriver', '~> 3.142'
@ -413,7 +416,7 @@ group :test do
gem 'webmock', '~> 3.5.1' gem 'webmock', '~> 3.5.1'
gem 'rails-controller-testing' gem 'rails-controller-testing'
gem 'concurrent-ruby', '~> 1.1' gem 'concurrent-ruby', '~> 1.1'
gem 'test-prof', '~> 0.10.0' gem 'test-prof', '~> 0.12.0'
gem 'rspec_junit_formatter' gem 'rspec_junit_formatter'
gem 'guard-rspec' gem 'guard-rspec'
@ -440,7 +443,7 @@ gem 'activerecord-explain-analyze', '~> 0.1', require: false
gem 'oauth2', '~> 1.4' gem 'oauth2', '~> 1.4'
# Health check # Health check
gem 'health_check', '~> 2.6.0' gem 'health_check', '~> 3.0'
# System information # System information
gem 'vmstat', '~> 2.3.0' gem 'vmstat', '~> 2.3.0'
@ -460,11 +463,11 @@ group :ed25519 do
end end
# Gitaly GRPC protocol definitions # Gitaly GRPC protocol definitions
gem 'gitaly', '~> 13.2.0.pre.rc2' gem 'gitaly', '~> 13.3.0-rc1'
gem 'grpc', '~> 1.24.0' gem 'grpc', '~> 1.30.2'
gem 'google-protobuf', '~> 3.8.0' gem 'google-protobuf', '~> 3.12'
gem 'toml-rb', '~> 1.0.0' gem 'toml-rb', '~> 1.0.0'
@ -505,5 +508,7 @@ gem 'valid_email', '~> 0.1'
# JSON # JSON
gem 'json', '~> 2.3.0' gem 'json', '~> 2.3.0'
gem 'json-schema', '~> 2.8.0' gem 'json-schema', '~> 2.8.0'
gem 'json_schemer', '~> 0.2.12'
gem 'oj', '~> 3.10.6' gem 'oj', '~> 3.10.6'
gem 'multi_json', '~> 1.14.1' gem 'multi_json', '~> 1.14.1'
gem 'yajl-ruby', '~> 1.4.1', require: 'yajl'

View file

@ -93,16 +93,34 @@ GEM
encryptor (~> 3.0.0) encryptor (~> 3.0.0)
attr_required (1.0.1) attr_required (1.0.1)
awesome_print (1.8.0) awesome_print (1.8.0)
aws-eventstream (1.0.3) aws-eventstream (1.1.0)
aws-sdk (2.11.374) aws-partitions (1.345.0)
aws-sdk-resources (= 2.11.374) aws-sdk-cloudformation (1.41.0)
aws-sdk-core (2.11.374) aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.0) aws-sigv4 (~> 1.1)
aws-sdk-core (3.104.3)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0) jmespath (~> 1.0)
aws-sdk-resources (2.11.374) aws-sdk-kms (1.36.0)
aws-sdk-core (= 2.11.374) aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (1.1.0) aws-sigv4 (~> 1.1)
aws-eventstream (~> 1.0, >= 1.0.2) aws-sdk-s3 (1.75.0)
aws-sdk-core (~> 3, >= 3.104.1)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.2.1)
aws-eventstream (~> 1, >= 1.0.2)
azure-core (0.1.15)
faraday (~> 0.9)
faraday_middleware (~> 0.10)
nokogiri (~> 1.6)
azure-storage (0.15.0.preview)
azure-core (~> 0.1)
faraday (~> 0.9)
faraday_middleware (~> 0.10)
nokogiri (~> 1.6, >= 1.6.8)
babosa (1.0.2) babosa (1.0.2)
base32 (0.3.2) base32 (0.3.2)
batch-loader (1.4.0) batch-loader (1.4.0)
@ -125,7 +143,7 @@ GEM
actionpack (>= 5.0) actionpack (>= 5.0)
activemodel (>= 5.0) activemodel (>= 5.0)
brakeman (4.2.1) brakeman (4.2.1)
browser (2.5.3) browser (4.2.0)
builder (3.2.4) builder (3.2.4)
bullet (6.0.2) bullet (6.0.2)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
@ -134,7 +152,7 @@ GEM
bundler (>= 1.2.0, < 3) bundler (>= 1.2.0, < 3)
thor (~> 0.18) thor (~> 0.18)
byebug (9.1.0) byebug (9.1.0)
capybara (3.22.0) capybara (3.33.0)
addressable addressable
mini_mime (>= 0.1.3) mini_mime (>= 0.1.3)
nokogiri (~> 1.8) nokogiri (~> 1.8)
@ -149,7 +167,7 @@ GEM
activemodel (>= 4.0.0) activemodel (>= 4.0.0)
activesupport (>= 4.0.0) activesupport (>= 4.0.0)
mime-types (>= 1.16) mime-types (>= 1.16)
character_set (1.1.2) character_set (1.4.0)
charlock_holmes (0.7.6) charlock_holmes (0.7.6)
childprocess (3.0.0) childprocess (3.0.0)
chunky_png (1.3.5) chunky_png (1.3.5)
@ -263,6 +281,8 @@ GEM
dry-equalizer (~> 0.3) dry-equalizer (~> 0.3)
dry-inflector (~> 0.1, >= 0.1.2) dry-inflector (~> 0.1, >= 0.1.2)
dry-logic (~> 1.0, >= 1.0.2) dry-logic (~> 1.0, >= 1.0.2)
ecma-re-validator (0.2.1)
regexp_parser (~> 1.2)
ed25519 (1.2.4) ed25519 (1.2.4)
elasticsearch (6.8.0) elasticsearch (6.8.0)
elasticsearch-api (= 6.8.0) elasticsearch-api (= 6.8.0)
@ -302,13 +322,16 @@ GEM
railties (>= 4.2.0) railties (>= 4.2.0)
faraday (0.17.3) faraday (0.17.3)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6)
faraday (>= 0.7.4)
http-cookie (~> 1.0.0)
faraday-http-cache (2.0.0) faraday-http-cache (2.0.0)
faraday (~> 0.8) faraday (~> 0.8)
faraday_middleware (0.14.0) faraday_middleware (0.14.0)
faraday (>= 0.7.4, < 1.0) faraday (>= 0.7.4, < 1.0)
faraday_middleware-aws-signers-v4 (0.1.7) faraday_middleware-aws-sigv4 (0.3.0)
aws-sdk-resources (~> 2) aws-sigv4 (~> 1.0)
faraday (~> 0.9) faraday (>= 0.15)
faraday_middleware-multi_json (0.0.6) faraday_middleware-multi_json (0.0.6)
faraday_middleware faraday_middleware
multi_json multi_json
@ -391,11 +414,17 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
git (1.5.0) git (1.5.0)
gitaly (13.2.0.pre.rc2) gitaly (13.3.0.pre.rc2)
grpc (~> 1.0) grpc (~> 1.0)
github-markup (1.7.0) github-markup (1.7.0)
gitlab-chronic (0.10.5) gitlab-chronic (0.10.5)
numerizer (~> 0.2) numerizer (~> 0.2)
gitlab-fog-azure-rm (0.7.0)
azure-storage (~> 0.15.0.preview)
fog-core (= 2.1.0)
fog-json (~> 1.2.0)
mime-types
ms_rest_azure (~> 0.12.0)
gitlab-labkit (0.12.1) gitlab-labkit (0.12.1)
actionpack (>= 5.0.0, < 6.1.0) actionpack (>= 5.0.0, < 6.1.0)
activesupport (>= 5.0.0, < 6.1.0) activesupport (>= 5.0.0, < 6.1.0)
@ -441,9 +470,9 @@ GEM
representable (~> 3.0) representable (~> 3.0)
retriable (>= 2.0, < 4.0) retriable (>= 2.0, < 4.0)
signet (~> 0.12) signet (~> 0.12)
google-protobuf (3.8.0) google-protobuf (3.12.4)
googleapis-common-protos-types (1.0.4) googleapis-common-protos-types (1.0.5)
google-protobuf (~> 3.0) google-protobuf (~> 3.11)
googleauth (0.12.0) googleauth (0.12.0)
faraday (>= 0.17.3, < 2.0) faraday (>= 0.17.3, < 2.0)
jwt (>= 1.4, < 3.0) jwt (>= 1.4, < 3.0)
@ -482,8 +511,8 @@ GEM
graphql (~> 1.6) graphql (~> 1.6)
html-pipeline (~> 2.8) html-pipeline (~> 2.8)
sass (~> 3.4) sass (~> 3.4)
grpc (1.24.0) grpc (1.30.2)
google-protobuf (~> 3.8) google-protobuf (~> 3.12)
googleapis-common-protos-types (~> 1.0) googleapis-common-protos-types (~> 1.0)
gssapi (1.2.0) gssapi (1.2.0)
ffi (>= 1.0.1) ffi (>= 1.0.1)
@ -513,13 +542,14 @@ GEM
temple (>= 0.8.2) temple (>= 0.8.2)
thor thor
tilt tilt
hana (1.3.6)
hangouts-chat (0.0.5) hangouts-chat (0.0.5)
hashdiff (0.3.8) hashdiff (0.3.8)
hashie (3.6.0) hashie (3.6.0)
hashie-forbidden_attributes (0.1.1) hashie-forbidden_attributes (0.1.1)
hashie (>= 3.0) hashie (>= 3.0)
health_check (2.6.0) health_check (3.0.0)
rails (>= 4.0) railties (>= 5.0)
heapy (0.1.4) heapy (0.1.4)
hipchat (1.5.2) hipchat (1.5.2)
httparty httparty
@ -562,9 +592,9 @@ GEM
multipart-post multipart-post
oauth (~> 0.5, >= 0.5.0) oauth (~> 0.5, >= 0.5.0)
jmespath (1.4.0) jmespath (1.4.0)
js_regex (3.1.1) js_regex (3.4.0)
character_set (~> 1.1) character_set (~> 1.4)
regexp_parser (~> 1.1) regexp_parser (~> 1.5)
regexp_property_values (~> 0.3) regexp_property_values (~> 0.3)
json (2.3.0) json (2.3.0)
json-jwt (1.11.0) json-jwt (1.11.0)
@ -573,6 +603,11 @@ GEM
bindata bindata
json-schema (2.8.0) json-schema (2.8.0)
addressable (>= 2.4) addressable (>= 2.4)
json_schemer (0.2.12)
ecma-re-validator (~> 0.2)
hana (~> 1.3)
regexp_parser (~> 1.5)
uri_template (~> 0.7)
jwt (2.1.0) jwt (2.1.0)
kaminari (1.2.1) kaminari (1.2.1)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
@ -642,15 +677,24 @@ GEM
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
memory_profiler (0.9.14) memory_profiler (0.9.14)
method_source (0.9.2) method_source (0.9.2)
mime-types (3.2.2) mime-types (3.3.1)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2019.0331) mime-types-data (3.2020.0512)
mimemagic (0.3.5) mimemagic (0.3.5)
mini_histogram (0.1.3) mini_histogram (0.1.3)
mini_magick (4.9.5) mini_magick (4.9.5)
mini_mime (1.0.2) mini_mime (1.0.2)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
minitest (5.11.3) minitest (5.11.3)
ms_rest (0.7.6)
concurrent-ruby (~> 1.0)
faraday (>= 0.9, < 2.0.0)
timeliness (~> 0.3.10)
ms_rest_azure (0.12.0)
concurrent-ruby (~> 1.0)
faraday (>= 0.9, < 2.0.0)
faraday-cookie_jar (~> 0.0.6)
ms_rest (~> 0.7.6)
msgpack (1.3.1) msgpack (1.3.1)
multi_json (1.14.1) multi_json (1.14.1)
multi_xml (0.6.0) multi_xml (0.6.0)
@ -740,7 +784,7 @@ GEM
omniauth-twitter (1.4.0) omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1) omniauth-oauth (~> 1.1)
rack rack
omniauth_crowd (2.2.3) omniauth_crowd (2.4.0)
activesupport activesupport
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
omniauth (~> 1.0) omniauth (~> 1.0)
@ -787,7 +831,7 @@ GEM
parser parser
unparser unparser
procto (0.0.3) procto (0.0.3)
prometheus-client-mmap (0.10.0) prometheus-client-mmap (0.11.0)
pry (0.11.3) pry (0.11.3)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.9.0) method_source (~> 0.9.0)
@ -877,7 +921,7 @@ GEM
redis-activesupport (5.2.0) redis-activesupport (5.2.0)
activesupport (>= 3, < 7) activesupport (>= 3, < 7)
redis-store (>= 1.3, < 2) redis-store (>= 1.3, < 2)
redis-namespace (1.6.0) redis-namespace (1.7.0)
redis (>= 3.0.4) redis (>= 3.0.4)
redis-rack (2.1.2) redis-rack (2.1.2)
rack (>= 2.0.8, < 3) rack (>= 2.0.8, < 3)
@ -889,7 +933,7 @@ GEM
redis-store (1.8.1) redis-store (1.8.1)
redis (>= 4, < 5) redis (>= 4, < 5)
regexp_parser (1.5.1) regexp_parser (1.5.1)
regexp_property_values (0.3.4) regexp_property_values (0.3.5)
representable (3.0.4) representable (3.0.4)
declarative (< 0.1.0) declarative (< 0.1.0)
declarative-option (< 0.2.0) declarative-option (< 0.2.0)
@ -1076,7 +1120,7 @@ GEM
temple (0.8.2) temple (0.8.2)
terminal-table (1.8.0) terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1) unicode-display_width (~> 1.1, >= 1.1.1)
test-prof (0.10.0) test-prof (0.12.0)
text (1.3.1) text (1.3.1)
thin (1.7.2) thin (1.7.2)
daemons (~> 1.0, >= 1.0.9) daemons (~> 1.0, >= 1.0.9)
@ -1087,6 +1131,7 @@ GEM
thrift (0.11.0.0) thrift (0.11.0.0)
tilt (2.0.10) tilt (2.0.10)
timecop (0.9.1) timecop (0.9.1)
timeliness (0.3.10)
timfel-krb5-auth (0.8.3) timfel-krb5-auth (0.8.3)
toml (0.2.0) toml (0.2.0)
parslet (~> 1.8.0) parslet (~> 1.8.0)
@ -1126,6 +1171,7 @@ GEM
equalizer (~> 0.0.9) equalizer (~> 0.0.9)
parser (>= 2.6.5) parser (>= 2.6.5)
procto (~> 0.0.2) procto (~> 0.0.2)
uri_template (0.7.0)
valid_email (0.1.3) valid_email (0.1.3)
activemodel activemodel
mail (>= 2.6.1) mail (>= 2.6.1)
@ -1162,6 +1208,7 @@ GEM
xml-simple (1.1.5) xml-simple (1.1.5)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
yajl-ruby (1.4.1)
zeitwerk (2.3.0) zeitwerk (2.3.0)
PLATFORMS PLATFORMS
@ -1183,7 +1230,9 @@ DEPENDENCIES
atlassian-jwt (~> 0.2.0) atlassian-jwt (~> 0.2.0)
attr_encrypted (~> 3.1.0) attr_encrypted (~> 3.1.0)
awesome_print awesome_print
aws-sdk aws-sdk-cloudformation (~> 1)
aws-sdk-core (~> 3)
aws-sdk-s3 (~> 1)
babosa (~> 1.0.2) babosa (~> 1.0.2)
base32 (~> 0.3.0) base32 (~> 0.3.0)
batch-loader (~> 1.4.0) batch-loader (~> 1.4.0)
@ -1195,10 +1244,10 @@ DEPENDENCIES
bootsnap (~> 1.4.6) bootsnap (~> 1.4.6)
bootstrap_form (~> 4.2.0) bootstrap_form (~> 4.2.0)
brakeman (~> 4.2) brakeman (~> 4.2)
browser (~> 2.5) browser (~> 4.2)
bullet (~> 6.0.2) bullet (~> 6.0.2)
bundler-audit (~> 0.6.1) bundler-audit (~> 0.6.1)
capybara (~> 3.22.0) capybara (~> 3.33.0)
capybara-screenshot (~> 1.0.22) capybara-screenshot (~> 1.0.22)
carrierwave (~> 1.3) carrierwave (~> 1.3)
charlock_holmes (~> 0.7.5) charlock_holmes (~> 0.7.5)
@ -1230,7 +1279,7 @@ DEPENDENCIES
escape_utils (~> 1.1) escape_utils (~> 1.1)
factory_bot_rails (~> 5.1.0) factory_bot_rails (~> 5.1.0)
faraday (~> 0.12) faraday (~> 0.12)
faraday_middleware-aws-signers-v4 faraday_middleware-aws-sigv4 (~> 0.3.0)
fast_blank fast_blank
ffaker (~> 2.10) ffaker (~> 2.10)
flipper (~> 0.17.1) flipper (~> 0.17.1)
@ -1251,9 +1300,10 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3) gettext_i18n_rails_js (~> 1.3)
gitaly (~> 13.2.0.pre.rc2) gitaly (~> 13.3.0.pre.rc1)
github-markup (~> 1.7.0) github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5) gitlab-chronic (~> 0.10.5)
gitlab-fog-azure-rm (~> 0.7)
gitlab-labkit (= 0.12.1) gitlab-labkit (= 0.12.1)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
gitlab-mail_room (~> 0.0.6) gitlab-mail_room (~> 0.0.6)
@ -1267,7 +1317,7 @@ DEPENDENCIES
gitlab_omniauth-ldap (~> 2.1.1) gitlab_omniauth-ldap (~> 2.1.1)
gon (~> 6.2) gon (~> 6.2)
google-api-client (~> 0.33) google-api-client (~> 0.33)
google-protobuf (~> 3.8.0) google-protobuf (~> 3.12)
gpgme (~> 2.0.19) gpgme (~> 2.0.19)
grape (= 1.4.0) grape (= 1.4.0)
grape-entity (~> 0.7.1) grape-entity (~> 0.7.1)
@ -1276,14 +1326,14 @@ DEPENDENCIES
graphiql-rails (~> 1.4.10) graphiql-rails (~> 1.4.10)
graphql (~> 1.10.5) graphql (~> 1.10.5)
graphql-docs (~> 1.6.0) graphql-docs (~> 1.6.0)
grpc (~> 1.24.0) grpc (~> 1.30.2)
gssapi gssapi
guard-rspec guard-rspec
haml_lint (~> 0.34.0) haml_lint (~> 0.34.0)
hamlit (~> 2.11.0) hamlit (~> 2.11.0)
hangouts-chat (~> 0.0.5) hangouts-chat (~> 0.0.5)
hashie-forbidden_attributes hashie-forbidden_attributes
health_check (~> 2.6.0) health_check (~> 3.0)
hipchat (~> 1.5.0) hipchat (~> 1.5.0)
html-pipeline (~> 2.12) html-pipeline (~> 2.12)
html2text html2text
@ -1291,9 +1341,10 @@ DEPENDENCIES
icalendar icalendar
invisible_captcha (~> 0.12.1) invisible_captcha (~> 0.12.1)
jira-ruby (~> 2.0.0) jira-ruby (~> 2.0.0)
js_regex (~> 3.1) js_regex (~> 3.4)
json (~> 2.3.0) json (~> 2.3.0)
json-schema (~> 2.8.0) json-schema (~> 2.8.0)
json_schemer (~> 0.2.12)
jwt (~> 2.1.0) jwt (~> 2.1.0)
kaminari (~> 1.0) kaminari (~> 1.0)
knapsack (~> 1.17) knapsack (~> 1.17)
@ -1337,7 +1388,7 @@ DEPENDENCIES
omniauth-saml (~> 1.10) omniauth-saml (~> 1.10)
omniauth-shibboleth (~> 1.3.0) omniauth-shibboleth (~> 1.3.0)
omniauth-twitter (~> 1.4) omniauth-twitter (~> 1.4)
omniauth_crowd (~> 2.2.0) omniauth_crowd (~> 2.4.0)
omniauth_openid_connect (~> 0.3.5) omniauth_openid_connect (~> 0.3.5)
org-ruby (~> 0.9.12) org-ruby (~> 0.9.12)
parallel (~> 1.19) parallel (~> 1.19)
@ -1345,7 +1396,7 @@ DEPENDENCIES
pg (~> 1.1) pg (~> 1.1)
png_quantizator (~> 0.2.1) png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3) premailer-rails (~> 1.10.3)
prometheus-client-mmap (~> 0.10.0) prometheus-client-mmap (~> 0.11.0)
pry-byebug (~> 3.5.1) pry-byebug (~> 3.5.1)
pry-rails (~> 0.3.9) pry-rails (~> 0.3.9)
rack (~> 2.0.9) rack (~> 2.0.9)
@ -1365,7 +1416,7 @@ DEPENDENCIES
re2 (~> 1.2.0) re2 (~> 1.2.0)
recaptcha (~> 4.11) recaptcha (~> 4.11)
redis (~> 4.0) redis (~> 4.0)
redis-namespace (~> 1.6.0) redis-namespace (~> 1.7.0)
redis-rails (~> 5.0.2) redis-rails (~> 5.0.2)
request_store (~> 1.5) request_store (~> 1.5)
responders (~> 3.0) responders (~> 3.0)
@ -1408,7 +1459,7 @@ DEPENDENCIES
stackprof (~> 0.2.15) stackprof (~> 0.2.15)
state_machines-activerecord (~> 0.6.0) state_machines-activerecord (~> 0.6.0)
sys-filesystem (~> 1.1.6) sys-filesystem (~> 1.1.6)
test-prof (~> 0.10.0) test-prof (~> 0.12.0)
thin (~> 1.7.0) thin (~> 1.7.0)
timecop (~> 0.9.1) timecop (~> 0.9.1)
toml-rb (~> 1.0.0) toml-rb (~> 1.0.0)
@ -1426,6 +1477,7 @@ DEPENDENCIES
webmock (~> 3.5.1) webmock (~> 3.5.1)
webpack-rails (~> 0.9.10) webpack-rails (~> 0.9.10)
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
yajl-ruby (~> 1.4.1)
BUNDLED WITH BUNDLED WITH
1.17.3 1.17.3

View file

@ -1 +1 @@
13.2.10 13.3.8

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

View file

@ -0,0 +1,49 @@
<script>
import { GlButton } from '@gitlab/ui';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
export default {
components: {
GlButton,
},
props: {
commitsEmpty: {
type: Boolean,
required: false,
default: false,
},
contextCommitsEmpty: {
type: Boolean,
required: true,
},
},
computed: {
buttonText() {
return this.contextCommitsEmpty || this.commitsEmpty
? s__('AddContextCommits|Add previously merged commits')
: s__('AddContextCommits|Add/remove');
},
},
methods: {
openModal() {
eventHub.$emit('openModal');
},
},
};
</script>
<template>
<gl-button
:class="[
{
'ml-3': !contextCommitsEmpty,
'mt-3': !commitsEmpty && contextCommitsEmpty,
},
]"
:variant="commitsEmpty ? 'info' : 'default'"
@click="openModal"
>
{{ buttonText }}
</gl-button>
</template>

View file

@ -0,0 +1,279 @@
<script>
import { mapState, mapActions } from 'vuex';
import { GlModal, GlTabs, GlTab, GlSearchBoxByType, GlSprintf } from '@gitlab/ui';
import ReviewTabContainer from '~/add_context_commits_modal/components/review_tab_container.vue';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import {
findCommitIndex,
setCommitStatus,
removeIfReadyToBeRemoved,
removeIfPresent,
} from '../utils';
export default {
components: {
GlModal,
GlTabs,
GlTab,
ReviewTabContainer,
GlSearchBoxByType,
GlSprintf,
},
props: {
contextCommitsPath: {
type: String,
required: true,
},
targetBranch: {
type: String,
required: true,
},
mergeRequestIid: {
type: Number,
required: true,
},
projectId: {
type: Number,
required: true,
},
},
computed: {
...mapState([
'tabIndex',
'isLoadingCommits',
'commits',
'commitsLoadingError',
'isLoadingContextCommits',
'contextCommits',
'contextCommitsLoadingError',
'selectedCommits',
'searchText',
'toRemoveCommits',
]),
currentTabIndex: {
get() {
return this.tabIndex;
},
set(newTabIndex) {
this.setTabIndex(newTabIndex);
},
},
selectedCommitsCount() {
return this.selectedCommits.filter(selectedCommit => selectedCommit.isSelected).length;
},
shouldPurge() {
return this.selectedCommitsCount !== this.selectedCommits.length;
},
uniqueCommits() {
return this.selectedCommits.filter(
selectedCommit =>
selectedCommit.isSelected &&
findCommitIndex(this.contextCommits, selectedCommit.short_id) === -1,
);
},
disableSaveButton() {
// We should have a minimum of one commit selected and that should not be in the context commits list or we should have a context commit to delete
return (
(this.selectedCommitsCount.length === 0 || this.uniqueCommits.length === 0) &&
this.toRemoveCommits.length === 0
);
},
},
watch: {
tabIndex(newTabIndex) {
this.handleTabChange(newTabIndex);
},
},
mounted() {
eventHub.$on('openModal', this.openModal);
this.setBaseConfig({
contextCommitsPath: this.contextCommitsPath,
mergeRequestIid: this.mergeRequestIid,
projectId: this.projectId,
});
},
beforeDestroy() {
eventHub.$off('openModal', this.openModal);
clearTimeout(this.timeout);
this.timeout = null;
},
methods: {
...mapActions([
'setBaseConfig',
'setTabIndex',
'searchCommits',
'setCommits',
'createContextCommits',
'fetchContextCommits',
'removeContextCommits',
'setSelectedCommits',
'setSearchText',
'setToRemoveCommits',
'resetModalState',
]),
focusSearch() {
this.$refs.searchInput.focusInput();
},
openModal() {
this.searchCommits();
this.fetchContextCommits();
this.$root.$emit('bv::show::modal', 'add-review-item');
},
handleTabChange(tabIndex) {
if (tabIndex === 0) {
this.focusSearch();
if (this.shouldPurge) {
this.setSelectedCommits(
[...this.commits, ...this.selectedCommits].filter(commit => commit.isSelected),
);
}
}
},
handleSearchCommits(value) {
// We only call the service, if we have 3 characters or we don't have any characters
if (value.length >= 3) {
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.searchCommits(value);
}, 500);
} else if (value.length === 0) {
this.searchCommits();
}
this.setSearchText(value);
},
handleCommitRowSelect(event) {
const index = event[0];
const selected = event[1];
const tempCommit = this.tabIndex === 0 ? this.commits[index] : this.selectedCommits[index];
const commitIndex = findCommitIndex(this.commits, tempCommit.short_id);
const tempCommits = setCommitStatus(this.commits, commitIndex, selected);
const selectedCommitIndex = findCommitIndex(this.selectedCommits, tempCommit.short_id);
let tempSelectedCommits = setCommitStatus(
this.selectedCommits,
selectedCommitIndex,
selected,
);
if (selected) {
// If user deselects a commit which is already present in previously merged commits, then user adds it again.
// Then the state is neutral, so we remove it from the list
this.setToRemoveCommits(
removeIfReadyToBeRemoved(this.toRemoveCommits, tempCommit.short_id),
);
} else {
// If user is present in first tab and deselects a commit, remove it directly
if (this.tabIndex === 0) {
tempSelectedCommits = removeIfPresent(tempSelectedCommits, tempCommit.short_id);
}
// If user deselects a commit which is already present in previously merged commits, we keep track of it in a list to remove
const contextCommitsIndex = findCommitIndex(this.contextCommits, tempCommit.short_id);
if (contextCommitsIndex !== -1) {
this.setToRemoveCommits([...this.toRemoveCommits, tempCommit.short_id]);
}
}
this.setCommits({ commits: tempCommits });
this.setSelectedCommits([
...tempSelectedCommits,
...tempCommits.filter(commit => commit.isSelected),
]);
},
handleCreateContextCommits() {
if (this.uniqueCommits.length > 0 && this.toRemoveCommits.length > 0) {
return Promise.all([
this.createContextCommits({ commits: this.uniqueCommits }),
this.removeContextCommits(),
]).then(values => {
if (values[0] || values[1]) {
window.location.reload();
}
if (!values[0] && !values[1]) {
createFlash(
s__('ContextCommits|Failed to create/remove context commits. Please try again.'),
);
}
});
} else if (this.uniqueCommits.length > 0) {
return this.createContextCommits({ commits: this.uniqueCommits, forceReload: true });
}
return this.removeContextCommits(true);
},
handleModalClose() {
this.resetModalState();
clearTimeout(this.timeout);
},
handleModalHide() {
this.resetModalState();
clearTimeout(this.timeout);
},
},
};
</script>
<template>
<gl-modal
ref="modal"
cancel-variant="light"
size="md"
body-class="add-review-item pt-0"
:scrollable="true"
:ok-title="__('Save changes')"
modal-id="add-review-item"
:title="__('Add or remove previously merged commits')"
:ok-disabled="disableSaveButton"
@shown="focusSearch"
@ok="handleCreateContextCommits"
@cancel="handleModalClose"
@close="handleModalClose"
@hide="handleModalHide"
>
<gl-tabs v-model="currentTabIndex" content-class="pt-0">
<gl-tab>
<template #title>
<gl-sprintf :message="__(`Commits in %{codeStart}${targetBranch}%{codeEnd}`)">
<template #code="{ content }">
<code>{{ content }}</code>
</template>
</gl-sprintf>
</template>
<div class="mt-2">
<gl-search-box-by-type
ref="searchInput"
:placeholder="__(`Search by commit title or SHA`)"
@input="handleSearchCommits"
/>
<review-tab-container
:is-loading="isLoadingCommits"
:loading-error="commitsLoadingError"
:loading-failed-text="__('Unable to load commits. Try again later.')"
:commits="commits"
:empty-list-text="__('Your search didn\'t match any commits. Try a different query.')"
@handleCommitSelect="handleCommitRowSelect"
/>
</div>
</gl-tab>
<gl-tab>
<template #title>
{{ __('Selected commits') }}
<span class="badge badge-pill">{{ selectedCommitsCount }}</span>
</template>
<review-tab-container
:is-loading="isLoadingContextCommits"
:loading-error="contextCommitsLoadingError"
:loading-failed-text="__('Unable to load commits. Try again later.')"
:commits="selectedCommits"
:empty-list-text="
__(
'Commits you select appear here. Go to the first tab and select commits to add to this merge request.',
)
"
@handleCommitSelect="handleCommitRowSelect"
/>
</gl-tab>
</gl-tabs>
</gl-modal>
</template>

View file

@ -0,0 +1,57 @@
<script>
import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
import CommitItem from '~/diffs/components/commit_item.vue';
import { __ } from '~/locale';
export default {
components: {
GlLoadingIcon,
GlAlert,
CommitItem,
},
props: {
isLoading: {
type: Boolean,
required: true,
},
loadingError: {
type: Boolean,
required: true,
},
loadingFailedText: {
type: String,
required: true,
},
commits: {
type: Array,
required: true,
},
emptyListText: {
type: String,
required: false,
default: __('No commits present here'),
},
},
};
</script>
<template>
<gl-loading-icon v-if="isLoading" size="lg" class="mt-3" />
<gl-alert v-else-if="loadingError" variant="danger" :dismissible="false" class="mt-3">
{{ loadingFailedText }}
</gl-alert>
<div v-else-if="commits.length === 0" class="text-center mt-4">
<span>{{ emptyListText }}</span>
</div>
<div v-else>
<ul class="content-list commit-list flex-list">
<commit-item
v-for="(commit, index) in commits"
:key="commit.id"
:is-selectable="true"
:commit="commit"
:checked="commit.isSelected"
@handleCheckboxChange="$emit('handleCommitSelect', [index, $event])"
/>
</ul>
</div>
</template>

View file

@ -0,0 +1,64 @@
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
import createStore from './store';
import AddContextCommitsModalTrigger from './components/add_context_commits_modal_trigger.vue';
import AddContextCommitsModalWrapper from './components/add_context_commits_modal_wrapper.vue';
export default function initAddContextCommitsTriggers() {
const addContextCommitsModalTriggerEl = document.querySelector('.add-review-item-modal-trigger');
const addContextCommitsModalWrapperEl = document.querySelector('.add-review-item-modal-wrapper');
if (addContextCommitsModalTriggerEl || addContextCommitsModalWrapperEl) {
// eslint-disable-next-line no-new
new Vue({
el: addContextCommitsModalTriggerEl,
data() {
const { commitsEmpty, contextCommitsEmpty } = this.$options.el.dataset;
return {
commitsEmpty: parseBoolean(commitsEmpty),
contextCommitsEmpty: parseBoolean(contextCommitsEmpty),
};
},
render(createElement) {
return createElement(AddContextCommitsModalTrigger, {
props: {
commitsEmpty: this.commitsEmpty,
contextCommitsEmpty: this.contextCommitsEmpty,
},
});
},
});
const store = createStore();
// eslint-disable-next-line no-new
new Vue({
el: addContextCommitsModalWrapperEl,
store,
data() {
const {
contextCommitsPath,
targetBranch,
mergeRequestIid,
projectId,
} = this.$options.el.dataset;
return {
contextCommitsPath,
targetBranch,
mergeRequestIid: Number(mergeRequestIid),
projectId: Number(projectId),
};
},
render(createElement) {
return createElement(AddContextCommitsModalWrapper, {
props: {
contextCommitsPath: this.contextCommitsPath,
targetBranch: this.targetBranch,
mergeRequestIid: this.mergeRequestIid,
projectId: this.projectId,
},
});
},
});
}
}

View file

@ -0,0 +1,134 @@
import _ from 'lodash';
import axios from '~/lib/utils/axios_utils';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { s__ } from '~/locale';
import Api from '~/api';
import * as types from './mutation_types';
export const setBaseConfig = ({ commit }, options) => {
commit(types.SET_BASE_CONFIG, options);
};
export const setTabIndex = ({ commit }, tabIndex) => commit(types.SET_TABINDEX, tabIndex);
export const searchCommits = ({ dispatch, commit, state }, searchText) => {
commit(types.FETCH_COMMITS);
let params = {};
if (searchText) {
params = {
params: {
search: searchText,
per_page: 40,
},
};
}
return axios
.get(state.contextCommitsPath, params)
.then(({ data }) => {
let commits = data.map(o => ({ ...o, isSelected: false }));
commits = commits.map(c => {
const isPresent = state.selectedCommits.find(
selectedCommit => selectedCommit.short_id === c.short_id && selectedCommit.isSelected,
);
if (isPresent) {
return { ...c, isSelected: true };
}
return c;
});
if (!searchText) {
dispatch('setCommits', { commits: [...commits, ...state.contextCommits] });
} else {
dispatch('setCommits', { commits });
}
})
.catch(() => {
commit(types.FETCH_COMMITS_ERROR);
});
};
export const setCommits = ({ commit }, { commits: data, silentAddition = false }) => {
let commits = _.uniqBy(data, 'short_id');
commits = _.orderBy(data, c => new Date(c.committed_date), ['desc']);
if (silentAddition) {
commit(types.SET_COMMITS_SILENT, commits);
} else {
commit(types.SET_COMMITS, commits);
}
};
export const createContextCommits = ({ state }, { commits, forceReload = false }) =>
Api.createContextCommits(state.projectId, state.mergeRequestIid, {
commits: commits.map(commit => commit.short_id),
})
.then(() => {
if (forceReload) {
window.location.reload();
}
return true;
})
.catch(() => {
if (forceReload) {
createFlash(s__('ContextCommits|Failed to create context commits. Please try again.'));
}
return false;
});
export const fetchContextCommits = ({ dispatch, commit, state }) => {
commit(types.FETCH_CONTEXT_COMMITS);
return Api.allContextCommits(state.projectId, state.mergeRequestIid)
.then(({ data }) => {
const contextCommits = data.map(o => ({ ...o, isSelected: true }));
dispatch('setContextCommits', contextCommits);
dispatch('setCommits', {
commits: [...state.commits, ...contextCommits],
silentAddition: true,
});
dispatch('setSelectedCommits', contextCommits);
})
.catch(() => {
commit(types.FETCH_CONTEXT_COMMITS_ERROR);
});
};
export const setContextCommits = ({ commit }, data) => {
commit(types.SET_CONTEXT_COMMITS, data);
};
export const removeContextCommits = ({ state }, forceReload = false) =>
Api.removeContextCommits(state.projectId, state.mergeRequestIid, {
commits: state.toRemoveCommits,
})
.then(() => {
if (forceReload) {
window.location.reload();
}
return true;
})
.catch(() => {
if (forceReload) {
createFlash(s__('ContextCommits|Failed to delete context commits. Please try again.'));
}
return false;
});
export const setSelectedCommits = ({ commit }, selected) => {
let selectedCommits = _.uniqBy(selected, 'short_id');
selectedCommits = _.orderBy(
selectedCommits,
selectedCommit => new Date(selectedCommit.committed_date),
['desc'],
);
commit(types.SET_SELECTED_COMMITS, selectedCommits);
};
export const setSearchText = ({ commit }, searchText) => commit(types.SET_SEARCH_TEXT, searchText);
export const setToRemoveCommits = ({ commit }, data) => commit(types.SET_TO_REMOVE_COMMITS, data);
export const resetModalState = ({ commit }) => commit(types.RESET_MODAL_STATE);

View file

@ -0,0 +1,15 @@
import Vue from 'vue';
import Vuex from 'vuex';
import * as actions from './actions';
import mutations from './mutations';
import state from './state';
Vue.use(Vuex);
export default () =>
new Vuex.Store({
namespaced: true,
state: state(),
actions,
mutations,
});

View file

@ -0,0 +1,20 @@
export const SET_BASE_CONFIG = 'SET_BASE_CONFIG';
export const SET_TABINDEX = 'SET_TABINDEX';
export const FETCH_COMMITS = 'FETCH_COMMITS';
export const SET_COMMITS = 'SET_COMMITS';
export const SET_COMMITS_SILENT = 'SET_COMMITS_SILENT';
export const FETCH_COMMITS_ERROR = 'FETCH_COMMITS_ERROR';
export const FETCH_CONTEXT_COMMITS = 'FETCH_CONTEXT_COMMITS';
export const SET_CONTEXT_COMMITS = 'SET_CONTEXT_COMMITS';
export const FETCH_CONTEXT_COMMITS_ERROR = 'FETCH_CONTEXT_COMMITS_ERROR';
export const SET_SELECTED_COMMITS = 'SET_SELECTED_COMMITS';
export const SET_SEARCH_TEXT = 'SET_SEARCH_TEXT';
export const SET_TO_REMOVE_COMMITS = 'SET_TO_REMOVE_COMMITS';
export const RESET_MODAL_STATE = 'RESET_MODAL_STATE';

View file

@ -0,0 +1,56 @@
import * as types from './mutation_types';
export default {
[types.SET_BASE_CONFIG](state, options) {
Object.assign(state, { ...options });
},
[types.SET_TABINDEX](state, tabIndex) {
state.tabIndex = tabIndex;
},
[types.FETCH_COMMITS](state) {
state.isLoadingCommits = true;
state.commitsLoadingError = false;
},
[types.SET_COMMITS](state, commits) {
state.commits = commits;
state.isLoadingCommits = false;
state.commitsLoadingError = false;
},
[types.SET_COMMITS_SILENT](state, commits) {
state.commits = commits;
},
[types.FETCH_COMMITS_ERROR](state) {
state.commitsLoadingError = true;
state.isLoadingCommits = false;
},
[types.FETCH_CONTEXT_COMMITS](state) {
state.isLoadingContextCommits = true;
state.contextCommitsLoadingError = false;
},
[types.SET_CONTEXT_COMMITS](state, contextCommits) {
state.contextCommits = contextCommits;
state.isLoadingContextCommits = false;
state.contextCommitsLoadingError = false;
},
[types.FETCH_CONTEXT_COMMITS_ERROR](state) {
state.contextCommitsLoadingError = true;
state.isLoadingContextCommits = false;
},
[types.SET_SELECTED_COMMITS](state, commits) {
state.selectedCommits = commits;
},
[types.SET_SEARCH_TEXT](state, searchText) {
state.searchText = searchText;
},
[types.SET_TO_REMOVE_COMMITS](state, commits) {
state.toRemoveCommits = commits;
},
[types.RESET_MODAL_STATE](state) {
state.tabIndex = 0;
state.commits = [];
state.contextCommits = [];
state.selectedCommits = [];
state.toRemoveCommits = [];
state.searchText = '';
},
};

View file

@ -0,0 +1,13 @@
export default () => ({
contextCommitsPath: '',
tabIndex: 0,
isLoadingCommits: false,
commits: [],
commitsLoadingError: false,
selectedCommits: [],
isLoadingContextCommits: false,
contextCommits: [],
contextCommitsLoadingError: false,
searchText: '',
toRemoveCommits: [],
});

View file

@ -0,0 +1,32 @@
export const findCommitIndex = (commits, commitShortId) => {
return commits.findIndex(commit => commit.short_id === commitShortId);
};
export const setCommitStatus = (commits, commitIndex, selected) => {
const tempCommits = [...commits];
tempCommits[commitIndex] = {
...tempCommits[commitIndex],
isSelected: selected,
};
return tempCommits;
};
export const removeIfReadyToBeRemoved = (toRemoveCommits, commitShortId) => {
const tempToRemoveCommits = [...toRemoveCommits];
const isPresentInToRemove = tempToRemoveCommits.indexOf(commitShortId);
if (isPresentInToRemove !== -1) {
tempToRemoveCommits.splice(isPresentInToRemove, 1);
}
return tempToRemoveCommits;
};
export const removeIfPresent = (selectedCommits, commitShortId) => {
const tempSelectedCommits = [...selectedCommits];
const selectedCommitsIndex = findCommitIndex(tempSelectedCommits, commitShortId);
if (selectedCommitsIndex !== -1) {
tempSelectedCommits.splice(selectedCommitsIndex, 1);
}
return tempSelectedCommits;
};

View file

@ -1,6 +1,6 @@
import Api from '~/api'; import Api from '~/api';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import createFlash from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import * as types from './mutation_types'; import * as types from './mutation_types';
@ -23,6 +23,3 @@ export const receiveStatisticsError = ({ commit }, error) => {
commit(types.RECEIVE_STATISTICS_ERROR, error); commit(types.RECEIVE_STATISTICS_ERROR, error);
createFlash(s__('AdminDashboard|Error loading the statistics. Please try again')); createFlash(s__('AdminDashboard|Error loading the statistics. Please try again'));
}; };
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};

View file

@ -3,6 +3,7 @@
* and returns an array of the following form: * and returns an array of the following form:
* [{ key: "forks", label: "Forks", value: 50 }] * [{ key: "forks", label: "Forks", value: 50 }]
*/ */
// eslint-disable-next-line import/prefer-default-export
export const getStatistics = state => labels => export const getStatistics = state => labels =>
Object.keys(labels).map(key => { Object.keys(labels).map(key => {
const result = { const result = {
@ -12,6 +13,3 @@ export const getStatistics = state => labels =>
}; };
return result; return result;
}); });
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};

View file

@ -35,13 +35,24 @@ export default {
errorMsg: s__( errorMsg: s__(
'AlertManagement|There was an error displaying the alert. Please refresh the page to try again.', 'AlertManagement|There was an error displaying the alert. Please refresh the page to try again.',
), ),
fullAlertDetailsTitle: s__('AlertManagement|Alert details'),
overviewTitle: s__('AlertManagement|Overview'),
metricsTitle: s__('AlertManagement|Metrics'),
reportedAt: s__('AlertManagement|Reported %{when}'), reportedAt: s__('AlertManagement|Reported %{when}'),
reportedAtWithTool: s__('AlertManagement|Reported %{when} by %{tool}'), reportedAtWithTool: s__('AlertManagement|Reported %{when} by %{tool}'),
}, },
severityLabels: ALERTS_SEVERITY_LABELS, severityLabels: ALERTS_SEVERITY_LABELS,
tabsConfig: [
{
id: 'overview',
title: s__('AlertManagement|Overview'),
},
{
id: 'fullDetails',
title: s__('AlertManagement|Alert details'),
},
{
id: 'metrics',
title: s__('AlertManagement|Metrics'),
},
],
components: { components: {
GlBadge, GlBadge,
GlAlert, GlAlert,
@ -102,8 +113,8 @@ export default {
errored: false, errored: false,
sidebarStatus: false, sidebarStatus: false,
isErrorDismissed: false, isErrorDismissed: false,
createIssueError: '', createIncidentError: '',
issueCreationInProgress: false, incidentCreationInProgress: false,
sidebarErrorMessage: '', sidebarErrorMessage: '',
}; };
}, },
@ -119,6 +130,18 @@ export default {
showErrorMsg() { showErrorMsg() {
return this.errored && !this.isErrorDismissed; return this.errored && !this.isErrorDismissed;
}, },
activeTab() {
return this.$route.params.tabId || this.$options.tabsConfig[0].id;
},
currentTabIndex: {
get() {
return this.$options.tabsConfig.findIndex(tab => tab.id === this.activeTab);
},
set(tabIdx) {
const tabId = this.$options.tabsConfig[tabIdx].id;
this.$router.replace({ name: 'tab', params: { tabId } });
},
},
}, },
mounted() { mounted() {
this.trackPageViews(); this.trackPageViews();
@ -149,8 +172,8 @@ export default {
this.errored = true; this.errored = true;
this.sidebarErrorMessage = errorMessage; this.sidebarErrorMessage = errorMessage;
}, },
createIssue() { createIncident() {
this.issueCreationInProgress = true; this.incidentCreationInProgress = true;
this.$apollo this.$apollo
.mutate({ .mutate({
@ -162,18 +185,18 @@ export default {
}) })
.then(({ data: { createAlertIssue: { errors, issue } } }) => { .then(({ data: { createAlertIssue: { errors, issue } } }) => {
if (errors?.length) { if (errors?.length) {
[this.createIssueError] = errors; [this.createIncidentError] = errors;
this.issueCreationInProgress = false; this.incidentCreationInProgress = false;
} else if (issue) { } else if (issue) {
visitUrl(this.issuePath(issue.iid)); visitUrl(this.incidentPath(issue.iid));
} }
}) })
.catch(error => { .catch(error => {
this.createIssueError = error; this.createIncidentError = error;
this.issueCreationInProgress = false; this.incidentCreationInProgress = false;
}); });
}, },
issuePath(issueId) { incidentPath(issueId) {
return joinPaths(this.projectIssuesPath, issueId); return joinPaths(this.projectIssuesPath, issueId);
}, },
trackPageViews() { trackPageViews() {
@ -190,12 +213,12 @@ export default {
<p v-html="sidebarErrorMessage || $options.i18n.errorMsg"></p> <p v-html="sidebarErrorMessage || $options.i18n.errorMsg"></p>
</gl-alert> </gl-alert>
<gl-alert <gl-alert
v-if="createIssueError" v-if="createIncidentError"
variant="danger" variant="danger"
data-testid="issueCreationError" data-testid="incidentCreationError"
@dismiss="createIssueError = null" @dismiss="createIncidentError = null"
> >
{{ createIssueError }} {{ createIncidentError }}
</gl-alert> </gl-alert>
<div v-if="loading"><gl-loading-icon size="lg" class="gl-mt-5" /></div> <div v-if="loading"><gl-loading-icon size="lg" class="gl-mt-5" /></div>
<div <div
@ -204,19 +227,12 @@ export default {
:class="{ 'pr-sm-8': sidebarStatus }" :class="{ 'pr-sm-8': sidebarStatus }"
> >
<div <div
class="gl-display-flex gl-justify-content-space-between gl-align-items-baseline gl-px-1 py-3 py-md-4 gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid flex-column flex-sm-row" class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-px-1 py-3 py-md-4 gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-flex-direction-column gl-sm-flex-direction-row"
> >
<div <div data-testid="alert-header">
data-testid="alert-header" <gl-badge class="gl-mr-3">
class="gl-display-flex gl-align-items-center gl-justify-content-center" <strong>{{ s__('AlertManagement|Alert') }}</strong>
> </gl-badge>
<div
class="gl-display-inline-flex gl-align-items-center gl-justify-content-space-between"
>
<gl-badge class="gl-mr-3">
<strong>{{ s__('AlertManagement|Alert') }}</strong>
</gl-badge>
</div>
<span> <span>
<gl-sprintf :message="reportedAtMessage"> <gl-sprintf :message="reportedAtMessage">
<template #when> <template #when>
@ -228,24 +244,24 @@ export default {
</div> </div>
<gl-button <gl-button
v-if="alert.issueIid" v-if="alert.issueIid"
class="gl-mt-3 mt-sm-0 align-self-center align-self-sm-baseline alert-details-issue-button" class="gl-mt-3 mt-sm-0 align-self-center align-self-sm-baseline alert-details-incident-button"
data-testid="viewIssueBtn" data-testid="viewIncidentBtn"
:href="issuePath(alert.issueIid)" :href="incidentPath(alert.issueIid)"
category="primary" category="primary"
variant="success" variant="success"
> >
{{ s__('AlertManagement|View issue') }} {{ s__('AlertManagement|View incident') }}
</gl-button> </gl-button>
<gl-button <gl-button
v-else v-else
class="gl-mt-3 mt-sm-0 align-self-center align-self-sm-baseline alert-details-issue-button" class="gl-mt-3 mt-sm-0 align-self-center align-self-sm-baseline alert-details-incident-button"
data-testid="createIssueBtn" data-testid="createIncidentBtn"
:loading="issueCreationInProgress" :loading="incidentCreationInProgress"
category="primary" category="primary"
variant="success" variant="success"
@click="createIssue()" @click="createIncident()"
> >
{{ s__('AlertManagement|Create issue') }} {{ s__('AlertManagement|Create incident') }}
</gl-button> </gl-button>
<gl-button <gl-button
:aria-label="__('Toggle sidebar')" :aria-label="__('Toggle sidebar')"
@ -264,8 +280,8 @@ export default {
> >
<h2 data-testid="title">{{ alert.title }}</h2> <h2 data-testid="title">{{ alert.title }}</h2>
</div> </div>
<gl-tabs v-if="alert" data-testid="alertDetailsTabs"> <gl-tabs v-if="alert" v-model="currentTabIndex" data-testid="alertDetailsTabs">
<gl-tab data-testid="overviewTab" :title="$options.i18n.overviewTitle"> <gl-tab :data-testid="$options.tabsConfig[0].id" :title="$options.tabsConfig[0].title">
<div v-if="alert.severity" class="gl-mt-3 gl-mb-5 gl-display-flex"> <div v-if="alert.severity" class="gl-mt-3 gl-mb-5 gl-display-flex">
<div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3"> <div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3">
{{ s__('AlertManagement|Severity') }}: {{ s__('AlertManagement|Severity') }}:
@ -308,6 +324,12 @@ export default {
</div> </div>
<div class="gl-pl-2" data-testid="service">{{ alert.service }}</div> <div class="gl-pl-2" data-testid="service">{{ alert.service }}</div>
</div> </div>
<div v-if="alert.runbook" class="gl-my-5 gl-display-flex">
<div class="bold gl-w-13 gl-text-right gl-pr-3">
{{ s__('AlertManagement|Runbook') }}:
</div>
<div class="gl-pl-2" data-testid="runbook">{{ alert.runbook }}</div>
</div>
<template> <template>
<div v-if="alert.notes.nodes" class="issuable-discussion py-5"> <div v-if="alert.notes.nodes" class="issuable-discussion py-5">
<ul class="notes main-notes-list timeline"> <ul class="notes main-notes-list timeline">
@ -316,7 +338,7 @@ export default {
</div> </div>
</template> </template>
</gl-tab> </gl-tab>
<gl-tab data-testid="fullDetailsTab" :title="$options.i18n.fullAlertDetailsTitle"> <gl-tab :data-testid="$options.tabsConfig[1].id" :title="$options.tabsConfig[1].title">
<gl-table <gl-table
class="alert-management-details-table" class="alert-management-details-table"
:items="[{ key: 'Value', ...alert }]" :items="[{ key: 'Value', ...alert }]"
@ -332,7 +354,7 @@ export default {
</template> </template>
</gl-table> </gl-table>
</gl-tab> </gl-tab>
<gl-tab data-testId="metricsTab" :title="$options.i18n.metricsTitle"> <gl-tab :data-testid="$options.tabsConfig[2].id" :title="$options.tabsConfig[2].title">
<alert-metrics :dashboard-url="alert.metricsDashboardUrl" /> <alert-metrics :dashboard-url="alert.metricsDashboardUrl" />
</gl-tab> </gl-tab>
</gl-tabs> </gl-tabs>

View file

@ -1,6 +1,7 @@
<script> <script>
import { GlEmptyState, GlButton } from '@gitlab/ui'; import { GlEmptyState, GlButton, GlLink } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import alertsHelpUrlQuery from '../graphql/queries/alert_help_url.query.graphql';
export default { export default {
i18n: { i18n: {
@ -25,6 +26,12 @@ export default {
components: { components: {
GlEmptyState, GlEmptyState,
GlButton, GlButton,
GlLink,
},
apollo: {
alertsHelpUrl: {
query: alertsHelpUrlQuery,
},
}, },
props: { props: {
enableAlertManagementPath: { enableAlertManagementPath: {
@ -50,6 +57,11 @@ export default {
default: '', default: '',
}, },
}, },
data() {
return {
alertsHelpUrl: '',
};
},
computed: { computed: {
emptyState() { emptyState() {
return { return {
@ -71,13 +83,9 @@ export default {
<template #description> <template #description>
<div class="gl-display-block"> <div class="gl-display-block">
<span>{{ emptyState.info }}</span> <span>{{ emptyState.info }}</span>
<a <gl-link v-if="!opsgenieMvcEnabled" :href="alertsHelpUrl" target="_blank">
v-if="!opsgenieMvcEnabled"
href="/help/user/project/operations/alert_management.html"
target="_blank"
>
{{ $options.i18n.moreInformation }} {{ $options.i18n.moreInformation }}
</a> </gl-link>
</div> </div>
<div v-if="alertsCanBeEnabled" class="gl-display-block center gl-pt-4"> <div v-if="alertsCanBeEnabled" class="gl-display-block center gl-pt-4">
<gl-button category="primary" variant="success" :href="emptyState.link"> <gl-button category="primary" variant="success" :href="emptyState.link">

View file

@ -12,8 +12,8 @@ import {
GlSearchBoxByType, GlSearchBoxByType,
GlSprintf, GlSprintf,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import { debounce, trim } from 'lodash'; import { debounce, trim } from 'lodash';
import { __, s__ } from '~/locale';
import { joinPaths, visitUrl } from '~/lib/utils/url_utility'; import { joinPaths, visitUrl } from '~/lib/utils/url_utility';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
@ -60,15 +60,15 @@ export default {
{ {
key: 'severity', key: 'severity',
label: s__('AlertManagement|Severity'), label: s__('AlertManagement|Severity'),
tdClass: `${tdClass} rounded-top text-capitalize`,
thClass: `${thClass} gl-w-eighth`, thClass: `${thClass} gl-w-eighth`,
tdClass: `${tdClass} rounded-top text-capitalize sortable-cell`,
sortable: true, sortable: true,
}, },
{ {
key: 'startedAt', key: 'startedAt',
label: s__('AlertManagement|Start time'), label: s__('AlertManagement|Start time'),
thClass: `${thClass} js-started-at w-15p`, thClass: `${thClass} js-started-at w-15p`,
tdClass, tdClass: `${tdClass} sortable-cell`,
sortable: true, sortable: true,
}, },
{ {
@ -81,7 +81,7 @@ export default {
key: 'eventCount', key: 'eventCount',
label: s__('AlertManagement|Events'), label: s__('AlertManagement|Events'),
thClass: `${thClass} text-right gl-w-12`, thClass: `${thClass} text-right gl-w-12`,
tdClass: `${tdClass} text-md-right`, tdClass: `${tdClass} text-md-right sortable-cell`,
sortable: true, sortable: true,
}, },
{ {
@ -89,7 +89,6 @@ export default {
label: s__('AlertManagement|Issue'), label: s__('AlertManagement|Issue'),
thClass: 'gl-w-12 gl-pointer-events-none', thClass: 'gl-w-12 gl-pointer-events-none',
tdClass, tdClass,
sortable: false,
}, },
{ {
key: 'assignees', key: 'assignees',
@ -99,9 +98,9 @@ export default {
}, },
{ {
key: 'status', key: 'status',
thClass: `${thClass} w-15p`,
label: s__('AlertManagement|Status'), label: s__('AlertManagement|Status'),
tdClass: `${tdClass} rounded-bottom`, thClass: `${thClass} w-15p`,
tdClass: `${tdClass} rounded-bottom sortable-cell`,
sortable: true, sortable: true,
}, },
], ],
@ -169,7 +168,7 @@ export default {
}; };
}, },
error() { error() {
this.errored = true; this.hasError = true;
}, },
}, },
alertsCount: { alertsCount: {
@ -188,10 +187,9 @@ export default {
data() { data() {
return { return {
searchTerm: '', searchTerm: '',
errored: false, hasError: false,
errorMessage: '', errorMessage: '',
isAlertDismissed: false, isAlertDismissed: false,
isErrorAlertDismissed: false,
sort: 'STARTED_AT_DESC', sort: 'STARTED_AT_DESC',
statusFilter: [], statusFilter: [],
filteredByStatus: '', filteredByStatus: '',
@ -204,16 +202,13 @@ export default {
computed: { computed: {
showNoAlertsMsg() { showNoAlertsMsg() {
return ( return (
!this.errored && !this.hasError &&
!this.loading && !this.loading &&
this.alertsCount?.all === 0 && this.alertsCount?.all === 0 &&
!this.searchTerm && !this.searchTerm &&
!this.isAlertDismissed !this.isAlertDismissed
); );
}, },
showErrorMsg() {
return this.errored && !this.isErrorAlertDismissed;
},
loading() { loading() {
return this.$apollo.queries.alerts.loading; return this.$apollo.queries.alerts.loading;
}, },
@ -307,11 +302,11 @@ export default {
}; };
}, },
handleAlertError(errorMessage) { handleAlertError(errorMessage) {
this.errored = true; this.hasError = true;
this.errorMessage = errorMessage; this.errorMessage = errorMessage;
}, },
dismissError() { dismissError() {
this.isErrorAlertDismissed = true; this.hasError = false;
this.errorMessage = ''; this.errorMessage = '';
}, },
}, },
@ -319,7 +314,7 @@ export default {
</script> </script>
<template> <template>
<div> <div>
<div class="alert-management-list"> <div class="incident-management-list">
<gl-alert v-if="showNoAlertsMsg" @dismiss="isAlertDismissed = true"> <gl-alert v-if="showNoAlertsMsg" @dismiss="isAlertDismissed = true">
<gl-sprintf :message="$options.i18n.noAlertsMsg"> <gl-sprintf :message="$options.i18n.noAlertsMsg">
<template #link="{ content }"> <template #link="{ content }">
@ -333,16 +328,14 @@ export default {
</template> </template>
</gl-sprintf> </gl-sprintf>
</gl-alert> </gl-alert>
<gl-alert <gl-alert v-if="hasError" variant="danger" data-testid="alert-error" @dismiss="dismissError">
v-if="showErrorMsg"
variant="danger"
data-testid="alert-error"
@dismiss="dismissError"
>
<p v-html="errorMessage || $options.i18n.errorMsg"></p> <p v-html="errorMessage || $options.i18n.errorMsg"></p>
</gl-alert> </gl-alert>
<gl-tabs content-class="gl-p-0" @input="filterAlertsByStatus"> <gl-tabs
content-class="gl-p-0 gl-border-b-solid gl-border-b-1 gl-border-gray-100"
@input="filterAlertsByStatus"
>
<gl-tab v-for="tab in $options.statusTabs" :key="tab.status"> <gl-tab v-for="tab in $options.statusTabs" :key="tab.status">
<template slot="title"> <template slot="title">
<span>{{ tab.title }}</span> <span>{{ tab.title }}</span>

View file

@ -1,5 +1,5 @@
<script> <script>
import { GlDropdown, GlDropdownItem, GlButton } from '@gitlab/ui'; import { GlDeprecatedDropdown, GlDeprecatedDropdownItem, GlButton } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import { trackAlertStatusUpdateOptions } from '../constants'; import { trackAlertStatusUpdateOptions } from '../constants';
@ -18,8 +18,8 @@ export default {
RESOLVED: s__('AlertManagement|Resolved'), RESOLVED: s__('AlertManagement|Resolved'),
}, },
components: { components: {
GlDropdown, GlDeprecatedDropdown,
GlDropdownItem, GlDeprecatedDropdownItem,
GlButton, GlButton,
}, },
props: { props: {
@ -91,7 +91,7 @@ export default {
<template> <template>
<div class="dropdown dropdown-menu-selectable" :class="dropdownClass"> <div class="dropdown dropdown-menu-selectable" :class="dropdownClass">
<gl-dropdown <gl-deprecated-dropdown
ref="dropdown" ref="dropdown"
right right
:text="$options.statuses[alert.status]" :text="$options.statuses[alert.status]"
@ -112,7 +112,7 @@ export default {
/> />
</div> </div>
<div class="dropdown-content dropdown-body"> <div class="dropdown-content dropdown-body">
<gl-dropdown-item <gl-deprecated-dropdown-item
v-for="(label, field) in $options.statuses" v-for="(label, field) in $options.statuses"
:key="field" :key="field"
data-testid="statusDropdownItem" data-testid="statusDropdownItem"
@ -122,8 +122,8 @@ export default {
@click="updateAlertStatus(label)" @click="updateAlertStatus(label)"
> >
{{ label }} {{ label }}
</gl-dropdown-item> </gl-deprecated-dropdown-item>
</div> </div>
</gl-dropdown> </gl-deprecated-dropdown>
</div> </div>
</template> </template>

View file

@ -1,9 +1,9 @@
<script> <script>
import { GlDropdownItem } from '@gitlab/ui'; import { GlDeprecatedDropdownItem } from '@gitlab/ui';
export default { export default {
components: { components: {
GlDropdownItem, GlDeprecatedDropdownItem,
}, },
props: { props: {
user: { user: {
@ -24,7 +24,7 @@ export default {
</script> </script>
<template> <template>
<gl-dropdown-item <gl-deprecated-dropdown-item
:key="user.username" :key="user.username"
data-testid="assigneeDropdownItem" data-testid="assigneeDropdownItem"
class="assignee-dropdown-item gl-vertical-align-middle" class="assignee-dropdown-item gl-vertical-align-middle"
@ -47,5 +47,5 @@ export default {
</strong> </strong>
<span class="dropdown-menu-user-username"> {{ user.username }}</span> <span class="dropdown-menu-user-username"> {{ user.username }}</span>
</span> </span>
</gl-dropdown-item> </gl-deprecated-dropdown-item>
</template> </template>

View file

@ -1,20 +1,20 @@
<script> <script>
import { import {
GlIcon, GlIcon,
GlDropdown, GlDeprecatedDropdown,
GlDropdownDivider, GlDeprecatedDropdownDivider,
GlDropdownHeader, GlDeprecatedDropdownHeader,
GlDropdownItem, GlDeprecatedDropdownItem,
GlLoadingIcon, GlLoadingIcon,
GlTooltip, GlTooltip,
GlButton, GlButton,
GlSprintf, GlSprintf,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { debounce } from 'lodash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import alertSetAssignees from '../../graphql/mutations/alert_set_assignees.mutation.graphql'; import alertSetAssignees from '../../graphql/mutations/alert_set_assignees.mutation.graphql';
import SidebarAssignee from './sidebar_assignee.vue'; import SidebarAssignee from './sidebar_assignee.vue';
import { debounce } from 'lodash';
const DATA_REFETCH_DELAY = 250; const DATA_REFETCH_DELAY = 250;
@ -33,10 +33,10 @@ export default {
}, },
components: { components: {
GlIcon, GlIcon,
GlDropdown, GlDeprecatedDropdown,
GlDropdownItem, GlDeprecatedDropdownItem,
GlDropdownDivider, GlDeprecatedDropdownDivider,
GlDropdownHeader, GlDeprecatedDropdownHeader,
GlLoadingIcon, GlLoadingIcon,
GlTooltip, GlTooltip,
GlButton, GlButton,
@ -213,7 +213,7 @@ export default {
</p> </p>
<div class="dropdown dropdown-menu-selectable" :class="dropdownClass"> <div class="dropdown dropdown-menu-selectable" :class="dropdownClass">
<gl-dropdown <gl-deprecated-dropdown
ref="dropdown" ref="dropdown"
:text="assignedUser" :text="assignedUser"
class="w-100" class="w-100"
@ -243,18 +243,18 @@ export default {
</div> </div>
<div class="dropdown-content dropdown-body"> <div class="dropdown-content dropdown-body">
<template v-if="userListValid"> <template v-if="userListValid">
<gl-dropdown-item <gl-deprecated-dropdown-item
:active="!userName" :active="!userName"
active-class="is-active" active-class="is-active"
@click="updateAlertAssignees('')" @click="updateAlertAssignees('')"
> >
{{ __('Unassigned') }} {{ __('Unassigned') }}
</gl-dropdown-item> </gl-deprecated-dropdown-item>
<gl-dropdown-divider /> <gl-deprecated-dropdown-divider />
<gl-dropdown-header class="mt-0"> <gl-deprecated-dropdown-header class="mt-0">
{{ __('Assignee') }} {{ __('Assignee') }}
</gl-dropdown-header> </gl-deprecated-dropdown-header>
<sidebar-assignee <sidebar-assignee
v-for="user in sortedUsers" v-for="user in sortedUsers"
:key="user.username" :key="user.username"
@ -263,17 +263,17 @@ export default {
@update-alert-assignees="updateAlertAssignees" @update-alert-assignees="updateAlertAssignees"
/> />
</template> </template>
<gl-dropdown-item v-else-if="userListEmpty"> <gl-deprecated-dropdown-item v-else-if="userListEmpty">
{{ __('No Matching Results') }} {{ __('No Matching Results') }}
</gl-dropdown-item> </gl-deprecated-dropdown-item>
<gl-loading-icon v-else /> <gl-loading-icon v-else />
</div> </div>
</gl-dropdown> </gl-deprecated-dropdown>
</div> </div>
<gl-loading-icon v-if="isUpdating" :inline="true" /> <gl-loading-icon v-if="isUpdating" :inline="true" />
<p v-else-if="!isDropdownShowing" class="value gl-m-0" :class="{ 'no-value': !userName }"> <p v-else-if="!isDropdownShowing" class="value gl-m-0" :class="{ 'no-value': !userName }">
<span v-if="userName" class="gl-text-gray-700" data-testid="assigned-users">{{ <span v-if="userName" class="gl-text-gray-500" data-testid="assigned-users">{{
assignedUser assignedUser
}}</span> }}</span>
<span v-else class="gl-display-flex gl-align-items-center"> <span v-else class="gl-display-flex gl-align-items-center">

View file

@ -27,7 +27,7 @@ export default {
<template> <template>
<div class="block gl-display-flex gl-justify-content-space-between"> <div class="block gl-display-flex gl-justify-content-space-between">
<span class="issuable-header-text hide-collapsed"> <span class="issuable-header-text hide-collapsed">
{{ __('To Do') }} {{ __('To-Do') }}
</span> </span>
<sidebar-todo <sidebar-todo
v-if="!sidebarCollapsed" v-if="!sidebarCollapsed"

View file

@ -107,7 +107,7 @@ export default {
> >
<span <span
v-if="$options.statuses[alert.status]" v-if="$options.statuses[alert.status]"
class="gl-text-gray-700" class="gl-text-gray-500"
data-testid="status" data-testid="status"
>{{ $options.statuses[alert.status] }}</span >{{ $options.statuses[alert.status] }}</span
> >

View file

@ -1,13 +1,14 @@
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import Todo from '~/sidebar/components/todo_toggle/todo.vue'; import Todo from '~/sidebar/components/todo_toggle/todo.vue';
import axios from '~/lib/utils/axios_utils'; import createAlertTodo from '../../graphql/mutations/alert_todo_create.mutation.graphql';
import createAlertTodo from '../../graphql/mutations/alert_todo_create.graphql'; import todoMarkDone from '../../graphql/mutations/alert_todo_mark_done.mutation.graphql';
import alertQuery from '../../graphql/queries/details.query.graphql';
export default { export default {
i18n: { i18n: {
UPDATE_ALERT_TODO_ERROR: s__( UPDATE_ALERT_TODO_ERROR: s__(
'AlertManagement|There was an error while updating the To Do of the alert.', 'AlertManagement|There was an error while updating the To-Do of the alert.',
), ),
}, },
components: { components: {
@ -30,14 +31,24 @@ export default {
data() { data() {
return { return {
isUpdating: false, isUpdating: false,
isTodo: false,
todo: '',
}; };
}, },
computed: { computed: {
alertID() { alertID() {
return parseInt(this.alert.iid, 10); return parseInt(this.alert.iid, 10);
}, },
firstToDoId() {
return this.alert?.todos?.nodes[0]?.id;
},
hasPendingTodos() {
return this.alert?.todos?.nodes.length > 0;
},
getAlertQueryVariables() {
return {
fullPath: this.projectPath,
alertId: this.alert.iid,
};
},
}, },
methods: { methods: {
updateToDoCount(add) { updateToDoCount(add) {
@ -51,11 +62,7 @@ export default {
return document.dispatchEvent(headerTodoEvent); return document.dispatchEvent(headerTodoEvent);
}, },
toggleTodo() { addToDo() {
if (this.todo) {
return this.markAsDone();
}
this.isUpdating = true; this.isUpdating = true;
return this.$apollo return this.$apollo
.mutate({ .mutate({
@ -65,24 +72,14 @@ export default {
projectPath: this.projectPath, projectPath: this.projectPath,
}, },
}) })
.then(({ data: { alertTodoCreate: { todo = {}, errors = [] } } = {} } = {}) => { .then(({ data: { errors = [] } }) => {
if (errors[0]) { if (errors[0]) {
return this.$emit( return this.throwError(errors[0]);
'alert-error',
`${this.$options.i18n.UPDATE_ALERT_TODO_ERROR} ${errors[0]}.`,
);
} }
this.todo = todo.id;
return this.updateToDoCount(true); return this.updateToDoCount(true);
}) })
.catch(() => { .catch(() => {
this.$emit( this.throwError();
'alert-error',
`${this.$options.i18n.UPDATE_ALERT_TODO_ERROR} ${s__(
'AlertManagement|Please try again.',
)}`,
);
}) })
.finally(() => { .finally(() => {
this.isUpdating = false; this.isUpdating = false;
@ -90,20 +87,45 @@ export default {
}, },
markAsDone() { markAsDone() {
this.isUpdating = true; this.isUpdating = true;
return this.$apollo
return axios .mutate({
.delete(`/dashboard/todos/${this.todo.split('/').pop()}`) mutation: todoMarkDone,
.then(() => { variables: {
this.todo = ''; id: this.firstToDoId,
},
update: this.updateCache,
})
.then(({ data: { errors = [] } }) => {
if (errors[0]) {
return this.throwError(errors[0]);
}
return this.updateToDoCount(false); return this.updateToDoCount(false);
}) })
.catch(() => { .catch(() => {
this.$emit('alert-error', this.$options.i18n.UPDATE_ALERT_TODO_ERROR); this.throwError();
}) })
.finally(() => { .finally(() => {
this.isUpdating = false; this.isUpdating = false;
}); });
}, },
updateCache(store) {
const data = store.readQuery({
query: alertQuery,
variables: this.getAlertQueryVariables,
});
data.project.alertManagementAlerts.nodes[0].todos.nodes.shift();
store.writeQuery({
query: alertQuery,
variables: this.getAlertQueryVariables,
data,
});
},
throwError(err = '') {
const error = err || s__('AlertManagement|Please try again.');
this.$emit('alert-error', `${this.$options.i18n.UPDATE_ALERT_TODO_ERROR} ${error}`);
},
}, },
}; };
</script> </script>
@ -114,10 +136,10 @@ export default {
data-testid="alert-todo-button" data-testid="alert-todo-button"
:collapsed="sidebarCollapsed" :collapsed="sidebarCollapsed"
:issuable-id="alertID" :issuable-id="alertID"
:is-todo="todo !== ''" :is-todo="hasPendingTodos"
:is-action-active="isUpdating" :is-action-active="isUpdating"
issuable-type="alert" issuable-type="alert"
@toggleTodo="toggleTodo" @toggleTodo="hasPendingTodos ? markAsDone() : addToDo()"
/> />
</div> </div>
</template> </template>

View file

@ -1,7 +1,8 @@
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { defaultDataIdFromObject } from 'apollo-cache-inmemory'; import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
import createDefaultClient from '~/lib/graphql';
import createRouter from './router';
import AlertDetails from './components/alert_details.vue'; import AlertDetails from './components/alert_details.vue';
import sidebarStatusQuery from './graphql/queries/sidebar_status.query.graphql'; import sidebarStatusQuery from './graphql/queries/sidebar_status.query.graphql';
@ -10,6 +11,7 @@ Vue.use(VueApollo);
export default selector => { export default selector => {
const domEl = document.querySelector(selector); const domEl = document.querySelector(selector);
const { alertId, projectPath, projectIssuesPath, projectId } = domEl.dataset; const { alertId, projectPath, projectIssuesPath, projectId } = domEl.dataset;
const router = createRouter();
const resolvers = { const resolvers = {
Mutation: { Mutation: {
@ -54,6 +56,7 @@ export default selector => {
components: { components: {
AlertDetails, AlertDetails,
}, },
router,
render(createElement) { render(createElement) {
return createElement('alert-details', {}); return createElement('alert-details', {});
}, },

View file

@ -11,6 +11,12 @@ fragment AlertDetailItem on AlertManagementAlert {
updatedAt updatedAt
endedAt endedAt
details details
runbook
todos {
nodes {
id
}
}
notes { notes {
nodes { nodes {
...AlertNote ...AlertNote

View file

@ -1,11 +0,0 @@
mutation($projectPath: ID!, $iid: String!) {
alertTodoCreate(input: { iid: $iid, projectPath: $projectPath }) {
errors
alert {
iid
}
todo {
id
}
}
}

View file

@ -0,0 +1,10 @@
#import "../fragments/detail_item.fragment.graphql"
mutation alertTodoCreate($projectPath: ID!, $iid: String!) {
alertTodoCreate(input: { iid: $iid, projectPath: $projectPath }) {
errors
alert {
...AlertDetailItem
}
}
}

View file

@ -0,0 +1,8 @@
mutation todoMarkDone($id: ID!) {
todoMarkDone(input: { id: $id }) {
errors
todo {
id
}
}
}

View file

@ -0,0 +1,3 @@
query alertsHelpUrl {
alertsHelpUrl @client
}

View file

@ -1,7 +1,7 @@
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { defaultDataIdFromObject } from 'apollo-cache-inmemory'; import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import AlertManagementList from './components/alert_management_list_wrapper.vue'; import AlertManagementList from './components/alert_management_list_wrapper.vue';
@ -16,6 +16,7 @@ export default () => {
enableAlertManagementPath, enableAlertManagementPath,
emptyAlertSvgPath, emptyAlertSvgPath,
populatingAlertsHelpUrl, populatingAlertsHelpUrl,
alertsHelpUrl,
opsgenieMvcTargetUrl, opsgenieMvcTargetUrl,
} = domEl.dataset; } = domEl.dataset;
let { alertManagementEnabled, userCanEnableAlertManagement, opsgenieMvcEnabled } = domEl.dataset; let { alertManagementEnabled, userCanEnableAlertManagement, opsgenieMvcEnabled } = domEl.dataset;
@ -41,6 +42,12 @@ export default () => {
), ),
}); });
apolloProvider.clients.defaultClient.cache.writeData({
data: {
alertsHelpUrl,
},
});
return new Vue({ return new Vue({
el: selector, el: selector,
apolloProvider, apolloProvider,

View file

@ -0,0 +1,13 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import { joinPaths } from '~/lib/utils/url_utility';
Vue.use(VueRouter);
export default function createRouter(base) {
return new VueRouter({
mode: 'hash',
base: joinPaths(gon.relative_url_root || '', base),
routes: [{ path: '/:tabId', name: 'tab' }],
});
}

View file

@ -12,7 +12,7 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import ToggleButton from '~/vue_shared/components/toggle_button.vue'; import ToggleButton from '~/vue_shared/components/toggle_button.vue';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import createFlash from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
export default { export default {
i18n: { i18n: {
@ -180,9 +180,11 @@ export default {
/> />
</span> </span>
</div> </div>
<gl-button v-gl-modal.authKeyModal class="mt-2" :disabled="isDisabled">{{ <span class="gl-display-flex gl-justify-content-end">
$options.RESET_KEY <gl-button v-gl-modal.authKeyModal class="gl-mt-2" :disabled="isDisabled">{{
}}</gl-button> $options.RESET_KEY
}}</gl-button>
</span>
<gl-modal <gl-modal
modal-id="authKeyModal" modal-id="authKeyModal"
:title="$options.RESET_KEY" :title="$options.RESET_KEY"

View file

@ -51,52 +51,26 @@ export default {
'gl-modal': GlModalDirective, 'gl-modal': GlModalDirective,
}, },
mixins: [glFeatureFlagsMixin()], mixins: [glFeatureFlagsMixin()],
props: { inject: ['prometheus', 'generic', 'opsgenie'],
prometheus: {
type: Object,
required: true,
validator: ({ activated }) => {
return activated !== undefined;
},
},
generic: {
type: Object,
required: true,
validator: ({ formPath }) => {
return formPath !== undefined;
},
},
opsgenie: {
type: Object,
required: true,
},
},
data() { data() {
return { return {
activated: {
generic: this.generic.activated,
prometheus: this.prometheus.activated,
opsgenie: this.opsgenie?.activated,
},
loading: false, loading: false,
authorizationKey: {
generic: this.generic.initialAuthorizationKey,
prometheus: this.prometheus.prometheusAuthorizationKey,
},
selectedEndpoint: serviceOptions[0].value, selectedEndpoint: serviceOptions[0].value,
options: serviceOptions, options: serviceOptions,
targetUrl: null, active: false,
authKey: '',
targetUrl: '',
feedback: { feedback: {
variant: 'danger', variant: 'danger',
feedbackMessage: null, feedbackMessage: '',
isFeedbackDismissed: false, isFeedbackDismissed: false,
}, },
serverError: null,
testAlert: { testAlert: {
json: null, json: null,
error: null, error: null,
}, },
canSaveForm: false, canSaveForm: false,
serverError: null,
}; };
}, },
computed: { computed: {
@ -123,24 +97,24 @@ export default {
case 'generic': { case 'generic': {
return { return {
url: this.generic.url, url: this.generic.url,
authKey: this.authorizationKey.generic, authKey: this.generic.authorizationKey,
active: this.activated.generic, activated: this.generic.activated,
resetKey: this.resetGenericKey.bind(this), resetKey: this.resetKey.bind(this),
}; };
} }
case 'prometheus': { case 'prometheus': {
return { return {
url: this.prometheus.prometheusUrl, url: this.prometheus.prometheusUrl,
authKey: this.authorizationKey.prometheus, authKey: this.prometheus.authorizationKey,
active: this.activated.prometheus, activated: this.prometheus.activated,
resetKey: this.resetPrometheusKey.bind(this), resetKey: this.resetKey.bind(this, 'prometheus'),
targetUrl: this.prometheus.prometheusApiUrl, targetUrl: this.prometheus.prometheusApiUrl,
}; };
} }
case 'opsgenie': { case 'opsgenie': {
return { return {
targetUrl: this.opsgenie.opsgenieMvcTargetUrl, targetUrl: this.opsgenie.opsgenieMvcTargetUrl,
active: this.activated.opsgenie, activated: this.opsgenie.activated,
}; };
} }
default: { default: {
@ -164,7 +138,7 @@ export default {
return this.testAlert.error === null; return this.testAlert.error === null;
}, },
canTestAlert() { canTestAlert() {
return this.selectedService.active && this.testAlert.json !== null; return this.active && this.testAlert.json !== null;
}, },
canSaveConfig() { canSaveConfig() {
return !this.loading && this.canSaveForm; return !this.loading && this.canSaveForm;
@ -187,19 +161,21 @@ export default {
}, },
mounted() { mounted() {
if ( if (
this.activated.prometheus || this.prometheus.activated ||
this.activated.generic || this.generic.activated ||
!this.opsgenie.opsgenieMvcIsAvailable !this.opsgenie.opsgenieMvcIsAvailable
) { ) {
this.removeOpsGenieOption(); this.removeOpsGenieOption();
} else if (this.activated.opsgenie) { } else if (this.opsgenie.activated) {
this.setOpsgenieAsDefault(); this.setOpsgenieAsDefault();
} }
this.active = this.selectedService.activated;
this.authKey = this.selectedService.authKey ?? '';
}, },
methods: { methods: {
createUserErrorMessage(errors) { createUserErrorMessage(errors = { error: [''] }) {
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
this.serverError = Object.values(errors)[0][0]; this.serverError = errors.error[0];
}, },
setOpsgenieAsDefault() { setOpsgenieAsDefault() {
this.options = this.options.map(el => { this.options = this.options.map(el => {
@ -224,41 +200,38 @@ export default {
resetFormValues() { resetFormValues() {
this.testAlert.json = null; this.testAlert.json = null;
this.targetUrl = this.selectedService.targetUrl; this.targetUrl = this.selectedService.targetUrl;
this.active = this.selectedService.activated;
}, },
dismissFeedback() { dismissFeedback() {
this.serverError = null; this.serverError = null;
this.feedback = { ...this.feedback, feedbackMessage: null }; this.feedback = { ...this.feedback, feedbackMessage: null };
this.isFeedbackDismissed = false; this.isFeedbackDismissed = false;
}, },
resetGenericKey() { resetKey(key) {
return service const fn = key === 'prometheus' ? this.resetPrometheusKey() : this.resetGenericKey();
.updateGenericKey({ endpoint: this.generic.formPath, params: { service: { token: '' } } })
return fn
.then(({ data: { token } }) => { .then(({ data: { token } }) => {
this.authorizationKey.generic = token; this.authKey = token;
this.setFeedback({ feedbackMessage: this.$options.i18n.authKeyRest, variant: 'success' }); this.setFeedback({ feedbackMessage: this.$options.i18n.authKeyRest, variant: 'success' });
}) })
.catch(() => { .catch(() => {
this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' }); this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' });
}); });
}, },
resetGenericKey() {
this.dismissFeedback();
return service.updateGenericKey({
endpoint: this.generic.formPath,
params: { service: { token: '' } },
});
},
resetPrometheusKey() { resetPrometheusKey() {
return service return service.updatePrometheusKey({ endpoint: this.prometheus.prometheusResetKeyPath });
.updatePrometheusKey({ endpoint: this.prometheus.prometheusResetKeyPath })
.then(({ data: { token } }) => {
this.authorizationKey.prometheus = token;
this.setFeedback({ feedbackMessage: this.$options.i18n.authKeyRest, variant: 'success' });
})
.catch(() => {
this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' });
});
}, },
toggleService(value) { toggleService(value) {
this.canSaveForm = true; this.canSaveForm = true;
if (this.isPrometheus) { this.active = value;
this.activated.prometheus = value;
} else {
this.activated[this.selectedEndpoint] = value;
}
}, },
toggle(value) { toggle(value) {
return this.isPrometheus ? this.togglePrometheusActive(value) : this.toggleActivated(value); return this.isPrometheus ? this.togglePrometheusActive(value) : this.toggleActivated(value);
@ -273,7 +246,7 @@ export default {
: { service: { active: value } }, : { service: { active: value } },
}) })
.then(() => { .then(() => {
this.activated[this.selectedEndpoint] = value; this.active = value;
this.toggleSuccess(value); this.toggleSuccess(value);
if (!this.isOpsgenie && value) { if (!this.isOpsgenie && value) {
@ -316,7 +289,7 @@ export default {
}, },
}) })
.then(() => { .then(() => {
this.activated.prometheus = value; this.active = value;
this.toggleSuccess(value); this.toggleSuccess(value);
this.removeOpsGenieOption(); this.removeOpsGenieOption();
}) })
@ -358,6 +331,7 @@ export default {
}, },
validateTestAlert() { validateTestAlert() {
this.loading = true; this.loading = true;
this.dismissFeedback();
this.validateJson(); this.validateJson();
return service return service
.updateTestAlert({ .updateTestAlert({
@ -382,7 +356,8 @@ export default {
}); });
}, },
onSubmit() { onSubmit() {
this.toggle(this.selectedService.active); this.dismissFeedback();
this.toggle(this.active);
}, },
onReset() { onReset() {
this.testAlert.json = null; this.testAlert.json = null;
@ -391,7 +366,7 @@ export default {
if (this.canSaveForm) { if (this.canSaveForm) {
this.canSaveForm = false; this.canSaveForm = false;
this.activated[this.selectedEndpoint] = this[this.selectedEndpoint].activated; this.active = this.selectedService.activated;
} }
}, },
}, },
@ -409,7 +384,7 @@ export default {
variant="danger" variant="danger"
category="primary" category="primary"
class="gl-display-block gl-mt-3" class="gl-display-block gl-mt-3"
@click="toggle(selectedService.active)" @click="toggle(active)"
> >
{{ __('Save anyway') }} {{ __('Save anyway') }}
</gl-button> </gl-button>
@ -435,7 +410,7 @@ export default {
data-testid="alert-settings-select" data-testid="alert-settings-select"
@change="resetFormValues" @change="resetFormValues"
/> />
<span class="gl-text-gray-400"> <span class="gl-text-gray-200">
<gl-sprintf :message="$options.i18n.integrationsInfo"> <gl-sprintf :message="$options.i18n.integrationsInfo">
<template #link="{ content }"> <template #link="{ content }">
<gl-link <gl-link
@ -457,7 +432,7 @@ export default {
id="activated" id="activated"
:disabled-input="loading" :disabled-input="loading"
:is-loading="loading" :is-loading="loading"
:value="selectedService.active" :value="active"
@change="toggleService" @change="toggleService"
/> />
</gl-form-group> </gl-form-group>
@ -472,9 +447,9 @@ export default {
v-model="targetUrl" v-model="targetUrl"
type="url" type="url"
:placeholder="baseUrlPlaceholder" :placeholder="baseUrlPlaceholder"
:disabled="!selectedService.active" :disabled="!active"
/> />
<span class="gl-text-gray-400"> <span class="gl-text-gray-200">
{{ $options.i18n.apiBaseUrlHelpText }} {{ $options.i18n.apiBaseUrlHelpText }}
</span> </span>
</gl-form-group> </gl-form-group>
@ -489,7 +464,7 @@ export default {
/> />
</template> </template>
</gl-form-input-group> </gl-form-input-group>
<span class="gl-text-gray-400"> <span class="gl-text-gray-200">
{{ prometheusInfo }} {{ prometheusInfo }}
</span> </span>
</gl-form-group> </gl-form-group>
@ -498,21 +473,16 @@ export default {
label-for="authorization-key" label-for="authorization-key"
label-class="label-bold" label-class="label-bold"
> >
<gl-form-input-group <gl-form-input-group id="authorization-key" class="gl-mb-2" readonly :value="authKey">
id="authorization-key"
class="gl-mb-2"
readonly
:value="selectedService.authKey"
>
<template #append> <template #append>
<clipboard-button <clipboard-button
:text="selectedService.authKey || ''" :text="authKey"
:title="$options.i18n.copyToClipboard" :title="$options.i18n.copyToClipboard"
class="gl-m-0!" class="gl-m-0!"
/> />
</template> </template>
</gl-form-input-group> </gl-form-input-group>
<gl-button v-gl-modal.authKeyModal :disabled="!selectedService.active" class="gl-mt-3">{{ <gl-button v-gl-modal.authKeyModal :disabled="!active" class="gl-mt-3">{{
$options.i18n.resetKey $options.i18n.resetKey
}}</gl-button> }}</gl-button>
<gl-modal <gl-modal
@ -534,18 +504,23 @@ export default {
<gl-form-textarea <gl-form-textarea
id="alert-json" id="alert-json"
v-model.trim="testAlert.json" v-model.trim="testAlert.json"
:disabled="!selectedService.active" :disabled="!active"
:state="jsonIsValid" :state="jsonIsValid"
:placeholder="$options.i18n.alertJsonPlaceholder" :placeholder="$options.i18n.alertJsonPlaceholder"
rows="6" rows="6"
max-rows="10" max-rows="10"
/> />
</gl-form-group> </gl-form-group>
<gl-button :disabled="!canTestAlert" @click="validateTestAlert">{{ <div class="gl-display-flex gl-justify-content-end">
$options.i18n.testAlertInfo <gl-button :disabled="!canTestAlert" @click="validateTestAlert">{{
}}</gl-button> $options.i18n.testAlertInfo
}}</gl-button>
</div>
</template> </template>
<div class="footer-block row-content-block gl-display-flex gl-justify-content-space-between"> <div class="footer-block row-content-block gl-display-flex gl-justify-content-space-between">
<gl-button category="primary" :disabled="!canSaveConfig" @click="onReset">
{{ __('Cancel') }}
</gl-button>
<gl-button <gl-button
variant="success" variant="success"
category="primary" category="primary"
@ -554,9 +529,6 @@ export default {
> >
{{ __('Save changes') }} {{ __('Save changes') }}
</gl-button> </gl-button>
<gl-button variant="default" category="primary" :disabled="!canSaveConfig" @click="onReset">
{{ __('Cancel') }}
</gl-button>
</div> </div>
</gl-form> </gl-form>
</div> </div>

View file

@ -35,7 +35,9 @@ export const i18n = {
testAlertSuccess: s__( testAlertSuccess: s__(
'AlertSettings|Test alert sent successfully. If you have made other changes, please save them now.', 'AlertSettings|Test alert sent successfully. If you have made other changes, please save them now.',
), ),
authKeyRest: s__('AlertSettings|Authorization key has been successfully reset'), authKeyRest: s__(
'AlertSettings|Authorization key has been successfully reset. Please save your changes now.',
),
}; };
export const serviceOptions = [ export const serviceOptions = [

View file

@ -31,37 +31,37 @@ export default el => {
const opsgenieMvcActivated = parseBoolean(opsgenieMvcEnabled); const opsgenieMvcActivated = parseBoolean(opsgenieMvcEnabled);
const opsgenieMvcIsAvailable = parseBoolean(opsgenieMvcAvailable); const opsgenieMvcIsAvailable = parseBoolean(opsgenieMvcAvailable);
const props = {
prometheus: {
activated: prometheusIsActivated,
prometheusUrl,
prometheusAuthorizationKey,
prometheusFormPath,
prometheusResetKeyPath,
prometheusApiUrl,
},
generic: {
alertsSetupUrl,
alertsUsageUrl,
activated: genericActivated,
formPath,
initialAuthorizationKey: authorizationKey,
url,
},
opsgenie: {
formPath: opsgenieMvcFormPath,
activated: opsgenieMvcActivated,
opsgenieMvcTargetUrl,
opsgenieMvcIsAvailable,
},
};
return new Vue({ return new Vue({
el, el,
provide: {
prometheus: {
activated: prometheusIsActivated,
prometheusUrl,
authorizationKey: prometheusAuthorizationKey,
prometheusFormPath,
prometheusResetKeyPath,
prometheusApiUrl,
},
generic: {
alertsSetupUrl,
alertsUsageUrl,
activated: genericActivated,
formPath,
authorizationKey,
url,
},
opsgenie: {
formPath: opsgenieMvcFormPath,
activated: opsgenieMvcActivated,
opsgenieMvcTargetUrl,
opsgenieMvcIsAvailable,
},
},
components: {
AlertSettingsForm,
},
render(createElement) { render(createElement) {
return createElement(AlertSettingsForm, { return createElement('alert-settings-form');
props,
});
}, },
}); });
}; };

View file

@ -0,0 +1,28 @@
import Vue from 'vue';
import ActivityChart from './components/activity_chart.vue';
export default () => {
const containers = document.querySelectorAll('.js-project-analytics-chart');
if (!containers) {
return false;
}
return containers.forEach(container => {
const { chartData } = container.dataset;
const formattedData = JSON.parse(chartData);
return new Vue({
el: container,
provide: {
formattedData,
},
components: {
ActivityChart,
},
render(createElement) {
return createElement('activity-chart');
},
});
});
};

View file

@ -0,0 +1,42 @@
<script>
import { GlColumnChart } from '@gitlab/ui/dist/charts';
import { s__ } from '~/locale';
export default {
i18n: {
noDataMsg: s__(
'ProductAnalytics|There is no data for this type of chart currently. Please see the Setup tab if you have not configured the product analytics tool already.',
),
},
components: {
GlColumnChart,
},
inject: {
formattedData: {
default: {},
},
},
computed: {
seriesData() {
return {
full: this.formattedData.keys.map((val, idx) => [val, this.formattedData.values[idx]]),
};
},
},
};
</script>
<template>
<div class="gl-xs-w-full">
<gl-column-chart
v-if="formattedData.keys"
:data="seriesData"
:x-axis-title="__('Value')"
:y-axis-title="__('Number of events')"
:x-axis-type="'category'"
/>
<p v-else data-testid="noActivityChartData">
{{ $options.i18n.noDataMsg }}
</p>
</div>
</template>

View file

@ -1,6 +1,6 @@
import axios from './lib/utils/axios_utils'; import axios from './lib/utils/axios_utils';
import { joinPaths } from './lib/utils/url_utility'; import { joinPaths } from './lib/utils/url_utility';
import flash from '~/flash'; import { deprecatedCreateFlash as flash } from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
const DEFAULT_PER_PAGE = 20; const DEFAULT_PER_PAGE = 20;
@ -9,6 +9,7 @@ const Api = {
groupsPath: '/api/:version/groups.json', groupsPath: '/api/:version/groups.json',
groupPath: '/api/:version/groups/:id', groupPath: '/api/:version/groups/:id',
groupMembersPath: '/api/:version/groups/:id/members', groupMembersPath: '/api/:version/groups/:id/members',
groupMilestonesPath: '/api/:version/groups/:id/milestones',
subgroupsPath: '/api/:version/groups/:id/subgroups', subgroupsPath: '/api/:version/groups/:id/subgroups',
namespacesPath: '/api/:version/namespaces.json', namespacesPath: '/api/:version/namespaces.json',
groupPackagesPath: '/api/:version/groups/:id/packages', groupPackagesPath: '/api/:version/groups/:id/packages',
@ -55,10 +56,14 @@ const Api = {
adminStatisticsPath: '/api/:version/application/statistics', adminStatisticsPath: '/api/:version/application/statistics',
pipelineSinglePath: '/api/:version/projects/:id/pipelines/:pipeline_id', pipelineSinglePath: '/api/:version/projects/:id/pipelines/:pipeline_id',
pipelinesPath: '/api/:version/projects/:id/pipelines/', pipelinesPath: '/api/:version/projects/:id/pipelines/',
createPipelinePath: '/api/:version/projects/:id/pipeline',
environmentsPath: '/api/:version/projects/:id/environments', environmentsPath: '/api/:version/projects/:id/environments',
contextCommitsPath:
'/api/:version/projects/:id/merge_requests/:merge_request_iid/context_commits',
rawFilePath: '/api/:version/projects/:id/repository/files/:path/raw', rawFilePath: '/api/:version/projects/:id/repository/files/:path/raw',
issuePath: '/api/:version/projects/:id/issues/:issue_iid', issuePath: '/api/:version/projects/:id/issues/:issue_iid',
tagsPath: '/api/:version/projects/:id/repository/tags', tagsPath: '/api/:version/projects/:id/repository/tags',
freezePeriodsPath: '/api/:version/projects/:id/freeze_periods',
group(groupId, callback = () => {}) { group(groupId, callback = () => {}) {
const url = Api.buildUrl(Api.groupPath).replace(':id', groupId); const url = Api.buildUrl(Api.groupPath).replace(':id', groupId);
@ -106,6 +111,17 @@ const Api = {
}); });
}, },
groupMilestones(id, options) {
const url = Api.buildUrl(this.groupMilestonesPath).replace(':id', encodeURIComponent(id));
return axios.get(url, {
params: {
per_page: DEFAULT_PER_PAGE,
...options,
},
});
},
// Return groups list. Filtered by query // Return groups list. Filtered by query
groups(query, options, callback = () => {}) { groups(query, options, callback = () => {}) {
const url = Api.buildUrl(Api.groupsPath); const url = Api.buildUrl(Api.groupsPath);
@ -528,6 +544,12 @@ const Api = {
return axios.get(url); return axios.get(url);
}, },
createRelease(projectPath, release) {
const url = Api.buildUrl(this.releasesPath).replace(':id', encodeURIComponent(projectPath));
return axios.post(url, release);
},
updateRelease(projectPath, tagName, release) { updateRelease(projectPath, tagName, release) {
const url = Api.buildUrl(this.releasePath) const url = Api.buildUrl(this.releasePath)
.replace(':id', encodeURIComponent(projectPath)) .replace(':id', encodeURIComponent(projectPath))
@ -575,11 +597,45 @@ const Api = {
}); });
}, },
createPipeline(id, data) {
const url = Api.buildUrl(this.createPipelinePath).replace(':id', encodeURIComponent(id));
return axios.post(url, data, {
headers: {
'Content-Type': 'application/json',
},
});
},
environments(id) { environments(id) {
const url = Api.buildUrl(this.environmentsPath).replace(':id', encodeURIComponent(id)); const url = Api.buildUrl(this.environmentsPath).replace(':id', encodeURIComponent(id));
return axios.get(url); return axios.get(url);
}, },
createContextCommits(id, mergeRequestIid, data) {
const url = Api.buildUrl(this.contextCommitsPath)
.replace(':id', encodeURIComponent(id))
.replace(':merge_request_iid', mergeRequestIid);
return axios.post(url, data);
},
allContextCommits(id, mergeRequestIid) {
const url = Api.buildUrl(this.contextCommitsPath)
.replace(':id', encodeURIComponent(id))
.replace(':merge_request_iid', mergeRequestIid);
return axios.get(url);
},
removeContextCommits(id, mergeRequestIid, data) {
const url = Api.buildUrl(this.contextCommitsPath)
.replace(':id', id)
.replace(':merge_request_iid', mergeRequestIid);
return axios.delete(url, { data });
},
getRawFile(id, path, params = { ref: 'master' }) { getRawFile(id, path, params = { ref: 'master' }) {
const url = Api.buildUrl(this.rawFilePath) const url = Api.buildUrl(this.rawFilePath)
.replace(':id', encodeURIComponent(id)) .replace(':id', encodeURIComponent(id))
@ -616,6 +672,18 @@ const Api = {
}); });
}, },
freezePeriods(id) {
const url = Api.buildUrl(this.freezePeriodsPath).replace(':id', encodeURIComponent(id));
return axios.get(url);
},
createFreezePeriod(id, freezePeriod = {}) {
const url = Api.buildUrl(this.freezePeriodsPath).replace(':id', encodeURIComponent(id));
return axios.post(url, freezePeriod);
},
buildUrl(url) { buildUrl(url) {
return joinPaths(gon.relative_url_root || '', url.replace(':version', gon.api_version)); return joinPaths(gon.relative_url_root || '', url.replace(':version', gon.api_version));
}, },

View file

@ -7,7 +7,7 @@ import Cookies from 'js-cookie';
import { __ } from './locale'; import { __ } from './locale';
import { updateTooltipTitle } from './lib/utils/common_utils'; import { updateTooltipTitle } from './lib/utils/common_utils';
import { isInVueNoteablePage } from './lib/utils/dom_utils'; import { isInVueNoteablePage } from './lib/utils/dom_utils';
import flash from './flash'; import { deprecatedCreateFlash as flash } from './flash';
import axios from './lib/utils/axios_utils'; import axios from './lib/utils/axios_utils';
import * as Emoji from '~/emoji'; import * as Emoji from '~/emoji';

View file

@ -2,7 +2,7 @@
import { escape, debounce } from 'lodash'; import { escape, debounce } from 'lodash';
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import { GlLoadingIcon, GlFormInput, GlFormGroup } from '@gitlab/ui'; import { GlLoadingIcon, GlFormInput, GlFormGroup } from '@gitlab/ui';
import createFlash from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import LoadingButton from '~/vue_shared/components/loading_button.vue'; import LoadingButton from '~/vue_shared/components/loading_button.vue';
import createEmptyBadge from '../empty_badge'; import createEmptyBadge from '../empty_badge';
@ -184,7 +184,7 @@ export default {
@input="debouncedPreview" @input="debouncedPreview"
/> />
<div class="invalid-feedback">{{ s__('Badges|Please fill in a valid URL') }}</div> <div class="invalid-feedback">{{ s__('Badges|Please fill in a valid URL') }}</div>
<span class="form-text text-muted"> {{ badgeLinkUrlExample }} </span> <span class="form-text text-muted">{{ badgeLinkUrlExample }}</span>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -199,7 +199,7 @@ export default {
@input="debouncedPreview" @input="debouncedPreview"
/> />
<div class="invalid-feedback">{{ s__('Badges|Please fill in a valid URL') }}</div> <div class="invalid-feedback">{{ s__('Badges|Please fill in a valid URL') }}</div>
<span class="form-text text-muted"> {{ badgeImageUrlExample }} </span> <span class="form-text text-muted">{{ badgeImageUrlExample }}</span>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -210,22 +210,26 @@ export default {
:image-url="renderedImageUrl" :image-url="renderedImageUrl"
:link-url="renderedLinkUrl" :link-url="renderedLinkUrl"
/> />
<p v-show="isRendering"><gl-loading-icon :inline="true" /></p> <p v-show="isRendering">
<gl-loading-icon :inline="true" />
</p>
<p v-show="!renderedBadge && !isRendering" class="disabled-content"> <p v-show="!renderedBadge && !isRendering" class="disabled-content">
{{ s__('Badges|No image to preview') }} {{ s__('Badges|No image to preview') }}
</p> </p>
</div> </div>
<div v-if="isEditing" class="row-content-block"> <div v-if="isEditing" class="row-content-block gl-display-flex gl-justify-content-end">
<button class="btn btn-cancel gl-mr-4" type="button" @click="onCancel">
{{ __('Cancel') }}
</button>
<loading-button <loading-button
:loading="isSaving" :loading="isSaving"
:label="s__('Badges|Save changes')" :label="s__('Badges|Save changes')"
type="submit" type="submit"
container-class="btn btn-success" container-class="btn btn-success"
/> />
<button class="btn btn-cancel" type="button" @click="onCancel">{{ __('Cancel') }}</button>
</div> </div>
<div v-else class="form-group"> <div v-else class="gl-display-flex gl-justify-content-end form-group">
<loading-button <loading-button
:loading="isSaving" :loading="isSaving"
:label="s__('Badges|Add badge')" :label="s__('Badges|Add badge')"

View file

@ -1,6 +1,7 @@
<script> <script>
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions } from 'vuex';
import createFlash from '~/flash'; import { GlSprintf } from '@gitlab/ui';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue'; import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import Badge from './badge.vue'; import Badge from './badge.vue';
@ -14,14 +15,15 @@ export default {
BadgeForm, BadgeForm,
BadgeList, BadgeList,
GlModal: DeprecatedModal2, GlModal: DeprecatedModal2,
GlSprintf,
},
i18n: {
deleteModalText: s__(
'Badges|You are going to delete this badge. Deleted badges %{strongStart}cannot%{strongEnd} be restored.',
),
}, },
computed: { computed: {
...mapState(['badgeInModal', 'isEditing']), ...mapState(['badgeInModal', 'isEditing']),
deleteModalText() {
return s__(
'Badges|You are going to delete this badge. Deleted badges <strong>cannot</strong> be restored.',
);
},
}, },
methods: { methods: {
...mapActions(['deleteBadge']), ...mapActions(['deleteBadge']),
@ -54,7 +56,13 @@ export default {
:link-url="badgeInModal ? badgeInModal.renderedLinkUrl : ''" :link-url="badgeInModal ? badgeInModal.renderedLinkUrl : ''"
/> />
</div> </div>
<p v-html="deleteModalText"></p> <p>
<gl-sprintf :message="$options.i18n.deleteModalText">
<template #strong="{ content }">
<strong>{{ content }}</strong>
</template>
</gl-sprintf>
</p>
</gl-modal> </gl-modal>
<badge-form v-show="isEditing" :is-editing="true" /> <badge-form v-show="isEditing" :is-editing="true" />

View file

@ -1,15 +1,17 @@
<script> <script>
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import { GlButton } from '@gitlab/ui';
import NoteableNote from '~/notes/components/noteable_note.vue'; import NoteableNote from '~/notes/components/noteable_note.vue';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import PublishButton from './publish_button.vue'; import PublishButton from './publish_button.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default { export default {
components: { components: {
NoteableNote, NoteableNote,
PublishButton, PublishButton,
LoadingButton, GlButton,
}, },
mixins: [glFeatureFlagsMixin()],
props: { props: {
draft: { draft: {
type: Object, type: Object,
@ -64,14 +66,27 @@ export default {
handleNotEditing() { handleNotEditing() {
this.isEditingDraft = false; this.isEditingDraft = false;
}, },
handleMouseEnter(draft) {
if (this.glFeatures.multilineComments && draft.position) {
this.setSelectedCommentPositionHover(draft.position.line_range);
}
},
handleMouseLeave(draft) {
// Even though position isn't used here we still don't want to unecessarily call a mutation
// The lack of position tells us that highlighting is irrelevant in this context
if (this.glFeatures.multilineComments && draft.position) {
this.setSelectedCommentPositionHover();
}
},
}, },
}; };
</script> </script>
<template> <template>
<article <article
role="article"
class="draft-note-component note-wrapper" class="draft-note-component note-wrapper"
@mouseenter="setSelectedCommentPositionHover(draft.position.line_range)" @mouseenter="handleMouseEnter(draft)"
@mouseleave="setSelectedCommentPositionHover()" @mouseleave="handleMouseLeave(draft)"
> >
<ul class="notes draft-notes"> <ul class="notes draft-notes">
<noteable-note <noteable-note
@ -100,18 +115,15 @@ export default {
></div> ></div>
<p class="draft-note-actions d-flex"> <p class="draft-note-actions d-flex">
<publish-button <publish-button :show-count="true" :should-publish="false" category="secondary" />
:show-count="true" <gl-button
:should-publish="false"
class="btn btn-success btn-inverted gl-mr-3"
/>
<loading-button
ref="publishNowButton" ref="publishNowButton"
:loading="isPublishingDraft(draft.id) || isPublishing" :loading="isPublishingDraft(draft.id) || isPublishing"
:label="__('Add comment now')" class="gl-ml-3"
container-class="btn btn-inverted"
@click="publishNow" @click="publishNow"
/> >
{{ __('Add comment now') }}
</gl-button>
</p> </p>
</template> </template>
</article> </article>

View file

@ -1,15 +1,19 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { GlBadge } from '@gitlab/ui';
export default { export default {
components: {
GlBadge,
},
computed: { computed: {
...mapGetters('batchComments', ['draftsCount']), ...mapGetters('batchComments', ['draftsCount']),
}, },
}; };
</script> </script>
<template> <template>
<span class="drafts-count-component"> <gl-badge size="sm" variant="success">
<span class="drafts-count-number">{{ draftsCount }}</span> {{ draftsCount }}
<span class="sr-only"> {{ n__('draft', 'drafts', draftsCount) }} </span> <span class="sr-only"> {{ n__('draft', 'drafts', draftsCount) }} </span>
</span> </gl-badge>
</template> </template>

View file

@ -1,10 +1,10 @@
<script> <script>
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import { GlSprintf } from '@gitlab/ui';
import { IMAGE_DIFF_POSITION_TYPE } from '~/diffs/constants'; import { IMAGE_DIFF_POSITION_TYPE } from '~/diffs/constants';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import resolvedStatusMixin from '../mixins/resolved_status'; import resolvedStatusMixin from '../mixins/resolved_status';
import { GlSprintf } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { import {
getStartLineNumber, getStartLineNumber,

View file

@ -1,12 +1,12 @@
<script> <script>
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import { GlButton } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import DraftsCount from './drafts_count.vue'; import DraftsCount from './drafts_count.vue';
export default { export default {
components: { components: {
LoadingButton, GlButton,
DraftsCount, DraftsCount,
}, },
props: { props: {
@ -20,6 +20,16 @@ export default {
required: false, required: false,
default: __('Finish review'), default: __('Finish review'),
}, },
category: {
type: String,
required: false,
default: 'primary',
},
variant: {
type: String,
required: false,
default: 'success',
},
shouldPublish: { shouldPublish: {
type: Boolean, type: Boolean,
required: true, required: true,
@ -42,14 +52,14 @@ export default {
</script> </script>
<template> <template>
<loading-button <gl-button
:loading="isPublishing" :loading="isPublishing"
container-class="btn btn-success js-publish-draft-button qa-submit-review" class="js-publish-draft-button qa-submit-review"
:category="category"
:variant="variant"
@click="onClick" @click="onClick"
> >
<span> {{ label }}
{{ label }} <drafts-count v-if="showCount" />
<drafts-count v-if="showCount" /> </gl-button>
</span>
</loading-button>
</template> </template>

View file

@ -1,13 +1,12 @@
<script> <script>
import { mapActions, mapState, mapGetters } from 'vuex'; import { mapActions, mapState, mapGetters } from 'vuex';
import { GlModal, GlModalDirective } from '@gitlab/ui'; import { GlModal, GlModalDirective, GlButton } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale'; import { sprintf, s__ } from '~/locale';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import PreviewDropdown from './preview_dropdown.vue'; import PreviewDropdown from './preview_dropdown.vue';
export default { export default {
components: { components: {
LoadingButton, GlButton,
GlModal, GlModal,
PreviewDropdown, PreviewDropdown,
}, },
@ -48,12 +47,13 @@ export default {
<nav class="review-bar-component"> <nav class="review-bar-component">
<div class="review-bar-content qa-review-bar"> <div class="review-bar-content qa-review-bar">
<preview-dropdown /> <preview-dropdown />
<loading-button <gl-button
v-gl-modal="$options.modalId" v-gl-modal="$options.modalId"
:loading="isDiscarding" :loading="isDiscarding"
:label="__('Discard review')"
class="qa-discard-review float-right" class="qa-discard-review float-right"
/> >
{{ __('Discard review') }}
</gl-button>
</div> </div>
</nav> </nav>
<gl-modal <gl-modal

View file

@ -1,4 +1,4 @@
import flash from '~/flash'; import { deprecatedCreateFlash as flash } from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { scrollToElement } from '~/lib/utils/common_utils'; import { scrollToElement } from '~/lib/utils/common_utils';
import service from '../../../services/drafts_service'; import service from '../../../services/drafts_service';
@ -146,6 +146,3 @@ export const expandAllDiscussions = ({ dispatch, state }) =>
export const toggleResolveDiscussion = ({ commit }, draftId) => { export const toggleResolveDiscussion = ({ commit }, draftId) => {
commit(types.TOGGLE_RESOLVE_DISCUSSION, draftId); commit(types.TOGGLE_RESOLVE_DISCUSSION, draftId);
}; };
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};

View file

@ -82,6 +82,3 @@ export const isPublishingDraft = state => draftId =>
state.currentlyPublishingDrafts.indexOf(draftId) !== -1; state.currentlyPublishingDrafts.indexOf(draftId) !== -1;
export const sortedDrafts = state => [...state.drafts].sort((a, b) => a.id > b.id); export const sortedDrafts = state => [...state.drafts].sort((a, b) => a.id > b.id);
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};

View file

@ -180,6 +180,10 @@ export class CopyAsGFM {
}) })
.catch(() => {}); .catch(() => {});
} }
static quoted(markdown) {
return `> ${markdown.split('\n').join('\n> ')}`;
}
} }
// Export CopyAsGFM as a global for rspec to access // Export CopyAsGFM as a global for rspec to access

View file

@ -1,4 +1,4 @@
import flash from '~/flash'; import { deprecatedCreateFlash as flash } from '~/flash';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
// Renders math using KaTeX in any element with the // Renders math using KaTeX in any element with the

View file

@ -1,7 +1,7 @@
import flash from '~/flash';
import $ from 'jquery'; import $ from 'jquery';
import { __, sprintf } from '~/locale';
import { once } from 'lodash'; import { once } from 'lodash';
import { deprecatedCreateFlash as flash } from '~/flash';
import { __, sprintf } from '~/locale';
// Renders diagrams and flowcharts from text using Mermaid in any element with the // Renders diagrams and flowcharts from text using Mermaid in any element with the
// `js-render-mermaid` class. // `js-render-mermaid` class.

View file

@ -2,7 +2,7 @@
import $ from 'jquery'; import $ from 'jquery';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import flash from '~/flash'; import { deprecatedCreateFlash as flash } from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
// MarkdownPreview // MarkdownPreview

View file

@ -72,7 +72,7 @@ $(document).on(
$this.tooltip({ $this.tooltip({
container: 'body', container: 'body',
html: 'true', html: true,
placement: 'top', placement: 'top',
title, title,
trigger: 'manual', trigger: 'manual',

View file

@ -1,4 +1,4 @@
import Flash from '../flash'; import { deprecatedCreateFlash as Flash } from '../flash';
import BalsamiqViewer from './balsamiq/balsamiq_viewer'; import BalsamiqViewer from './balsamiq/balsamiq_viewer';
import { __ } from '~/locale'; import { __ } from '~/locale';

View file

@ -1,6 +1,6 @@
<script> <script>
import { __ } from '~/locale';
import { GlSprintf, GlLink } from '@gitlab/ui'; import { GlSprintf, GlLink } from '@gitlab/ui';
import { __ } from '~/locale';
import { BLOB_RENDER_ERRORS } from './constants'; import { BLOB_RENDER_ERRORS } from './constants';
export default { export default {

View file

@ -1,6 +1,12 @@
<script> <script>
import { initEditorLite } from '~/blob/utils';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { initEditorLite } from '~/blob/utils';
import {
SNIPPET_MARK_BLOBS_CONTENT,
SNIPPET_MARK_EDIT_APP_START,
SNIPPET_MEASURE_BLOBS_CONTENT,
SNIPPET_MEASURE_BLOBS_CONTENT_WITHIN_APP,
} from '~/performance_constants';
export default { export default {
props: { props: {
@ -14,6 +20,13 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
// This is used to help uniquely create a monaco model
// even if two blob's share a file path.
fileGlobalId: {
type: String,
required: false,
default: '',
},
}, },
data() { data() {
return { return {
@ -30,17 +43,33 @@ export default {
el: this.$refs.editor, el: this.$refs.editor,
blobPath: this.fileName, blobPath: this.fileName,
blobContent: this.value, blobContent: this.value,
blobGlobalId: this.fileGlobalId,
});
this.editor.onChangeContent(debounce(this.onFileChange.bind(this), 250));
window.requestAnimationFrame(() => {
if (!performance.getEntriesByName(SNIPPET_MARK_BLOBS_CONTENT).length) {
performance.mark(SNIPPET_MARK_BLOBS_CONTENT);
performance.measure(SNIPPET_MEASURE_BLOBS_CONTENT);
performance.measure(SNIPPET_MEASURE_BLOBS_CONTENT_WITHIN_APP, SNIPPET_MARK_EDIT_APP_START);
}
}); });
}, },
beforeDestroy() {
this.editor.dispose();
},
methods: { methods: {
triggerFileChange: debounce(function debouncedFileChange() { onFileChange() {
this.$emit('input', this.editor.getValue()); this.$emit('input', this.editor.getValue());
}, 250), },
}, },
}; };
</script> </script>
<template> <template>
<div class="file-content code"> <div class="file-content code">
<pre id="editor" ref="editor" data-editor-loading @keyup="triggerFileChange">{{ value }}</pre> <div id="editor" ref="editor" data-editor-loading>
<pre class="editor-loading-content">{{ value }}</pre>
</div>
</div> </div>
</template> </template>

View file

@ -1,9 +1,10 @@
<script> <script>
import { GlFormInput } from '@gitlab/ui'; import { GlFormInput, GlButton } from '@gitlab/ui';
export default { export default {
components: { components: {
GlFormInput, GlFormInput,
GlButton,
}, },
inheritAttrs: false, inheritAttrs: false,
props: { props: {
@ -11,6 +12,16 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
canDelete: {
type: Boolean,
required: false,
default: true,
},
showDelete: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
@ -21,17 +32,27 @@ export default {
</script> </script>
<template> <template>
<div class="js-file-title file-title-flex-parent"> <div class="js-file-title file-title-flex-parent">
<gl-form-input <div class="gl-display-flex gl-align-items-center gl-w-full">
id="snippet_file_name" <gl-form-input
v-model="name" v-model="name"
:placeholder=" :placeholder="
s__('Snippets|Give your file a name to add code highlighting, e.g. example.rb for Ruby') s__('Snippets|Give your file a name to add code highlighting, e.g. example.rb for Ruby')
" "
name="snippet_file_name" name="snippet_file_name"
class="form-control js-snippet-file-name" class="form-control js-snippet-file-name"
type="text" type="text"
v-bind="$attrs" v-bind="$attrs"
@change="$emit('input', name)" @change="$emit('input', name)"
/> />
<gl-button
v-if="showDelete"
class="gl-ml-4"
variant="danger"
category="secondary"
:disabled="!canDelete"
@click="$emit('delete')"
>{{ s__('Snippets|Delete file') }}</gl-button
>
</div>
</div> </div>
</template> </template>

View file

@ -71,7 +71,7 @@ export default {
</template> </template>
</blob-filepath> </blob-filepath>
<div class="file-actions d-none d-sm-flex"> <div class="gl-display-none gl-display-sm-flex">
<viewer-switcher v-if="showViewerSwitcher" v-model="viewer" /> <viewer-switcher v-if="showViewerSwitcher" v-model="viewer" />
<slot name="actions"></slot> <slot name="actions"></slot>

View file

@ -1,5 +1,5 @@
<script> <script>
import { GlDeprecatedButton, GlButtonGroup, GlIcon, GlTooltipDirective } from '@gitlab/ui'; import { GlButton, GlButtonGroup, GlTooltipDirective } from '@gitlab/ui';
import { import {
BTN_COPY_CONTENTS_TITLE, BTN_COPY_CONTENTS_TITLE,
BTN_DOWNLOAD_TITLE, BTN_DOWNLOAD_TITLE,
@ -10,9 +10,8 @@ import {
export default { export default {
components: { components: {
GlIcon,
GlButtonGroup, GlButtonGroup,
GlDeprecatedButton, GlButton,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
@ -48,7 +47,7 @@ export default {
</script> </script>
<template> <template>
<gl-button-group> <gl-button-group>
<gl-deprecated-button <gl-button
v-if="!hasRenderError" v-if="!hasRenderError"
v-gl-tooltip.hover v-gl-tooltip.hover
:aria-label="$options.BTN_COPY_CONTENTS_TITLE" :aria-label="$options.BTN_COPY_CONTENTS_TITLE"
@ -56,26 +55,29 @@ export default {
:disabled="copyDisabled" :disabled="copyDisabled"
data-clipboard-target="#blob-code-content" data-clipboard-target="#blob-code-content"
data-testid="copyContentsButton" data-testid="copyContentsButton"
> icon="copy-to-clipboard"
<gl-icon name="copy-to-clipboard" :size="14" /> category="primary"
</gl-deprecated-button> variant="default"
<gl-deprecated-button />
<gl-button
v-gl-tooltip.hover v-gl-tooltip.hover
:aria-label="$options.BTN_RAW_TITLE" :aria-label="$options.BTN_RAW_TITLE"
:title="$options.BTN_RAW_TITLE" :title="$options.BTN_RAW_TITLE"
:href="rawPath" :href="rawPath"
target="_blank" target="_blank"
> icon="doc-code"
<gl-icon name="doc-code" :size="14" /> category="primary"
</gl-deprecated-button> variant="default"
<gl-deprecated-button />
<gl-button
v-gl-tooltip.hover v-gl-tooltip.hover
:aria-label="$options.BTN_DOWNLOAD_TITLE" :aria-label="$options.BTN_DOWNLOAD_TITLE"
:title="$options.BTN_DOWNLOAD_TITLE" :title="$options.BTN_DOWNLOAD_TITLE"
:href="downloadUrl" :href="downloadUrl"
target="_blank" target="_blank"
> icon="download"
<gl-icon name="download" :size="14" /> category="primary"
</gl-deprecated-button> variant="default"
/>
</gl-button-group> </gl-button-group>
</template> </template>

View file

@ -1,5 +1,5 @@
<script> <script>
import { GlButton, GlButtonGroup, GlIcon, GlTooltipDirective } from '@gitlab/ui'; import { GlButton, GlButtonGroup, GlTooltipDirective } from '@gitlab/ui';
import { import {
RICH_BLOB_VIEWER, RICH_BLOB_VIEWER,
RICH_BLOB_VIEWER_TITLE, RICH_BLOB_VIEWER_TITLE,
@ -9,7 +9,6 @@ import {
export default { export default {
components: { components: {
GlIcon,
GlButtonGroup, GlButtonGroup,
GlButton, GlButton,
}, },
@ -52,19 +51,21 @@ export default {
:title="$options.SIMPLE_BLOB_VIEWER_TITLE" :title="$options.SIMPLE_BLOB_VIEWER_TITLE"
:selected="isSimpleViewer" :selected="isSimpleViewer"
:class="{ active: isSimpleViewer }" :class="{ active: isSimpleViewer }"
icon="code"
category="primary"
variant="default"
@click="switchToViewer($options.SIMPLE_BLOB_VIEWER)" @click="switchToViewer($options.SIMPLE_BLOB_VIEWER)"
> />
<gl-icon name="code" :size="14" />
</gl-button>
<gl-button <gl-button
v-gl-tooltip.hover v-gl-tooltip.hover
:aria-label="$options.RICH_BLOB_VIEWER_TITLE" :aria-label="$options.RICH_BLOB_VIEWER_TITLE"
:title="$options.RICH_BLOB_VIEWER_TITLE" :title="$options.RICH_BLOB_VIEWER_TITLE"
:selected="isRichViewer" :selected="isRichViewer"
:class="{ active: isRichViewer }" :class="{ active: isRichViewer }"
icon="document"
category="primary"
variant="default"
@click="switchToViewer($options.RICH_BLOB_VIEWER)" @click="switchToViewer($options.RICH_BLOB_VIEWER)"
> />
<gl-icon name="document" :size="14" />
</gl-button>
</gl-button-group> </gl-button-group>
</template> </template>

View file

@ -1,12 +1,13 @@
import $ from 'jquery'; import $ from 'jquery';
import Api from '~/api'; import Api from '~/api';
import Flash from '../flash'; import { deprecatedCreateFlash as Flash } from '../flash';
import FileTemplateTypeSelector from './template_selectors/type_selector'; import FileTemplateTypeSelector from './template_selectors/type_selector';
import BlobCiYamlSelector from './template_selectors/ci_yaml_selector'; import BlobCiYamlSelector from './template_selectors/ci_yaml_selector';
import DockerfileSelector from './template_selectors/dockerfile_selector'; import DockerfileSelector from './template_selectors/dockerfile_selector';
import GitignoreSelector from './template_selectors/gitignore_selector'; import GitignoreSelector from './template_selectors/gitignore_selector';
import LicenseSelector from './template_selectors/license_selector'; import LicenseSelector from './template_selectors/license_selector';
import MetricsDashboardSelector from './template_selectors/metrics_dashboard_selector';
import toast from '~/vue_shared/plugins/global_toast'; import toast from '~/vue_shared/plugins/global_toast';
import { __ } from '~/locale'; import { __ } from '~/locale';
import initPopover from '~/blob/suggest_gitlab_ci_yml'; import initPopover from '~/blob/suggest_gitlab_ci_yml';
@ -30,6 +31,7 @@ export default class FileTemplateMediator {
this.templateSelectors = [ this.templateSelectors = [
GitignoreSelector, GitignoreSelector,
BlobCiYamlSelector, BlobCiYamlSelector,
MetricsDashboardSelector,
DockerfileSelector, DockerfileSelector,
LicenseSelector, LicenseSelector,
].map(TemplateSelectorClass => new TemplateSelectorClass({ mediator: this })); ].map(TemplateSelectorClass => new TemplateSelectorClass({ mediator: this }));

View file

@ -1,7 +1,7 @@
<script> <script>
import { GlLoadingIcon } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import notebookLab from '~/notebook/index.vue'; import notebookLab from '~/notebook/index.vue';
import { GlLoadingIcon } from '@gitlab/ui';
export default { export default {
components: { components: {

View file

@ -1,5 +1,5 @@
import { SwaggerUIBundle } from 'swagger-ui-dist'; import { SwaggerUIBundle } from 'swagger-ui-dist';
import flash from '~/flash'; import { deprecatedCreateFlash as flash } from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
export default () => { export default () => {

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