New upstream version 13.2.1
This commit is contained in:
parent
036e5a5f03
commit
9c63f7bcc8
8181 changed files with 344178 additions and 71305 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -17,6 +17,7 @@ eslint-report.html
|
|||
.rbx/
|
||||
/.ruby-gemset
|
||||
/.ruby-version
|
||||
/.tool-versions
|
||||
/.rvmrc
|
||||
.sass-cache/
|
||||
/.secret
|
||||
|
|
|
@ -20,6 +20,8 @@ default:
|
|||
- gitlab-org
|
||||
# All jobs are interruptible by default
|
||||
interruptible: true
|
||||
# Default job timeout set to 90m https://gitlab.com/gitlab-com/gl-infra/infrastructure/-/issues/10520
|
||||
timeout: 90m
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
|
@ -61,6 +63,7 @@ variables:
|
|||
DOCKER_VERSION: "19.03.0"
|
||||
|
||||
include:
|
||||
- local: .gitlab/ci/build-images.gitlab-ci.yml
|
||||
- local: .gitlab/ci/cache-repo.gitlab-ci.yml
|
||||
- local: .gitlab/ci/cng.gitlab-ci.yml
|
||||
- local: .gitlab/ci/docs.gitlab-ci.yml
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
/doc/development/ @marcia @mjang1
|
||||
/doc/development/documentation/ @mikelewis
|
||||
/doc/ci @marcel.amirault @sselhorn
|
||||
/doc/operations @aqualls @eread
|
||||
/doc/user/clusters @aqualls
|
||||
/doc/user/infrastructure @aqualls
|
||||
/doc/user/project/clusters @aqualls
|
||||
|
@ -43,17 +44,12 @@
|
|||
# Feature specific owners
|
||||
/ee/lib/ee/gitlab/auth/ldap/ @dblessing @mkozono
|
||||
/lib/gitlab/auth/ldap/ @dblessing @mkozono
|
||||
/lib/gitlab/ci/templates/ @nolith @zj
|
||||
/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
|
||||
|
||||
# Code Owners
|
||||
#
|
||||
/ee/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
|
||||
/doc/user/project/code_owners.md @reprazent @kerrizor @garyh
|
||||
|
||||
# Quality owned files
|
||||
/qa/ @gl-quality
|
||||
|
||||
|
@ -77,3 +73,9 @@ Dangerfile @gl-quality/eng-prod
|
|||
/lib/gitlab/usage_data.rb @gitlab-org/growth/telemetry
|
||||
/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/telemetry
|
||||
/lib/gitlab/usage_data_counters/ @gitlab-org/growth/telemetry
|
||||
|
||||
[Code Owners]
|
||||
/ee/lib/gitlab/code_owners.rb @reprazent @kerrizor @garyh
|
||||
/ee/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
|
||||
|
|
31
.gitlab/ci/build-images.gitlab-ci.yml
Normal file
31
.gitlab/ci/build-images.gitlab-ci.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
# This image is used by the `review-qa-*` jobs. Not currently used by the `omnibus-gitlab` pipelines which rebuild this
|
||||
# image, e.g. https://gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/-/jobs/587107399, which we could probably avoid.
|
||||
# See https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5429.
|
||||
build-qa-image:
|
||||
extends:
|
||||
- .use-kaniko
|
||||
- .build-images:rules:build-qa-image
|
||||
stage: build-images
|
||||
needs: []
|
||||
script:
|
||||
- export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_REF_SLUG}"
|
||||
- /kaniko/executor --context=${CI_PROJECT_DIR} --dockerfile=${CI_PROJECT_DIR}/qa/Dockerfile --destination=${QA_IMAGE} --cache=true
|
||||
retry: 2
|
||||
|
||||
# This image is used by:
|
||||
# - The `CNG` pipelines (via the `review-build-cng` job): https://gitlab.com/gitlab-org/build/CNG/-/blob/cfc67136d711e1c8c409bf8e57427a644393da2f/.gitlab-ci.yml#L335
|
||||
# - The `omnibus-gitlab` pipelines (via the `package-and-qa` job): https://gitlab.com/gitlab-org/omnibus-gitlab/-/blob/dfd1ad475868fc84e91ab7b5706aa03e46dc3a86/.gitlab-ci.yml#L130
|
||||
build-assets-image:
|
||||
extends:
|
||||
- .use-kaniko
|
||||
- .build-images:rules:build-assets-image
|
||||
stage: build-images
|
||||
needs: ["compile-production-assets"]
|
||||
variables:
|
||||
GIT_DEPTH: "1"
|
||||
script:
|
||||
# TODO: Change the image tag to be the MD5 of assets files and skip image building if the image exists
|
||||
# We'll also need to pass GITLAB_ASSETS_TAG to the trigerred omnibus-gitlab pipeline similarly to how we do it for trigerred CNG pipelines
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/208389
|
||||
- run_timed_command "scripts/build_assets_image"
|
||||
retry: 2
|
|
@ -59,6 +59,15 @@ docs lint:
|
|||
# Check the internal anchor links
|
||||
- bundle exec nanoc check internal_anchors
|
||||
|
||||
ui-docs-links lint:
|
||||
extends:
|
||||
- .docs:rules:docs-lint
|
||||
- .static-analysis-base
|
||||
stage: test
|
||||
needs: []
|
||||
script:
|
||||
- bundle exec haml-lint -i DocumentationLinks
|
||||
|
||||
graphql-reference-verify:
|
||||
extends:
|
||||
- .default-retry
|
||||
|
|
|
@ -2,16 +2,18 @@
|
|||
extends:
|
||||
- .default-retry
|
||||
- .default-before_script
|
||||
- .assets-compile-cache
|
||||
variables:
|
||||
SETUP_DB: "false"
|
||||
# we override the max_old_space_size to prevent OOM errors
|
||||
NODE_OPTIONS: --max_old_space_size=3584
|
||||
WEBPACK_VENDOR_DLL: "true"
|
||||
|
||||
.compile-assets-base:
|
||||
extends: .frontend-base
|
||||
extends:
|
||||
- .frontend-base
|
||||
- .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
|
||||
variables:
|
||||
WEBPACK_VENDOR_DLL: "true"
|
||||
stage: prepare
|
||||
script:
|
||||
- node --version
|
||||
|
@ -90,21 +92,6 @@ update-yarn-cache:
|
|||
cache:
|
||||
policy: push
|
||||
|
||||
build-assets-image:
|
||||
extends:
|
||||
- .use-kaniko
|
||||
- .frontend:rules:compile-production-assets
|
||||
stage: build-images
|
||||
needs: ["compile-production-assets"]
|
||||
variables:
|
||||
GIT_DEPTH: "1"
|
||||
script:
|
||||
# TODO: Change the image tag to be the MD5 of assets files and skip image building if the image exists
|
||||
# We'll also need to pass GITLAB_ASSETS_TAG to the trigerred omnibus-gitlab pipeline similarly to how we do it for trigerred CNG pipelines
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/208389
|
||||
- run_timed_command "scripts/build_assets_image"
|
||||
retry: 2
|
||||
|
||||
.frontend-fixtures-base:
|
||||
extends:
|
||||
- .frontend-base
|
||||
|
@ -114,6 +101,7 @@ build-assets-image:
|
|||
needs: ["setup-test-env", "compile-test-assets"]
|
||||
variables:
|
||||
SETUP_DB: "true"
|
||||
WEBPACK_VENDOR_DLL: "true"
|
||||
script:
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
|
@ -138,22 +126,25 @@ frontend-fixtures-as-if-foss:
|
|||
|
||||
.frontend-test-base:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .frontend-base
|
||||
- .yarn-cache
|
||||
variables:
|
||||
USE_BUNDLE_INSTALL: "false"
|
||||
SETUP_DB: "false"
|
||||
stage: test
|
||||
before_script:
|
||||
- source scripts/utils.sh
|
||||
|
||||
eslint-as-if-foss:
|
||||
extends:
|
||||
- .frontend-test-base
|
||||
- .frontend:rules:eslint-as-if-foss
|
||||
- .as-if-foss
|
||||
needs: []
|
||||
script:
|
||||
- run_timed_command "retry yarn install --frozen-lockfile"
|
||||
- yarn run eslint
|
||||
|
||||
.karma-base:
|
||||
extends: .frontend-test-base
|
||||
variables:
|
||||
# we override the max_old_space_size to prevent OOM errors
|
||||
NODE_OPTIONS: --max_old_space_size=3584
|
||||
script:
|
||||
- source scripts/utils.sh
|
||||
- export BABEL_ENV=coverage CHROME_LOG_FILE=chrome_debug.log
|
||||
- run_timed_command "retry yarn install --frozen-lockfile"
|
||||
- run_timed_command "yarn karma"
|
||||
|
@ -174,6 +165,7 @@ karma:
|
|||
- tmp/tests/frontend/
|
||||
reports:
|
||||
junit: junit_karma.xml
|
||||
cobertura: coverage-javascript/cobertura-coverage.xml
|
||||
|
||||
karma-as-if-foss:
|
||||
extends:
|
||||
|
@ -185,7 +177,6 @@ karma-as-if-foss:
|
|||
.jest-base:
|
||||
extends: .frontend-test-base
|
||||
script:
|
||||
- source scripts/utils.sh
|
||||
- run_timed_command "retry yarn install --frozen-lockfile"
|
||||
- run_timed_command "yarn jest --ci --coverage --testSequencer ./scripts/frontend/parallel_ci_sequencer.js"
|
||||
|
||||
|
@ -211,7 +202,6 @@ jest-integration:
|
|||
- .frontend-test-base
|
||||
- .frontend:rules:default-frontend-jobs
|
||||
script:
|
||||
- source scripts/utils.sh
|
||||
- run_timed_command "retry yarn install --frozen-lockfile"
|
||||
- run_timed_command "yarn jest:integration --ci"
|
||||
needs: ["frontend-fixtures"]
|
||||
|
@ -236,11 +226,14 @@ coverage-frontend:
|
|||
- run_timed_command "retry yarn install --frozen-lockfile"
|
||||
script:
|
||||
- run_timed_command "yarn node scripts/frontend/merge_coverage_frontend.js"
|
||||
coverage: '/^Statements\s*:\s*?(\d+(?:\.\d+)?)%/'
|
||||
artifacts:
|
||||
name: coverage-frontend
|
||||
expire_in: 31d
|
||||
paths:
|
||||
- coverage-frontend/
|
||||
reports:
|
||||
cobertura: coverage-frontend/cobertura-coverage.xml
|
||||
|
||||
.qa-frontend-node:
|
||||
extends:
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
.rails-cache:
|
||||
cache:
|
||||
key: "rails-v1"
|
||||
key: "rails-v2"
|
||||
paths:
|
||||
- vendor/ruby/
|
||||
- vendor/gitaly-ruby/
|
||||
|
@ -72,6 +72,15 @@
|
|||
variables:
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
|
||||
.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"
|
||||
services:
|
||||
- name: postgres:12
|
||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||
- name: redis:alpine
|
||||
variables:
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
|
||||
.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"
|
||||
services:
|
||||
|
@ -82,6 +91,16 @@
|
|||
variables:
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
|
||||
.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"
|
||||
services:
|
||||
- name: postgres:12
|
||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||
- name: redis:alpine
|
||||
- name: elasticsearch:6.4.2
|
||||
variables:
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
|
||||
.use-kaniko:
|
||||
image:
|
||||
name: gcr.io/kaniko-project/executor:debug-v0.20.0
|
||||
|
|
|
@ -49,7 +49,6 @@ update-qa-cache:
|
|||
.package-and-qa-base:
|
||||
image: ruby:2.6-alpine
|
||||
stage: qa
|
||||
dependencies: []
|
||||
retry: 0
|
||||
script:
|
||||
- source scripts/utils.sh
|
||||
|
|
|
@ -1,9 +1,129 @@
|
|||
######################
|
||||
# rspec job base specs
|
||||
.rails-job-base:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .default-before_script
|
||||
- .rails-cache
|
||||
|
||||
.rspec-base:
|
||||
extends: .rails-job-base
|
||||
stage: test
|
||||
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets"]
|
||||
script:
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source scripts/rspec_helpers.sh
|
||||
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag ~level:migration"
|
||||
artifacts:
|
||||
expire_in: 31d
|
||||
when: always
|
||||
paths:
|
||||
- coverage/
|
||||
- knapsack/
|
||||
- rspec_flaky/
|
||||
- rspec_profiling/
|
||||
- tmp/capybara/
|
||||
- tmp/memory_test/
|
||||
- log/*.log
|
||||
reports:
|
||||
junit: junit_rspec.xml
|
||||
|
||||
.rspec-base-migration:
|
||||
extends: .rails:rules:ee-and-foss-migration
|
||||
script:
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source scripts/rspec_helpers.sh
|
||||
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag level:migration"
|
||||
|
||||
.rspec-base-pg11:
|
||||
extends:
|
||||
- .rspec-base
|
||||
- .use-pg11
|
||||
|
||||
.rspec-base-pg12:
|
||||
extends:
|
||||
- .rspec-base
|
||||
- .use-pg12
|
||||
|
||||
.rspec-base-pg11-as-if-foss:
|
||||
extends:
|
||||
- .rspec-base
|
||||
- .as-if-foss
|
||||
- .use-pg11
|
||||
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets as-if-foss"]
|
||||
|
||||
.rspec-ee-base-pg11:
|
||||
extends:
|
||||
- .rspec-base
|
||||
- .use-pg11-ee
|
||||
|
||||
.rspec-ee-base-pg12:
|
||||
extends:
|
||||
- .rspec-base
|
||||
- .use-pg12-ee
|
||||
|
||||
.rspec-ee-base-geo:
|
||||
extends: .rspec-base
|
||||
script:
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source scripts/rspec_helpers.sh
|
||||
- scripts/prepare_postgres_fdw.sh
|
||||
- rspec_paralellized_job "--tag ~quarantine --tag geo"
|
||||
|
||||
.rspec-ee-base-geo-pg11:
|
||||
extends:
|
||||
- .rspec-ee-base-geo
|
||||
- .use-pg11-ee
|
||||
|
||||
.rspec-ee-base-geo-pg12:
|
||||
extends:
|
||||
- .rspec-ee-base-geo
|
||||
- .use-pg12-ee
|
||||
|
||||
.db-job-base:
|
||||
extends:
|
||||
- .rails-job-base
|
||||
- .rails:rules:ee-and-foss-migration
|
||||
- .use-pg11
|
||||
stage: test
|
||||
needs: ["setup-test-env"]
|
||||
# rspec job base specs
|
||||
######################
|
||||
|
||||
############################
|
||||
# rspec job parallel configs
|
||||
.rspec-migration-parallel:
|
||||
parallel: 5
|
||||
|
||||
.rspec-ee-migration-parallel:
|
||||
parallel: 2
|
||||
|
||||
.rspec-unit-parallel:
|
||||
parallel: 20
|
||||
|
||||
.rspec-ee-unit-parallel:
|
||||
parallel: 10
|
||||
|
||||
.rspec-ee-unit-geo-parallel:
|
||||
parallel: 2
|
||||
|
||||
.rspec-integration-parallel:
|
||||
parallel: 8
|
||||
|
||||
.rspec-ee-integration-parallel:
|
||||
parallel: 4
|
||||
|
||||
.rspec-system-parallel:
|
||||
parallel: 24
|
||||
|
||||
.rspec-ee-system-parallel:
|
||||
parallel: 6
|
||||
# rspec job parallel configs
|
||||
############################
|
||||
|
||||
#######################################################
|
||||
# EE/FOSS: default refs (MRs, master, schedules) jobs #
|
||||
setup-test-env:
|
||||
|
@ -86,73 +206,37 @@ downtime_check:
|
|||
script:
|
||||
- bundle exec rake downtime_check
|
||||
|
||||
.rspec-base:
|
||||
extends: .rails-job-base
|
||||
stage: test
|
||||
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets"]
|
||||
script:
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source scripts/rspec_helpers.sh
|
||||
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag ~level:migration"
|
||||
artifacts:
|
||||
expire_in: 31d
|
||||
when: always
|
||||
paths:
|
||||
- coverage/
|
||||
- knapsack/
|
||||
- rspec_flaky/
|
||||
- rspec_profiling/
|
||||
- tmp/capybara/
|
||||
- tmp/memory_test/
|
||||
- log/*.log
|
||||
reports:
|
||||
junit: junit_rspec.xml
|
||||
|
||||
.rspec-base-pg11:
|
||||
extends:
|
||||
- .rspec-base
|
||||
- .rails:rules:ee-and-foss
|
||||
- .use-pg11
|
||||
|
||||
.rspec-base-migration:
|
||||
script:
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source scripts/rspec_helpers.sh
|
||||
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag level:migration"
|
||||
|
||||
rspec migration pg11:
|
||||
extends:
|
||||
- .rspec-base-pg11
|
||||
- .rspec-base-migration
|
||||
parallel: 5
|
||||
- .rspec-migration-parallel
|
||||
|
||||
rspec unit pg11:
|
||||
extends: .rspec-base-pg11
|
||||
parallel: 20
|
||||
extends:
|
||||
- .rspec-base-pg11
|
||||
- .rails:rules:ee-and-foss-unit
|
||||
- .rspec-unit-parallel
|
||||
|
||||
rspec integration pg11:
|
||||
extends: .rspec-base-pg11
|
||||
parallel: 8
|
||||
extends:
|
||||
- .rspec-base-pg11
|
||||
- .rails:rules:ee-and-foss-integration
|
||||
- .rspec-integration-parallel
|
||||
|
||||
rspec system pg11:
|
||||
extends: .rspec-base-pg11
|
||||
parallel: 24
|
||||
extends:
|
||||
- .rspec-base-pg11
|
||||
- .rails:rules:ee-and-foss-system
|
||||
- .rspec-system-parallel
|
||||
|
||||
rspec fast_spec_helper:
|
||||
extends: .rspec-base-pg11
|
||||
extends:
|
||||
- .rspec-base-pg11
|
||||
- .rails:rules:ee-and-foss-fast_spec_helper
|
||||
script:
|
||||
- bin/rspec spec/fast_spec_helper.rb
|
||||
|
||||
.db-job-base:
|
||||
extends:
|
||||
- .rails-job-base
|
||||
- .rails:rules:ee-and-foss
|
||||
- .use-pg11
|
||||
stage: test
|
||||
needs: ["setup-test-env"]
|
||||
|
||||
db:migrate:reset:
|
||||
extends: .db-job-base
|
||||
script:
|
||||
|
@ -216,7 +300,7 @@ gitlab:setup:
|
|||
rspec:coverage:
|
||||
extends:
|
||||
- .rails-job-base
|
||||
- .rails:rules:ee-mr-and-master-only
|
||||
- .rails:rules:rspec-coverage
|
||||
stage: post-test
|
||||
# We cannot use needs since it would mean needing 84 jobs (since most are parallelized)
|
||||
# so we use `dependencies` here.
|
||||
|
@ -248,118 +332,180 @@ rspec:coverage:
|
|||
- coverage/index.html
|
||||
- coverage/assets/
|
||||
- tmp/memory_test/
|
||||
reports:
|
||||
cobertura: coverage/coverage.xml
|
||||
# EE/FOSS: default refs (MRs, master, schedules) jobs #
|
||||
#######################################################
|
||||
|
||||
##################################################
|
||||
# EE: default refs (MRs, master, schedules) jobs #
|
||||
.rspec-base-ee:
|
||||
extends:
|
||||
- .rspec-base
|
||||
- .rails:rules:ee-only
|
||||
|
||||
.rspec-base-pg11-as-if-foss:
|
||||
extends:
|
||||
- .rspec-base
|
||||
- .rails:rules:as-if-foss
|
||||
- .as-if-foss
|
||||
- .use-pg11
|
||||
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets as-if-foss"]
|
||||
|
||||
.rspec-ee-base-pg11:
|
||||
extends:
|
||||
- .rspec-base-ee
|
||||
- .use-pg11-ee
|
||||
|
||||
rspec migration pg11-as-if-foss:
|
||||
extends:
|
||||
- .rspec-base-pg11-as-if-foss
|
||||
- .rspec-base-migration
|
||||
parallel: 5
|
||||
- .rails:rules:as-if-foss-migration
|
||||
- .rspec-migration-parallel
|
||||
|
||||
rspec unit pg11-as-if-foss:
|
||||
extends: .rspec-base-pg11-as-if-foss
|
||||
parallel: 20
|
||||
extends:
|
||||
- .rspec-base-pg11-as-if-foss
|
||||
- .rails:rules:as-if-foss-unit
|
||||
- .rspec-unit-parallel
|
||||
|
||||
rspec integration pg11-as-if-foss:
|
||||
extends: .rspec-base-pg11-as-if-foss
|
||||
parallel: 8
|
||||
extends:
|
||||
- .rspec-base-pg11-as-if-foss
|
||||
- .rails:rules:as-if-foss-integration
|
||||
- .rspec-integration-parallel
|
||||
|
||||
rspec system pg11-as-if-foss:
|
||||
extends: .rspec-base-pg11-as-if-foss
|
||||
parallel: 24
|
||||
extends:
|
||||
- .rspec-base-pg11-as-if-foss
|
||||
- .rails:rules:as-if-foss-system
|
||||
- .rspec-system-parallel
|
||||
|
||||
rspec-ee migration pg11:
|
||||
extends:
|
||||
- .rspec-ee-base-pg11
|
||||
- .rspec-base-migration
|
||||
parallel: 2
|
||||
- .rails:rules:ee-only-migration
|
||||
- .rspec-ee-migration-parallel
|
||||
|
||||
rspec-ee unit pg11:
|
||||
extends: .rspec-ee-base-pg11
|
||||
parallel: 10
|
||||
extends:
|
||||
- .rspec-ee-base-pg11
|
||||
- .rails:rules:ee-only-unit
|
||||
- .rspec-ee-unit-parallel
|
||||
|
||||
rspec-ee integration pg11:
|
||||
extends: .rspec-ee-base-pg11
|
||||
parallel: 4
|
||||
extends:
|
||||
- .rspec-ee-base-pg11
|
||||
- .rails:rules:ee-only-integration
|
||||
- .rspec-ee-integration-parallel
|
||||
|
||||
rspec-ee system pg11:
|
||||
extends: .rspec-ee-base-pg11
|
||||
parallel: 6
|
||||
|
||||
.rspec-ee-base-geo:
|
||||
extends: .rspec-base-ee
|
||||
script:
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source scripts/rspec_helpers.sh
|
||||
- scripts/prepare_postgres_fdw.sh
|
||||
- rspec_paralellized_job "--tag ~quarantine --tag geo"
|
||||
|
||||
.rspec-ee-base-geo-pg11:
|
||||
extends:
|
||||
- .rspec-ee-base-geo
|
||||
- .use-pg11-ee
|
||||
- .rspec-ee-base-pg11
|
||||
- .rails:rules:ee-only-system
|
||||
- .rspec-ee-system-parallel
|
||||
|
||||
rspec-ee unit pg11 geo:
|
||||
extends: .rspec-ee-base-geo-pg11
|
||||
parallel: 2
|
||||
extends:
|
||||
- .rspec-ee-base-geo-pg11
|
||||
- .rails:rules:ee-only-unit
|
||||
- .rspec-ee-unit-geo-parallel
|
||||
|
||||
rspec-ee integration pg11 geo:
|
||||
extends: .rspec-ee-base-geo-pg11
|
||||
extends:
|
||||
- .rspec-ee-base-geo-pg11
|
||||
- .rails:rules:ee-only-integration
|
||||
|
||||
rspec-ee system pg11 geo:
|
||||
extends: .rspec-ee-base-geo-pg11
|
||||
extends:
|
||||
- .rspec-ee-base-geo-pg11
|
||||
- .rails:rules:ee-only-system
|
||||
|
||||
db:rollback geo:
|
||||
extends:
|
||||
- db:rollback
|
||||
- .rails:rules:ee-only
|
||||
- .rails:rules:ee-only-migration
|
||||
script:
|
||||
- bundle exec rake geo:db:migrate VERSION=20170627195211
|
||||
- bundle exec rake geo:db:migrate
|
||||
# EE: default refs (MRs, master, schedules) jobs #
|
||||
##################################################
|
||||
|
||||
##########################################
|
||||
# EE/FOSS: master nightly scheduled jobs #
|
||||
rspec migration pg12:
|
||||
extends:
|
||||
- .rspec-base-pg12
|
||||
- .rspec-base-migration
|
||||
- .rails:rules:master-schedule-nightly--code-backstage
|
||||
- .rspec-migration-parallel
|
||||
|
||||
rspec unit pg12:
|
||||
extends:
|
||||
- .rspec-base-pg12
|
||||
- .rails:rules:master-schedule-nightly--code-backstage
|
||||
- .rspec-unit-parallel
|
||||
|
||||
rspec integration pg12:
|
||||
extends:
|
||||
- .rspec-base-pg12
|
||||
- .rails:rules:master-schedule-nightly--code-backstage
|
||||
- .rspec-integration-parallel
|
||||
|
||||
rspec system pg12:
|
||||
extends:
|
||||
- .rspec-base-pg12
|
||||
- .rails:rules:master-schedule-nightly--code-backstage
|
||||
- .rspec-system-parallel
|
||||
# EE/FOSS: master nightly scheduled jobs #
|
||||
##########################################
|
||||
|
||||
#####################################
|
||||
# EE: master nightly scheduled jobs #
|
||||
rspec-ee migration pg12:
|
||||
extends:
|
||||
- .rspec-ee-base-pg12
|
||||
- .rspec-base-migration
|
||||
- .rails:rules:master-schedule-nightly--code-backstage-ee-only
|
||||
- .rspec-ee-migration-parallel
|
||||
|
||||
rspec-ee unit pg12:
|
||||
extends:
|
||||
- .rspec-ee-base-pg12
|
||||
- .rails:rules:master-schedule-nightly--code-backstage-ee-only
|
||||
- .rspec-ee-unit-parallel
|
||||
|
||||
rspec-ee integration pg12:
|
||||
extends:
|
||||
- .rspec-ee-base-pg12
|
||||
- .rails:rules:master-schedule-nightly--code-backstage-ee-only
|
||||
- .rspec-ee-integration-parallel
|
||||
|
||||
rspec-ee system pg12:
|
||||
extends:
|
||||
- .rspec-ee-base-pg12
|
||||
- .rails:rules:master-schedule-nightly--code-backstage-ee-only
|
||||
- .rspec-ee-system-parallel
|
||||
|
||||
rspec-ee unit pg12 geo:
|
||||
extends:
|
||||
- .rspec-ee-base-geo-pg12
|
||||
- .rails:rules:master-schedule-nightly--code-backstage-ee-only
|
||||
- .rspec-ee-unit-geo-parallel
|
||||
|
||||
rspec-ee integration pg12 geo:
|
||||
extends:
|
||||
- .rspec-ee-base-geo-pg12
|
||||
- .rails:rules:master-schedule-nightly--code-backstage-ee-only
|
||||
|
||||
rspec-ee system pg12 geo:
|
||||
extends:
|
||||
- .rspec-ee-base-geo-pg12
|
||||
- .rails:rules:master-schedule-nightly--code-backstage-ee-only
|
||||
# EE: master nightly scheduled jobs #
|
||||
#####################################
|
||||
|
||||
##################################################
|
||||
# EE: Canonical MR pipelines
|
||||
rspec foss-impact:
|
||||
extends:
|
||||
- .rspec-base
|
||||
- .as-if-foss
|
||||
- .rspec-base-pg11-as-if-foss
|
||||
- .rails:rules:ee-mr-only
|
||||
- .use-pg11
|
||||
script:
|
||||
- install_gitlab_gem
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source scripts/rspec_helpers.sh
|
||||
- tooling/bin/find_foss_tests tmp/matching_foss_tests.txt
|
||||
- rspec_matched_tests tmp/matching_foss_tests.txt "--tag ~quarantine --tag ~geo --tag ~level:migration"
|
||||
- rspec_matched_tests tmp/matching_foss_tests.txt "--tag ~quarantine"
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
- tmp/matching_foss_tests.txt
|
||||
- tmp/capybara/
|
||||
# EE: Merge Request pipelines
|
||||
# EE: Canonical MR pipelines
|
||||
##################################################
|
||||
|
|
|
@ -15,7 +15,7 @@ code_quality:
|
|||
stage: test
|
||||
needs: []
|
||||
variables:
|
||||
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.9"
|
||||
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.10"
|
||||
script:
|
||||
- |
|
||||
if ! docker info &>/dev/null; then
|
||||
|
@ -59,6 +59,7 @@ code_quality:
|
|||
SAST_ANALYZER_IMAGE_TAG: 2
|
||||
SAST_BRAKEMAN_LEVEL: 2 # GitLab-specific
|
||||
SAST_EXCLUDED_PATHS: qa,spec,doc,ee/spec # GitLab-specific
|
||||
SAST_DISABLE_BABEL: "true"
|
||||
script:
|
||||
- /analyzer run
|
||||
|
||||
|
@ -72,11 +73,10 @@ eslint-sast:
|
|||
image:
|
||||
name: "$SAST_ANALYZER_IMAGE_PREFIX/eslint:$SAST_ANALYZER_IMAGE_TAG"
|
||||
|
||||
# Temporary disabled as it's constantly failing. See https://gitlab.com/gitlab-org/gitlab/-/issues/213769.
|
||||
# nodejs-scan-sast:
|
||||
# extends: .sast
|
||||
# image:
|
||||
# name: "$SAST_ANALYZER_IMAGE_PREFIX/nodejs-scan:$SAST_ANALYZER_IMAGE_TAG"
|
||||
nodejs-scan-sast:
|
||||
extends: .sast
|
||||
image:
|
||||
name: "$SAST_ANALYZER_IMAGE_PREFIX/nodejs-scan:$SAST_ANALYZER_IMAGE_TAG"
|
||||
|
||||
secrets-sast:
|
||||
extends: .sast
|
||||
|
@ -172,6 +172,7 @@ dependency_scanning:
|
|||
# # - 'export DAST_AUTH_URL="${DAST_WEBSITE}/users/sign_in"'
|
||||
# # - 'export DAST_PASSWORD="${REVIEW_APPS_ROOT_PASSWORD}"'
|
||||
# - /analyze -t $DAST_WEBSITE
|
||||
# timeout: 4h
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - gl-dast-report.json # GitLab-specific
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
build-qa-image:
|
||||
extends:
|
||||
- .use-kaniko
|
||||
- .review:rules:build-qa-image
|
||||
stage: build-images
|
||||
needs: []
|
||||
script:
|
||||
- export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_REF_SLUG}"
|
||||
- /kaniko/executor --context=${CI_PROJECT_DIR} --dockerfile=${CI_PROJECT_DIR}/qa/Dockerfile --destination=${QA_IMAGE} --cache=true
|
||||
retry: 2
|
||||
|
||||
review-cleanup:
|
||||
extends:
|
||||
- .default-retry
|
||||
|
@ -27,25 +16,24 @@ review-cleanup:
|
|||
- ruby -rrubygems scripts/review_apps/automated_cleanup.rb
|
||||
- gcp_cleanup
|
||||
|
||||
# Temporarily disabling review apps
|
||||
#review-build-cng:
|
||||
# extends:
|
||||
# - .default-retry
|
||||
# - .review:rules:review-build-cng
|
||||
# image: ruby:2.6-alpine
|
||||
# stage: review-prepare
|
||||
# before_script:
|
||||
# - source scripts/utils.sh
|
||||
# - install_api_client_dependencies_with_apk
|
||||
# - install_gitlab_gem
|
||||
# needs:
|
||||
# - job: compile-production-assets
|
||||
# artifacts: false
|
||||
# script:
|
||||
# - BUILD_TRIGGER_TOKEN=$REVIEW_APPS_BUILD_TRIGGER_TOKEN ./scripts/trigger-build cng
|
||||
# # When the job is manual, review-deploy is also manual and we don't want people
|
||||
# # to have to manually start the jobs in sequence, so we do it for them.
|
||||
# - '[ -z $CI_JOB_MANUAL ] || play_job "review-deploy"'
|
||||
review-build-cng:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .review:rules:review-build-cng
|
||||
image: ruby:2.6-alpine
|
||||
stage: review-prepare
|
||||
before_script:
|
||||
- source scripts/utils.sh
|
||||
- install_api_client_dependencies_with_apk
|
||||
- install_gitlab_gem
|
||||
needs:
|
||||
- job: compile-production-assets
|
||||
artifacts: false
|
||||
script:
|
||||
- BUILD_TRIGGER_TOKEN=$REVIEW_APPS_BUILD_TRIGGER_TOKEN ./scripts/trigger-build cng
|
||||
# When the job is manual, review-deploy is also manual and we don't want people
|
||||
# to have to manually start the jobs in sequence, so we do it for them.
|
||||
- '[ -z $CI_JOB_MANUAL ] || play_job "review-deploy"'
|
||||
|
||||
.review-workflow-base:
|
||||
extends:
|
||||
|
@ -53,45 +41,46 @@ review-cleanup:
|
|||
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-helm3-kubectl1.14
|
||||
variables:
|
||||
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
|
||||
REVIEW_APPS_DOMAIN: "temp.gitlab-review.app" # FIXME: using temporary domain
|
||||
DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
|
||||
GITLAB_HELM_CHART_REF: "master"
|
||||
GITLAB_HELM_CHART_REF: "v4.1.3"
|
||||
environment:
|
||||
name: review/${CI_COMMIT_REF_NAME}
|
||||
url: https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}
|
||||
on_stop: review-stop
|
||||
auto_stop_in: 48 hours
|
||||
|
||||
# Temporarily disabling review apps
|
||||
#review-deploy:
|
||||
# extends:
|
||||
# - .review-workflow-base
|
||||
# - .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
|
||||
# stage: review
|
||||
# dependencies: []
|
||||
# resource_group: "review/${CI_COMMIT_REF_NAME}"
|
||||
# before_script:
|
||||
# - export GITLAB_SHELL_VERSION=$(<GITLAB_SHELL_VERSION)
|
||||
# - export GITALY_VERSION=$(<GITALY_SERVER_VERSION)
|
||||
# - export GITLAB_WORKHORSE_VERSION=$(<GITLAB_WORKHORSE_VERSION)
|
||||
# - echo "${CI_ENVIRONMENT_URL}" > environment_url.txt
|
||||
# - source ./scripts/utils.sh
|
||||
# - install_api_client_dependencies_with_apk
|
||||
# - source scripts/review_apps/review-apps.sh
|
||||
# script:
|
||||
# - check_kube_domain
|
||||
# - ensure_namespace
|
||||
# - install_external_dns
|
||||
# - download_chart
|
||||
# - date
|
||||
# - deploy || (display_deployment_debug && exit 1)
|
||||
# # When the job is manual, review-qa-smoke is also manual and we don't want people
|
||||
# # to have to manually start the jobs in sequence, so we do it for them.
|
||||
# - '[ -z $CI_JOB_MANUAL ] || play_job "review-qa-smoke"'
|
||||
# - '[ -z $CI_JOB_MANUAL ] || play_job "review-performance"'
|
||||
# artifacts:
|
||||
# paths: [environment_url.txt]
|
||||
# expire_in: 2 days
|
||||
# when: always
|
||||
review-deploy:
|
||||
extends:
|
||||
- .review-workflow-base
|
||||
- .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
|
||||
stage: review
|
||||
dependencies: []
|
||||
resource_group: "review/${CI_COMMIT_REF_NAME}"
|
||||
before_script:
|
||||
- export GITLAB_SHELL_VERSION=$(<GITLAB_SHELL_VERSION)
|
||||
- export GITALY_VERSION=$(<GITALY_SERVER_VERSION)
|
||||
- export GITLAB_WORKHORSE_VERSION=$(<GITLAB_WORKHORSE_VERSION)
|
||||
- echo "${CI_ENVIRONMENT_URL}" > environment_url.txt
|
||||
- source ./scripts/utils.sh
|
||||
- install_api_client_dependencies_with_apk
|
||||
- source scripts/review_apps/review-apps.sh
|
||||
script:
|
||||
- check_kube_domain
|
||||
- ensure_namespace
|
||||
- install_external_dns
|
||||
- download_chart
|
||||
- date
|
||||
- deploy || (display_deployment_debug && exit 1)
|
||||
- disable_sign_ups
|
||||
# When the job is manual, review-qa-smoke is also manual and we don't want people
|
||||
# to have to manually start the jobs in sequence, so we do it for them.
|
||||
- '[ -z $CI_JOB_MANUAL ] || play_job "review-qa-smoke"'
|
||||
- '[ -z $CI_JOB_MANUAL ] || play_job "review-performance"'
|
||||
artifacts:
|
||||
paths: [environment_url.txt]
|
||||
expire_in: 2 days
|
||||
when: always
|
||||
|
||||
.review-stop-base:
|
||||
extends: .review-workflow-base
|
||||
|
@ -124,110 +113,110 @@ review-stop:
|
|||
script:
|
||||
- delete_release
|
||||
|
||||
# Temporarily disabling review apps
|
||||
#.review-qa-base:
|
||||
# extends:
|
||||
# - .default-retry
|
||||
# - .use-docker-in-docker
|
||||
# image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.6
|
||||
# stage: qa
|
||||
# # This is needed so that manual jobs with needs don't block the pipeline.
|
||||
# # See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
|
||||
# dependencies: ["review-deploy"]
|
||||
# variables:
|
||||
# QA_ARTIFACTS_DIR: "${CI_PROJECT_DIR}/qa"
|
||||
# QA_CAN_TEST_GIT_PROTOCOL_V2: "false"
|
||||
# QA_DEBUG: "true"
|
||||
# GITLAB_USERNAME: "root"
|
||||
# GITLAB_PASSWORD: "${REVIEW_APPS_ROOT_PASSWORD}"
|
||||
# GITLAB_ADMIN_USERNAME: "root"
|
||||
# GITLAB_ADMIN_PASSWORD: "${REVIEW_APPS_ROOT_PASSWORD}"
|
||||
# GITHUB_ACCESS_TOKEN: "${REVIEW_APPS_QA_GITHUB_ACCESS_TOKEN}"
|
||||
# EE_LICENSE: "${REVIEW_APPS_EE_LICENSE}"
|
||||
# before_script:
|
||||
# - export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_REF_SLUG}"
|
||||
# - export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
|
||||
# - echo "${CI_ENVIRONMENT_URL}"
|
||||
# - echo "${QA_IMAGE}"
|
||||
# - source scripts/utils.sh
|
||||
# - install_api_client_dependencies_with_apk
|
||||
# - gem install gitlab-qa --no-document ${GITLAB_QA_VERSION:+ --version ${GITLAB_QA_VERSION}}
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - ./qa/gitlab-qa-run-*
|
||||
# expire_in: 7 days
|
||||
# when: always
|
||||
#
|
||||
#review-qa-smoke:
|
||||
# extends:
|
||||
# - .review-qa-base
|
||||
# - .review:rules:review-qa-smoke
|
||||
# script:
|
||||
# - gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}"
|
||||
#
|
||||
#review-qa-all:
|
||||
# extends:
|
||||
# - .review-qa-base
|
||||
# - .review:rules:mr-only-manual
|
||||
# parallel: 5
|
||||
# script:
|
||||
# - export KNAPSACK_REPORT_PATH=knapsack/master_report.json
|
||||
# - export KNAPSACK_TEST_FILE_PATTERN=qa/specs/features/**/*_spec.rb
|
||||
# - gitlab-qa Test::Instance::Any "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" -- --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml --format html --out tmp/rspec.htm --color --format documentation
|
||||
#
|
||||
#review-performance:
|
||||
# extends:
|
||||
# - .default-retry
|
||||
# - .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
|
||||
# image:
|
||||
# name: sitespeedio/sitespeed.io:6.3.1
|
||||
# entrypoint: [""]
|
||||
# stage: qa
|
||||
# # This is needed so that manual jobs with needs don't block the pipeline.
|
||||
# # See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
|
||||
# dependencies: ["review-deploy"]
|
||||
# before_script:
|
||||
# - export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
|
||||
# - echo "${CI_ENVIRONMENT_URL}"
|
||||
# - mkdir -p gitlab-exporter
|
||||
# - wget -O ./gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/master/index.js
|
||||
# - mkdir -p sitespeed-results
|
||||
# script:
|
||||
# - /start.sh --plugins.add ./gitlab-exporter --outputFolder sitespeed-results "${CI_ENVIRONMENT_URL}"
|
||||
# after_script:
|
||||
# - mv sitespeed-results/data/performance.json performance.json
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - sitespeed-results/
|
||||
# reports:
|
||||
# performance: performance.json
|
||||
# expire_in: 31d
|
||||
#
|
||||
#parallel-spec-reports:
|
||||
# extends:
|
||||
# - .review:rules:mr-only-manual
|
||||
# image: ruby:2.6-alpine
|
||||
# stage: post-qa
|
||||
# dependencies: ["review-qa-all"]
|
||||
# variables:
|
||||
# NEW_PARALLEL_SPECS_REPORT: qa/report-new.html
|
||||
# BASE_ARTIFACT_URL: "${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/file/qa/"
|
||||
# script:
|
||||
# - apk add --update build-base libxml2-dev libxslt-dev && rm -rf /var/cache/apk/*
|
||||
# - gem install nokogiri --no-document
|
||||
# - cd qa/gitlab-qa-run-*/gitlab-*
|
||||
# - ARTIFACT_DIRS=$(pwd |rev| awk -F / '{print $1,$2}' | rev | sed s_\ _/_)
|
||||
# - cd -
|
||||
# - '[[ -f $NEW_PARALLEL_SPECS_REPORT ]] || echo "{}" > ${NEW_PARALLEL_SPECS_REPORT}'
|
||||
# - scripts/merge-html-reports ${NEW_PARALLEL_SPECS_REPORT} ${BASE_ARTIFACT_URL}${ARTIFACT_DIRS} qa/gitlab-qa-run-*/**/rspec.htm
|
||||
# artifacts:
|
||||
# when: always
|
||||
# paths:
|
||||
# - qa/report-new.html
|
||||
# - qa/gitlab-qa-run-*
|
||||
# reports:
|
||||
# junit: qa/gitlab-qa-run-*/**/rspec-*.xml
|
||||
# expire_in: 31d
|
||||
.review-qa-base:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .use-docker-in-docker
|
||||
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.6
|
||||
stage: qa
|
||||
# This is needed so that manual jobs with needs don't block the pipeline.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
|
||||
dependencies: ["review-deploy"]
|
||||
variables:
|
||||
QA_ARTIFACTS_DIR: "${CI_PROJECT_DIR}/qa"
|
||||
QA_CAN_TEST_GIT_PROTOCOL_V2: "false"
|
||||
QA_DEBUG: "true"
|
||||
GITLAB_USERNAME: "root"
|
||||
GITLAB_PASSWORD: "${REVIEW_APPS_ROOT_PASSWORD}"
|
||||
GITLAB_ADMIN_USERNAME: "root"
|
||||
GITLAB_ADMIN_PASSWORD: "${REVIEW_APPS_ROOT_PASSWORD}"
|
||||
GITHUB_ACCESS_TOKEN: "${REVIEW_APPS_QA_GITHUB_ACCESS_TOKEN}"
|
||||
EE_LICENSE: "${REVIEW_APPS_EE_LICENSE}"
|
||||
SIGNUP_DISABLED: "true"
|
||||
before_script:
|
||||
- export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_REF_SLUG}"
|
||||
- export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
|
||||
- echo "${CI_ENVIRONMENT_URL}"
|
||||
- echo "${QA_IMAGE}"
|
||||
- source scripts/utils.sh
|
||||
- install_api_client_dependencies_with_apk
|
||||
- gem install gitlab-qa --no-document ${GITLAB_QA_VERSION:+ --version ${GITLAB_QA_VERSION}}
|
||||
artifacts:
|
||||
paths:
|
||||
- ./qa/gitlab-qa-run-*
|
||||
expire_in: 7 days
|
||||
when: always
|
||||
|
||||
review-qa-smoke:
|
||||
extends:
|
||||
- .review-qa-base
|
||||
- .review:rules:review-qa-smoke
|
||||
script:
|
||||
- gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}"
|
||||
|
||||
review-qa-all:
|
||||
extends:
|
||||
- .review-qa-base
|
||||
- .review:rules:mr-only-manual
|
||||
parallel: 5
|
||||
script:
|
||||
- export KNAPSACK_REPORT_PATH=knapsack/master_report.json
|
||||
- export KNAPSACK_TEST_FILE_PATTERN=qa/specs/features/**/*_spec.rb
|
||||
- gitlab-qa Test::Instance::Any "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" -- --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml --format html --out tmp/rspec.htm --color --format documentation
|
||||
|
||||
review-performance:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
|
||||
image:
|
||||
name: sitespeedio/sitespeed.io:6.3.1
|
||||
entrypoint: [""]
|
||||
stage: qa
|
||||
# This is needed so that manual jobs with needs don't block the pipeline.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
|
||||
dependencies: ["review-deploy"]
|
||||
before_script:
|
||||
- export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
|
||||
- echo "${CI_ENVIRONMENT_URL}"
|
||||
- mkdir -p gitlab-exporter
|
||||
- wget -O ./gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/master/index.js
|
||||
- mkdir -p sitespeed-results
|
||||
script:
|
||||
- /start.sh --plugins.add ./gitlab-exporter --outputFolder sitespeed-results "${CI_ENVIRONMENT_URL}"
|
||||
after_script:
|
||||
- mv sitespeed-results/data/performance.json performance.json
|
||||
artifacts:
|
||||
paths:
|
||||
- sitespeed-results/
|
||||
reports:
|
||||
performance: performance.json
|
||||
expire_in: 31d
|
||||
|
||||
parallel-spec-reports:
|
||||
extends:
|
||||
- .review:rules:mr-only-manual
|
||||
image: ruby:2.6-alpine
|
||||
stage: post-qa
|
||||
dependencies: ["review-qa-all"]
|
||||
variables:
|
||||
NEW_PARALLEL_SPECS_REPORT: qa/report-new.html
|
||||
BASE_ARTIFACT_URL: "${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/file/qa/"
|
||||
script:
|
||||
- apk add --update build-base libxml2-dev libxslt-dev && rm -rf /var/cache/apk/*
|
||||
- gem install nokogiri --no-document
|
||||
- cd qa/gitlab-qa-run-*/gitlab-*
|
||||
- ARTIFACT_DIRS=$(pwd |rev| awk -F / '{print $1,$2}' | rev | sed s_\ _/_)
|
||||
- cd -
|
||||
- '[[ -f $NEW_PARALLEL_SPECS_REPORT ]] || echo "{}" > ${NEW_PARALLEL_SPECS_REPORT}'
|
||||
- scripts/merge-html-reports ${NEW_PARALLEL_SPECS_REPORT} ${BASE_ARTIFACT_URL}${ARTIFACT_DIRS} qa/gitlab-qa-run-*/**/rspec.htm
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- qa/report-new.html
|
||||
- qa/gitlab-qa-run-*
|
||||
reports:
|
||||
junit: qa/gitlab-qa-run-*/**/rspec-*.xml
|
||||
expire_in: 31d
|
||||
|
||||
danger-review:
|
||||
extends:
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
if: '$CI_PROJECT_NAME != "gitlab-foss" && $CI_PROJECT_NAME != "gitlab-ce" && $CI_PROJECT_NAME != "gitlabhq"'
|
||||
|
||||
.if-default-refs: &if-default-refs
|
||||
if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG'
|
||||
if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
|
||||
|
||||
.if-master-refs: &if-master-refs
|
||||
if: '$CI_COMMIT_REF_NAME == "master"'
|
||||
|
@ -40,6 +40,9 @@
|
|||
.if-merge-request-title-update-caches: &if-merge-request-title-update-caches
|
||||
if: '$CI_MERGE_REQUEST_TITLE =~ /UPDATE CACHE/'
|
||||
|
||||
.if-merge-request-title-run-all-rspec: &if-merge-request-title-run-all-rspec
|
||||
if: '$CI_MERGE_REQUEST_TITLE =~ /RUN ALL RSPEC/'
|
||||
|
||||
.if-security-merge-request: &if-security-merge-request
|
||||
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID'
|
||||
|
||||
|
@ -71,6 +74,22 @@
|
|||
- ".gitlab-ci.yml"
|
||||
- ".gitlab/ci/**/*"
|
||||
|
||||
.ci-build-images-patterns: &ci-build-images-patterns
|
||||
- ".gitlab-ci.yml"
|
||||
- ".gitlab/ci/build-images.gitlab-ci.yml"
|
||||
|
||||
.ci-review-patterns: &ci-review-patterns
|
||||
- ".gitlab-ci.yml"
|
||||
- ".gitlab/ci/frontend.gitlab-ci.yml"
|
||||
- ".gitlab/ci/build-images.gitlab-ci.yml"
|
||||
- ".gitlab/ci/review.gitlab-ci.yml"
|
||||
|
||||
.ci-qa-patterns: &ci-qa-patterns
|
||||
- ".gitlab-ci.yml"
|
||||
- ".gitlab/ci/frontend.gitlab-ci.yml"
|
||||
- ".gitlab/ci/build-images.gitlab-ci.yml"
|
||||
- ".gitlab/ci/qa.gitlab-ci.yml"
|
||||
|
||||
.yaml-patterns: &yaml-patterns
|
||||
- "**/*.yml"
|
||||
|
||||
|
@ -92,6 +111,21 @@
|
|||
- "vendor/assets/**/*"
|
||||
- "{,ee/}{app/assets,app/helpers,app/presenters,app/views,locale,public,symbol}/**/*"
|
||||
|
||||
.backend-patterns: &backend-patterns
|
||||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "config.ru"
|
||||
# List explicitly all the app/ dirs that are backend (i.e. all except app/assets).
|
||||
- "{,ee/}{app/channels,app/controllers,app/finders,app/graphql,app/helpers,app/mailers,app/models,app/policies,app/presenters,app/serializers,app/services,app/uploaders,app/validators,app/views,app/workers}/**/*"
|
||||
- "{,ee/}{bin,cable,config,db,lib}/**/*"
|
||||
- "{,ee/}spec/**/*.rb"
|
||||
- ".gitlab-ci.yml"
|
||||
- ".gitlab/ci/**/*"
|
||||
|
||||
.db-patterns: &db-patterns
|
||||
- "{,ee/}{,spec/}{db,migrations}/**/*"
|
||||
- "{,ee/}{,spec/}lib/{,ee/}gitlab/background_migration/**/*"
|
||||
|
||||
.backstage-patterns: &backstage-patterns
|
||||
- "Dangerfile"
|
||||
- "danger/**/*"
|
||||
|
@ -197,6 +231,26 @@
|
|||
- <<: *if-master-schedule-2-hourly
|
||||
- <<: *if-merge-request-title-update-caches
|
||||
|
||||
######################
|
||||
# Build images rules #
|
||||
######################
|
||||
.build-images:rules:build-qa-image:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-dot-com-gitlab-org-and-security-merge-request
|
||||
changes: *ci-build-images-patterns
|
||||
- <<: *if-dot-com-gitlab-org-and-security-merge-request
|
||||
changes: *code-qa-patterns
|
||||
- <<: *if-dot-com-gitlab-org-schedule
|
||||
|
||||
.build-images:rules:build-assets-image:
|
||||
rules:
|
||||
- <<: *if-not-canonical-namespace
|
||||
when: never
|
||||
- changes: *ci-build-images-patterns
|
||||
- changes: *code-qa-patterns
|
||||
|
||||
####################
|
||||
# Cache repo rules #
|
||||
####################
|
||||
|
@ -263,7 +317,7 @@
|
|||
- <<: *if-not-canonical-namespace
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-qa-patterns
|
||||
changes: *code-qa-patterns
|
||||
|
||||
.frontend:rules:compile-test-assets:
|
||||
rules:
|
||||
|
@ -273,11 +327,8 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-security-merge-request
|
||||
- <<: *if-merge-request # Always run for MRs since `compile-test-assets as-if-foss` is either needed by `rspec foss-impact` or the `rspec * as-if-foss` jobs.
|
||||
changes: *code-backstage-qa-patterns
|
||||
- <<: *if-merge-request-title-as-if-foss
|
||||
- <<: *if-merge-request
|
||||
changes: *ci-patterns
|
||||
|
||||
.frontend:rules:default-frontend-jobs:
|
||||
rules:
|
||||
|
@ -294,6 +345,15 @@
|
|||
- <<: *if-merge-request
|
||||
changes: *ci-patterns
|
||||
|
||||
.frontend:rules:eslint-as-if-foss:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-title-as-if-foss
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *frontend-patterns
|
||||
|
||||
.frontend:rules:ee-mr-and-master-only:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
|
@ -341,9 +401,7 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-dot-com-gitlab-org-master
|
||||
changes: *code-backstage-qa-patterns
|
||||
when: on_success
|
||||
- <<: *if-master-schedule-2-hourly
|
||||
|
||||
############
|
||||
# QA rules #
|
||||
|
@ -367,7 +425,7 @@
|
|||
.qa:rules:package-and-qa:
|
||||
rules:
|
||||
- <<: *if-dot-com-gitlab-org-and-security-merge-request
|
||||
changes: *ci-patterns
|
||||
changes: *ci-qa-patterns
|
||||
allow_failure: true
|
||||
- <<: *if-dot-com-gitlab-org-and-security-merge-request
|
||||
changes: *qa-patterns
|
||||
|
@ -382,24 +440,95 @@
|
|||
###############
|
||||
# Rails rules #
|
||||
###############
|
||||
.rails:rules:ee-and-foss:
|
||||
.rails:rules:ee-and-foss-migration:
|
||||
rules:
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
- changes: *db-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-and-foss-unit:
|
||||
rules:
|
||||
- changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-and-foss-integration:
|
||||
rules:
|
||||
- changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-and-foss-system:
|
||||
rules:
|
||||
- changes: *code-backstage-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-and-foss-fast_spec_helper:
|
||||
rules:
|
||||
- changes: ["config/**/*"]
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:default-refs-code-backstage-qa:
|
||||
rules:
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-qa-patterns
|
||||
|
||||
.rails:rules:ee-only:
|
||||
.rails:rules:ee-only-migration:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
- changes: *db-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:as-if-foss:
|
||||
.rails:rules:ee-only-unit:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-only-integration:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-only-system:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- changes: *code-backstage-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:as-if-foss-migration:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-security-merge-request
|
||||
changes: *db-patterns
|
||||
- <<: *if-merge-request-title-as-if-foss
|
||||
- <<: *if-merge-request
|
||||
changes: *ci-patterns
|
||||
|
||||
.rails:rules:as-if-foss-unit:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-security-merge-request
|
||||
changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-as-if-foss
|
||||
- <<: *if-merge-request
|
||||
changes: *ci-patterns
|
||||
|
||||
.rails:rules:as-if-foss-integration:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-security-merge-request
|
||||
changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-as-if-foss
|
||||
- <<: *if-merge-request
|
||||
changes: *ci-patterns
|
||||
|
||||
.rails:rules:as-if-foss-system:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
|
@ -413,6 +542,7 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
- <<: *if-merge-request
|
||||
changes: *code-backstage-patterns
|
||||
- <<: *if-master-refs
|
||||
|
@ -434,6 +564,27 @@
|
|||
- <<: *if-merge-request
|
||||
changes: *code-backstage-patterns
|
||||
|
||||
.rails:rules:rspec-coverage:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-master-schedule-2-hourly
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:master-schedule-nightly--code-backstage:
|
||||
rules:
|
||||
- <<: *if-master-schedule-nightly
|
||||
- <<: *if-merge-request
|
||||
changes: [".gitlab/ci/rails.gitlab-ci.yml"]
|
||||
|
||||
.rails:rules:master-schedule-nightly--code-backstage-ee-only:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-master-schedule-nightly
|
||||
- <<: *if-merge-request
|
||||
changes: [".gitlab/ci/rails.gitlab-ci.yml"]
|
||||
|
||||
##################
|
||||
# Releases rules #
|
||||
##################
|
||||
|
@ -496,18 +647,12 @@
|
|||
################
|
||||
# Review rules #
|
||||
################
|
||||
.review:rules:build-qa-image:
|
||||
.review:rules:review-build-cng:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-dot-com-gitlab-org-and-security-merge-request
|
||||
changes: *code-qa-patterns
|
||||
- <<: *if-dot-com-gitlab-org-schedule
|
||||
|
||||
.review:rules:review-build-cng:
|
||||
rules:
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes: *ci-patterns
|
||||
changes: *ci-review-patterns
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes: *frontend-patterns
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
|
@ -521,7 +666,7 @@
|
|||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes: *ci-patterns
|
||||
changes: *ci-review-patterns
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes: *frontend-patterns
|
||||
allow_failure: true
|
||||
|
@ -544,7 +689,7 @@
|
|||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes: *ci-patterns
|
||||
changes: *ci-review-patterns
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes: *frontend-patterns
|
||||
allow_failure: true
|
||||
|
|
|
@ -9,6 +9,7 @@ cache gems:
|
|||
stage: test
|
||||
needs: ["setup-test-env"]
|
||||
variables:
|
||||
BUNDLE_INSTALL_FLAGS: --with=production --with=development --with=test --jobs=2 --path=vendor --retry=3 --quiet
|
||||
SETUP_DB: "false"
|
||||
script:
|
||||
- bundle package --all --all-platforms
|
||||
|
|
|
@ -4,11 +4,11 @@ lint-ci-gitlab:
|
|||
extends:
|
||||
- .default-retry
|
||||
- .yaml:rules
|
||||
image: sdesbure/yamllint:latest
|
||||
image: pipelinecomponents/yamllint:latest
|
||||
stage: test
|
||||
needs: []
|
||||
variables:
|
||||
LINT_PATHS: .gitlab-ci.yml .gitlab/ci lib/gitlab/ci/templates changelogs
|
||||
script:
|
||||
- '[[ ! -d "ee/" ]] || export LINT_PATHS="$LINT_PATHS ee/changelogs"'
|
||||
- yamllint $LINT_PATHS
|
||||
- yamllint -f colored $LINT_PATHS
|
||||
|
|
|
@ -43,7 +43,14 @@ https://about.gitlab.com/handbook/engineering/ux/ux-research-training/user-story
|
|||
|
||||
### Permissions and Security
|
||||
|
||||
<!-- What permissions are required to perform the described actions? Are they consistent with the existing permissions as documented for users, groups, and projects as appropriate? Is the proposed behavior consistent between the UI, API, and other access methods (e.g. email replies)?-->
|
||||
<!-- What permissions are required to perform the described actions? Are they consistent with the existing permissions as documented for users, groups, and projects as appropriate? Is the proposed behavior consistent between the UI, API, and other access methods (e.g. email replies)?
|
||||
Consider adding checkboxes and expectations of users with certain levels of membership https://docs.gitlab.com/ee/user/permissions.html
|
||||
* [ ] Add expected impact to members with no access (0)
|
||||
* [ ] Add expected impact to Guest (10) members
|
||||
* [ ] Add expected impact to Reporter (20) members
|
||||
* [ ] Add expected impact to Developer (30) members
|
||||
* [ ] Add expected impact to Maintainer (40) members
|
||||
* [ ] Add expected impact to Owner (50) members -->
|
||||
|
||||
### Documentation
|
||||
|
||||
|
|
|
@ -9,19 +9,17 @@ Set the title to: `Description of the original issue`
|
|||
## Prior to starting the security release work
|
||||
|
||||
- [ ] Read the [security process for developers] if you are not familiar with it.
|
||||
- [ ] Mark this [issue as related] to the Security Release tracking issue. You can find it on the topic of the `#releases` Slack channel.
|
||||
- [ ] Run `scripts/security-harness` in your local repository to prevent accidentally pushing to any remote besides `gitlab.com/gitlab-org/security`.
|
||||
- [ ] Mark this [issue as related] to the Security Release Tracking Issue. You can find it on the topic of the `#releases` Slack channel.
|
||||
- Fill out the [Links section](#links):
|
||||
- [ ] Next to **Issue on GitLab**, add a link to the `gitlab-org/gitlab` issue that describes the security vulnerability.
|
||||
- [ ] Next to **Security Release tracking issue**, add a link to the security release issue that will include this security issue.
|
||||
|
||||
## Development
|
||||
|
||||
- [ ] Run `scripts/security-harness` in your local repository to prevent accidentally pushing to any remote besides `gitlab.com/gitlab-org/security`.
|
||||
- [ ] Create a new branch prefixing it with `security-`.
|
||||
- [ ] Create a merge request targeting `master` on `gitlab.com/gitlab-org/security` and use the [Security Release merge request template].
|
||||
- [ ] Follow the same [code review process]: Assign to a reviewer, then to a maintainer.
|
||||
|
||||
After your merge request has been approved according to our [approval guidelines], you're ready to prepare the backports
|
||||
After your merge request has been approved according to our [approval guidelines] and by a team member of the AppSec team, you're ready to prepare the backports
|
||||
|
||||
## Backports
|
||||
|
||||
|
@ -41,7 +39,6 @@ After your merge request has been approved according to our [approval guidelines
|
|||
- [ ] Fill in any upgrade notes that users may need to take into account in the [details section](#details)
|
||||
- [ ] Add Yes/No and further details if needed to the migration and settings columns in the [details section](#details)
|
||||
- [ ] Add the nickname of the external user who found the issue (and/or HackerOne profile) to the Thanks row in the [details section](#details)
|
||||
- [ ] Once your `master` MR is merged, comment on the original security issue with a link to that MR indicating the issue is fixed.
|
||||
|
||||
## Summary
|
||||
|
||||
|
@ -50,7 +47,6 @@ After your merge request has been approved according to our [approval guidelines
|
|||
| Description | Link |
|
||||
| -------- | -------- |
|
||||
| Issue on [GitLab](https://gitlab.com/gitlab-org/gitlab/issues) | #TODO |
|
||||
| Security Release tracking issue | #TODO |
|
||||
|
||||
### Details
|
||||
|
||||
|
@ -64,7 +60,7 @@ After your merge request has been approved according to our [approval guidelines
|
|||
| Thanks | | |
|
||||
|
||||
[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/developer.md#secpick-script
|
||||
[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
|
||||
[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
|
||||
|
|
|
@ -45,9 +45,11 @@ All reviewers can help ensure accuracy, clarity, completeness, and adherence to
|
|||
|
||||
**2. Technical Writer**
|
||||
|
||||
- [ ] Optional: Technical writer review. If not requested for this MR, must be scheduled post-merge. To request for this MR, assign the writer listed for the applicable [DevOps stage](https://about.gitlab.com/handbook/product/categories/#devops-stages).
|
||||
- [ ] Add ~"Technical Writing" and `docs::` workflow label.
|
||||
- [ ] Technical writer review. If not requested for this MR, must be scheduled post-merge. To request for this MR, assign the writer listed for the applicable [DevOps stage](https://about.gitlab.com/handbook/product/product-categories/#devops-stages).
|
||||
- [ ] Ensure ~"Technical Writing", ~"documentation", and a `docs::` scoped label are added.
|
||||
- [ ] Add ~docs-only when the only files changed are under `doc/*`.
|
||||
- [ ] Add ~"tw::doing" when starting work on the MR.
|
||||
- [ ] Add ~"tw::finished" if Technical Writing team work on the MR is complete but it remains open.
|
||||
|
||||
**3. Maintainer**
|
||||
|
||||
|
|
|
@ -13,25 +13,33 @@ See [the general developer security release guidelines](https://gitlab.com/gitla
|
|||
## Developer checklist
|
||||
|
||||
- [ ] **On "Related issues" section, write down the [GitLab Security] issue it belongs to (i.e. `Related to <issue_id>`).**
|
||||
- [ ] Merge request targets `master`, or `X-Y-stable` for backports.
|
||||
- [ ] Merge request targets `master`, or a versioned stable branch (`X-Y-stable-ee`).
|
||||
- [ ] Milestone is set for the version this merge request applies to. A closed milestone can be assigned via [quick actions].
|
||||
- [ ] Title of this merge request is the same as for all backports.
|
||||
- [ ] A [CHANGELOG entry](https://docs.gitlab.com/ee/development/changelog.html) is added without a `merge_request` value, with `type` set to `security`
|
||||
- [ ] Assign to a reviewer and maintainer, per our [Code Review process].
|
||||
- [ ] A [CHANGELOG entry] is added without a `merge_request` value, with `type` set to `security`
|
||||
- [ ] For the MR targeting `master`:
|
||||
- [ ] Ask for a non-blocking review from the AppSec team member associated to the issue in the [Canonical repository](https://gitlab.com/gitlab-org/gitlab). If you're unsure who to ping, ask on `#sec-appsec` Slack channel.
|
||||
- [ ] Assign to a reviewer and maintainer, per our [Code Review process].
|
||||
- [ ] Ensure it's approved according to our [Approval Guidelines].
|
||||
- [ ] Merge request _must not_ close the corresponding security issue, _unless_ it targets `master`.
|
||||
- [ ] Ensure it's approved by an AppSec engineer.
|
||||
- If you're unsure who should approve, find the AppSec engineer associated to the issue in the [Canonical repository], or ask #sec-appsec on Slack.
|
||||
- Trigger the [`package-and-qa` build]. The docker image generated will be used by the AppSec engineer to validate the security vulnerability has been remediated.
|
||||
- [ ] Merge request _must_ close the corresponding security issue.
|
||||
- [ ] For a backport MR targeting a versioned stable branch (`X-Y-stable-ee`)
|
||||
- [ ] Ensure it's approved by a maintainer.
|
||||
|
||||
**Note:** Reviewer/maintainer should not be a Release Manager
|
||||
|
||||
## Maintainer checklist
|
||||
|
||||
- [ ] Correct milestone is applied and the title is matching across all backports
|
||||
- [ ] Assigned to `@gitlab-release-tools-bot` with passing CI pipelines and **when all backports including the MR targeting master are ready.**
|
||||
|
||||
/label ~security
|
||||
|
||||
[GitLab Security]: https://gitlab.com/gitlab-org/security/gitlab
|
||||
[approval guidelines]: https://docs.gitlab.com/ee/development/code_review.html#approval-guidelines
|
||||
[Code Review process]: https://docs.gitlab.com/ee/development/code_review.html
|
||||
[quick actions]: https://docs.gitlab.com/ee/user/project/quick_actions.html#quick-actions-for-issues-merge-requests-and-epics
|
||||
[CHANGELOG entry]: https://docs.gitlab.com/ee/development/changelog.html
|
||||
[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
|
||||
[Canonical repository]: https://gitlab.com/gitlab-org/gitlab
|
||||
[`package-and-qa` build]: https://docs.gitlab.com/ee/development/testing_guide/end_to_end/#using-the-package-and-qa-job
|
||||
|
|
|
@ -8,6 +8,7 @@ exclude:
|
|||
- 'spec/**/*'
|
||||
require:
|
||||
- './haml_lint/linter/no_plain_nodes.rb'
|
||||
- './haml_lint/linter/documentation_links.rb'
|
||||
|
||||
linters:
|
||||
AltText:
|
||||
|
@ -26,6 +27,12 @@ linters:
|
|||
enabled: false
|
||||
max_consecutive: 2
|
||||
|
||||
DocumentationLinks:
|
||||
enabled: true
|
||||
include:
|
||||
- 'app/views/**/*.haml'
|
||||
- 'ee/app/views/**/*.haml'
|
||||
|
||||
EmptyObjectReference:
|
||||
enabled: true
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ linters:
|
|||
- "app/views/admin/hooks/edit.html.haml"
|
||||
- "app/views/admin/logs/show.html.haml"
|
||||
- "app/views/admin/projects/_projects.html.haml"
|
||||
- "app/views/admin/projects/show.html.haml"
|
||||
- "app/views/admin/requests_profiles/index.html.haml"
|
||||
- "app/views/admin/runners/_runner.html.haml"
|
||||
- "app/views/admin/runners/index.html.haml"
|
||||
|
@ -57,7 +56,6 @@ linters:
|
|||
- "app/views/admin/spam_logs/_spam_log.html.haml"
|
||||
- "app/views/admin/spam_logs/index.html.haml"
|
||||
- "app/views/admin/system_info/show.html.haml"
|
||||
- "app/views/admin/users/_access_levels.html.haml"
|
||||
- "app/views/admin/users/_form.html.haml"
|
||||
- "app/views/admin/users/_head.html.haml"
|
||||
- "app/views/admin/users/_profile.html.haml"
|
||||
|
@ -280,7 +278,6 @@ linters:
|
|||
- "app/views/shared/_no_password.html.haml"
|
||||
- "app/views/shared/_ping_consent.html.haml"
|
||||
- "app/views/shared/_project_limit.html.haml"
|
||||
- "app/views/shared/boards/components/_board.html.haml"
|
||||
- "app/views/shared/boards/components/_sidebar.html.haml"
|
||||
- "app/views/shared/boards/components/sidebar/_due_date.html.haml"
|
||||
- "app/views/shared/boards/components/sidebar/_labels.html.haml"
|
||||
|
@ -358,7 +355,6 @@ linters:
|
|||
- "ee/app/views/notify/unapproved_merge_request_email.html.haml"
|
||||
- "ee/app/views/oauth/geo_auth/error.html.haml"
|
||||
- "ee/app/views/projects/commits/_mirror_status.html.haml"
|
||||
- "ee/app/views/projects/jobs/_shared_runner_limit_warning.html.haml"
|
||||
- "ee/app/views/projects/merge_requests/_approvals_count.html.haml"
|
||||
- "ee/app/views/projects/merge_requests/widget/open/_geo.html.haml"
|
||||
- "ee/app/views/projects/mirrors/_mirrored_repositories_count.html.haml"
|
||||
|
@ -372,7 +368,6 @@ linters:
|
|||
- "ee/app/views/projects/services/gitlab_slack_application/_slack_integration_form.html.haml"
|
||||
- "ee/app/views/projects/settings/slacks/edit.html.haml"
|
||||
- "ee/app/views/shared/_mirror_update_button.html.haml"
|
||||
- "ee/app/views/shared/boards/components/_list_weight.html.haml"
|
||||
- "ee/app/views/shared/epic/_search_bar.html.haml"
|
||||
- "ee/app/views/shared/issuable/_approvals.html.haml"
|
||||
- "ee/app/views/shared/issuable/_board_create_list_dropdown.html.haml"
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
"Jira Cloud",
|
||||
"Jira Server",
|
||||
"jQuery",
|
||||
"JSON",
|
||||
"JupyterHub",
|
||||
"Karma",
|
||||
"Kerberos",
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/public/
|
||||
/vendor/
|
||||
/tmp/
|
||||
doc/api/graphql/reference/gitlab_schema.graphql
|
||||
|
||||
# ignore stylesheets for now as this clashes with our linter
|
||||
*.css
|
||||
|
|
22
.rubocop.yml
22
.rubocop.yml
|
@ -308,6 +308,18 @@ Gitlab/Union:
|
|||
- 'spec/**/*'
|
||||
- 'ee/spec/**/*'
|
||||
|
||||
API/GrapeAPIInstance:
|
||||
Enabled: true
|
||||
Include:
|
||||
- 'lib/**/api/**/*.rb'
|
||||
- 'ee/**/api/**/*.rb'
|
||||
|
||||
API/GrapeArrayMissingCoerce:
|
||||
Enabled: true
|
||||
Include:
|
||||
- 'lib/**/api/**/*.rb'
|
||||
- 'ee/**/api/**/*.rb'
|
||||
|
||||
Cop/SidekiqOptionsQueue:
|
||||
Enabled: true
|
||||
Exclude:
|
||||
|
@ -316,6 +328,9 @@ Cop/SidekiqOptionsQueue:
|
|||
|
||||
Graphql/AuthorizeTypes:
|
||||
Enabled: true
|
||||
Include:
|
||||
- 'app/graphql/types/**/*'
|
||||
- 'ee/app/graphql/types/**/*'
|
||||
Exclude:
|
||||
- 'spec/**/*.rb'
|
||||
- 'ee/spec/**/*.rb'
|
||||
|
@ -450,10 +465,17 @@ Rails/TimeZone:
|
|||
- 'spec/models/**/*'
|
||||
- 'ee/app/models/**/*'
|
||||
- 'ee/spec/models/**/*'
|
||||
- 'app/workers/**/*'
|
||||
- 'spec/workers/**/*'
|
||||
- 'ee/app/workers/**/*'
|
||||
- 'ee/spec/workers/**/*'
|
||||
|
||||
|
||||
# WIP: See https://gitlab.com/gitlab-org/gitlab/-/issues/220040
|
||||
Rails/SaveBang:
|
||||
Enabled: true
|
||||
AllowImplicitReturn: false
|
||||
AllowedReceivers: ['ActionDispatch::TestRequest']
|
||||
Include:
|
||||
- 'spec/**/*.rb'
|
||||
- 'ee/spec/**/*.rb'
|
||||
|
|
|
@ -303,6 +303,11 @@ Performance/Detect:
|
|||
RSpec/ContextWording:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 626
|
||||
# Cop supports --auto-correct.
|
||||
RSpec/EmptyLineAfterLetBlock:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 1121
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle.
|
||||
|
@ -560,30 +565,6 @@ Style/GuardClause:
|
|||
Style/HashEachMethods:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
Style/HashTransformKeys:
|
||||
Exclude:
|
||||
- 'ee/app/models/vulnerabilities/occurrence.rb'
|
||||
- 'ee/spec/lib/gitlab/ci/templates/dependency_scanning_gitlab_ci_yaml_spec.rb'
|
||||
- 'lib/banzai/filter/commit_trailers_filter.rb'
|
||||
- 'lib/gitlab/analytics/cycle_analytics/stage_events.rb'
|
||||
|
||||
# Offense count: 10
|
||||
# Cop supports --auto-correct.
|
||||
Style/HashTransformValues:
|
||||
Exclude:
|
||||
- 'app/validators/addressable_url_validator.rb'
|
||||
- 'config/initializers/action_dispatch_journey_formatter.rb'
|
||||
- 'ee/app/helpers/compliance_management/compliance_framework/project_settings_helper.rb'
|
||||
- 'ee/app/services/packages/nuget/metadata_extraction_service.rb'
|
||||
- 'lib/gitlab/config/entry/configurable.rb'
|
||||
- 'lib/gitlab/config/entry/node.rb'
|
||||
- 'lib/gitlab/discussions_diff/file_collection.rb'
|
||||
- 'lib/gitlab/error_tracking.rb'
|
||||
- 'lib/rspec_flaky/flaky_examples_collection.rb'
|
||||
- 'spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb'
|
||||
|
||||
# Offense count: 31
|
||||
# Configuration parameters: AllowIfModifier.
|
||||
Style/IfInsideElse:
|
||||
|
@ -639,12 +620,122 @@ Style/Next:
|
|||
Style/NumericLiteralPrefix:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 255
|
||||
# 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:
|
||||
Enabled: false
|
||||
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
|
||||
# Cop supports --auto-correct.
|
||||
|
@ -690,18 +781,6 @@ Style/RedundantFreeze:
|
|||
Style/RedundantInterpolation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantParentheses:
|
||||
Exclude:
|
||||
- 'ee/app/models/ee/merge_request.rb'
|
||||
|
||||
# Offense count: 33
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowMultipleReturnValues.
|
||||
Style/RedundantReturn:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 801
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantSelf:
|
||||
|
@ -711,8 +790,8 @@ Style/RedundantSelf:
|
|||
# Cop supports --auto-correct.
|
||||
Style/RedundantSort:
|
||||
Exclude:
|
||||
- 'ee/app/presenters/packages/nuget/search_results_presenter.rb'
|
||||
- 'ee/spec/presenters/packages/nuget/search_results_presenter_spec.rb'
|
||||
- 'app/presenters/packages/nuget/search_results_presenter.rb'
|
||||
- 'spec/presenters/packages/nuget/search_results_presenter_spec.rb'
|
||||
|
||||
# Offense count: 120
|
||||
# Cop supports --auto-correct.
|
||||
|
@ -769,25 +848,20 @@ Style/StringLiteralsInInterpolation:
|
|||
Style/SymbolProc:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 1478
|
||||
# Offense count: 2362
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowImplicitReturn, AllowedReceivers.
|
||||
Rails/SaveBang:
|
||||
Exclude:
|
||||
- 'ee/spec/controllers/groups/epic_issues_controller_spec.rb'
|
||||
- 'ee/spec/controllers/groups/epic_links_controller_spec.rb'
|
||||
- 'ee/spec/controllers/groups/epics_controller_spec.rb'
|
||||
- 'ee/spec/controllers/groups/roadmap_controller_spec.rb'
|
||||
- 'ee/spec/controllers/projects/environments_controller_spec.rb'
|
||||
- 'ee/spec/controllers/projects/issues_controller_spec.rb'
|
||||
- 'ee/spec/controllers/projects/merge_requests/creations_controller_spec.rb'
|
||||
- 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
|
||||
- 'ee/spec/controllers/projects/service_desk_controller_spec.rb'
|
||||
- 'ee/spec/controllers/projects/subscriptions_controller_spec.rb'
|
||||
- 'ee/spec/controllers/projects/vulnerability_feedback_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'
|
||||
|
@ -796,13 +870,19 @@ Rails/SaveBang:
|
|||
- '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/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/lib/analytics/merge_request_metrics_calculator_spec.rb'
|
||||
|
@ -811,60 +891,84 @@ Rails/SaveBang:
|
|||
- 'ee/spec/lib/ee/gitlab/background_migration/move_epic_issues_after_epics_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/populate_any_approval_rule_for_merge_requests_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/populate_any_approval_rule_for_projects_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/prune_orphaned_geo_events_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/checks/push_rules/commit_check_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/ci/pipeline/quota/activity_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/auth/ldap/access_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/auth/o_auth/user_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/auth/saml/user_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/background_migration/fix_orphan_promoted_issues_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/elastic/search_results_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/email/handler/ee/service_desk_handler_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/cron_manager_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/jwt_request_decoder_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/oauth/session_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/git_access_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/import_export/group/relation_factory_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/mirror_spec.rb'
|
||||
- 'ee/spec/mailers/notify_spec.rb'
|
||||
- 'ee/spec/migrations/fix_any_approver_rule_for_projects_spec.rb'
|
||||
- 'ee/spec/migrations/geo/migrate_ci_job_artifacts_to_separate_registry_spec.rb'
|
||||
- 'ee/spec/migrations/geo/migrate_lfs_objects_to_separate_registry_spec.rb'
|
||||
- 'ee/spec/migrations/schedule_merge_request_any_approval_rule_migration_spec.rb'
|
||||
- 'ee/spec/migrations/schedule_project_any_approval_rule_migration_spec.rb'
|
||||
- 'ee/spec/models/application_setting_spec.rb'
|
||||
- 'ee/spec/models/approval_merge_request_rule_spec.rb'
|
||||
- 'ee/spec/models/approval_project_rule_spec.rb'
|
||||
- 'ee/spec/models/approval_state_spec.rb'
|
||||
- 'ee/spec/models/burndown_spec.rb'
|
||||
- 'ee/spec/models/ci/build_spec.rb'
|
||||
- 'ee/spec/models/ci/pipeline_spec.rb'
|
||||
- 'ee/spec/models/ci/subscriptions/project_spec.rb'
|
||||
- 'ee/spec/models/concerns/approver_migrate_hook_spec.rb'
|
||||
- 'ee/spec/models/concerns/deprecated_approvals_before_merge_spec.rb'
|
||||
- 'ee/spec/models/concerns/elastic/note_spec.rb'
|
||||
- 'ee/spec/models/ee/appearance_spec.rb'
|
||||
- 'ee/spec/models/ee/ci/job_artifact_spec.rb'
|
||||
- 'ee/spec/models/ee/protected_branch_spec.rb'
|
||||
- 'ee/spec/models/ee/protected_ref_access_spec.rb'
|
||||
- 'ee/spec/models/ee/protected_ref_spec.rb'
|
||||
- 'ee/spec/models/elasticsearch_indexed_namespace_spec.rb'
|
||||
- 'ee/spec/models/environment_spec.rb'
|
||||
- 'ee/spec/models/epic_spec.rb'
|
||||
- 'ee/spec/models/geo/project_registry_spec.rb'
|
||||
- 'ee/spec/models/geo_node_spec.rb'
|
||||
- 'ee/spec/models/geo_node_status_spec.rb'
|
||||
- 'ee/spec/models/gitlab_subscription_spec.rb'
|
||||
- 'ee/spec/models/group_spec.rb'
|
||||
- 'ee/spec/models/issue_spec.rb'
|
||||
- 'ee/spec/models/label_note_spec.rb'
|
||||
- 'ee/spec/models/lfs_object_spec.rb'
|
||||
- 'ee/spec/models/license_spec.rb'
|
||||
- 'ee/spec/models/merge_request_spec.rb'
|
||||
- 'ee/spec/models/merge_train_spec.rb'
|
||||
- 'ee/spec/models/operations/feature_flag_scope_spec.rb'
|
||||
- 'ee/spec/models/operations/feature_flag_spec.rb'
|
||||
- 'ee/spec/models/operations/feature_flags/strategy_spec.rb'
|
||||
- 'ee/spec/models/operations/feature_flags/user_list_spec.rb'
|
||||
- 'spec/models/packages/package_spec.rb'
|
||||
- 'ee/spec/models/project_ci_cd_setting_spec.rb'
|
||||
- 'ee/spec/models/project_services/github_service_spec.rb'
|
||||
- 'ee/spec/models/project_services/jenkins_service_spec.rb'
|
||||
- 'ee/spec/models/project_spec.rb'
|
||||
- 'ee/spec/models/protected_environment_spec.rb'
|
||||
- 'ee/spec/models/repository_spec.rb'
|
||||
- 'ee/spec/models/scim_identity_spec.rb'
|
||||
- 'ee/spec/models/scim_oauth_access_token_spec.rb'
|
||||
- 'ee/spec/models/upload_spec.rb'
|
||||
- 'ee/spec/models/user_preference_spec.rb'
|
||||
- 'ee/spec/models/user_spec.rb'
|
||||
- 'ee/spec/models/visible_approvable_spec.rb'
|
||||
- 'ee/spec/models/vulnerabilities/feedback_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/epic_presenter_spec.rb'
|
||||
- 'ee/spec/presenters/packages/conan/package_presenter_spec.rb'
|
||||
- 'ee/spec/requests/api/boards_spec.rb'
|
||||
- 'ee/spec/requests/api/epic_issues_spec.rb'
|
||||
- 'ee/spec/requests/api/epic_links_spec.rb'
|
||||
|
@ -876,7 +980,6 @@ Rails/SaveBang:
|
|||
- 'ee/spec/requests/api/groups_spec.rb'
|
||||
- 'ee/spec/requests/api/issues_spec.rb'
|
||||
- 'ee/spec/requests/api/ldap_group_links_spec.rb'
|
||||
- 'ee/spec/requests/api/maven_packages_spec.rb'
|
||||
- 'ee/spec/requests/api/merge_request_approval_rules_spec.rb'
|
||||
- 'ee/spec/requests/api/merge_request_approvals_spec.rb'
|
||||
- 'ee/spec/requests/api/merge_requests_spec.rb'
|
||||
|
@ -885,9 +988,15 @@ Rails/SaveBang:
|
|||
- 'ee/spec/requests/api/protected_branches_spec.rb'
|
||||
- 'ee/spec/requests/api/scim_spec.rb'
|
||||
- 'ee/spec/requests/api/todos_spec.rb'
|
||||
- 'ee/spec/requests/lfs_http_spec.rb'
|
||||
- 'ee/spec/services/approval_rules/finalize_service_spec.rb'
|
||||
- 'ee/spec/services/approval_rules/update_service_spec.rb'
|
||||
- 'ee/spec/services/ci/minutes/email_notification_service_spec.rb'
|
||||
- 'ee/spec/services/ci/process_build_service_spec.rb'
|
||||
- 'ee/spec/services/ci/register_job_service_spec.rb'
|
||||
- 'ee/spec/services/ee/boards/issues/create_service_spec.rb'
|
||||
- 'ee/spec/services/ee/boards/issues/list_service_spec.rb'
|
||||
- 'ee/spec/services/ee/boards/lists/list_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issuable/clone/attributes_rewriter_spec.rb'
|
||||
- 'ee/spec/services/ee/issuable/common_system_notes_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/update_service_spec.rb'
|
||||
|
@ -896,13 +1005,15 @@ Rails/SaveBang:
|
|||
- 'ee/spec/services/ee/notes/quick_actions_service_spec.rb'
|
||||
- 'ee/spec/services/ee/notification_service_spec.rb'
|
||||
- 'ee/spec/services/ee/resource_events/change_weight_service_spec.rb'
|
||||
- 'ee/spec/services/elastic/index_record_service_spec.rb'
|
||||
- 'ee/spec/services/epic_links/create_service_spec.rb'
|
||||
- 'ee/spec/services/epics/close_service_spec.rb'
|
||||
- 'ee/spec/services/epics/issue_promote_service_spec.rb'
|
||||
- 'ee/spec/services/epics/reopen_service_spec.rb'
|
||||
- 'ee/spec/services/epics/tree_reorder_service_spec.rb'
|
||||
- 'ee/spec/services/epics/update_dates_service_spec.rb'
|
||||
- 'ee/spec/services/epics/update_service_spec.rb'
|
||||
- 'ee/spec/services/geo/blob_verification_secondary_service_spec.rb'
|
||||
- 'ee/spec/services/geo/files_expire_service_spec.rb'
|
||||
- 'ee/spec/services/geo/metrics_update_service_spec.rb'
|
||||
- 'ee/spec/services/geo/registry_consistency_service_spec.rb'
|
||||
- 'ee/spec/services/geo/repository_verification_secondary_service_spec.rb'
|
||||
|
@ -911,8 +1022,11 @@ Rails/SaveBang:
|
|||
- 'ee/spec/services/lfs/unlock_file_service_spec.rb'
|
||||
- 'ee/spec/services/merge_requests/approval_service_spec.rb'
|
||||
- 'ee/spec/services/merge_requests/remove_approval_service_spec.rb'
|
||||
- 'ee/spec/services/merge_requests/update_blocks_service_spec.rb'
|
||||
- 'ee/spec/services/merge_trains/refresh_merge_request_service_spec.rb'
|
||||
- 'ee/spec/services/projects/after_rename_service_spec.rb'
|
||||
- 'ee/spec/services/projects/import_export/export_service_spec.rb'
|
||||
- 'ee/spec/services/projects/update_mirror_service_spec.rb'
|
||||
- 'ee/spec/services/projects/update_service_spec.rb'
|
||||
- 'ee/spec/services/quick_actions/interpret_service_spec.rb'
|
||||
- 'ee/spec/services/slash_commands/global_slack_handler_spec.rb'
|
||||
|
@ -920,50 +1034,92 @@ Rails/SaveBang:
|
|||
- 'ee/spec/services/status_page/trigger_publish_service_spec.rb'
|
||||
- 'ee/spec/services/todo_service_spec.rb'
|
||||
- 'ee/spec/services/update_build_minutes_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/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/graphql/geo/geo_registries_resolver_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/lib/analytics/common_merge_request_metrics_refresh_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/models/concerns/replicator_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/models/elasticsearch_indexed_container_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/models/geo_framework_registry_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/models/member_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/models/mentionable_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/policies/protected_environments_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/requests/api/graphql/geo/registries_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/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/clear_shared_runners_minutes_worker_spec.rb'
|
||||
- 'ee/spec/workers/create_github_webhook_worker_spec.rb'
|
||||
- 'ee/spec/workers/elastic_indexer_worker_spec.rb'
|
||||
- 'ee/spec/workers/elastic_namespace_rollout_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/container_repository_sync_dispatch_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/file_download_dispatch_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/prune_event_log_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/registry_sync_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/repository_shard_sync_worker_spec.rb'
|
||||
- 'ee/spec/workers/repository_import_worker_spec.rb'
|
||||
- 'ee/spec/workers/update_all_mirrors_worker_spec.rb'
|
||||
- 'qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb'
|
||||
- 'qa/qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_http_spec.rb'
|
||||
- 'qa/qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_ssh_with_key_spec.rb'
|
||||
- 'spec/controllers/abuse_reports_controller_spec.rb'
|
||||
- 'spec/controllers/admin/impersonations_controller_spec.rb'
|
||||
- 'spec/controllers/admin/runners_controller_spec.rb'
|
||||
- 'spec/controllers/admin/services_controller_spec.rb'
|
||||
- 'spec/controllers/boards/issues_controller_spec.rb'
|
||||
- 'spec/controllers/groups/milestones_controller_spec.rb'
|
||||
- 'spec/controllers/groups/runners_controller_spec.rb'
|
||||
- 'spec/controllers/groups/uploads_controller_spec.rb'
|
||||
- 'spec/controllers/groups_controller_spec.rb'
|
||||
- 'spec/controllers/oauth/authorizations_controller_spec.rb'
|
||||
- 'spec/controllers/omniauth_callbacks_controller_spec.rb'
|
||||
- 'spec/controllers/profiles/emails_controller_spec.rb'
|
||||
- 'spec/controllers/profiles/notifications_controller_spec.rb'
|
||||
- 'spec/controllers/projects/artifacts_controller_spec.rb'
|
||||
- 'spec/controllers/projects/cycle_analytics/events_controller_spec.rb'
|
||||
- 'spec/controllers/projects/cycle_analytics_controller_spec.rb'
|
||||
- 'spec/controllers/projects/discussions_controller_spec.rb'
|
||||
- 'spec/controllers/projects/forks_controller_spec.rb'
|
||||
- 'spec/controllers/projects/group_links_controller_spec.rb'
|
||||
- 'spec/controllers/projects/imports_controller_spec.rb'
|
||||
- 'spec/controllers/projects/issues_controller_spec.rb'
|
||||
- 'spec/controllers/projects/labels_controller_spec.rb'
|
||||
- 'spec/controllers/projects/merge_requests_controller_spec.rb'
|
||||
- 'spec/controllers/projects/milestones_controller_spec.rb'
|
||||
- 'spec/controllers/projects/notes_controller_spec.rb'
|
||||
- 'spec/controllers/projects/pipelines_controller_spec.rb'
|
||||
- 'spec/controllers/projects/releases/evidences_controller_spec.rb'
|
||||
- 'spec/controllers/projects/runners_controller_spec.rb'
|
||||
- 'spec/controllers/projects/starrers_controller_spec.rb'
|
||||
- 'spec/controllers/projects/uploads_controller_spec.rb'
|
||||
- 'spec/controllers/projects_controller_spec.rb'
|
||||
- 'spec/controllers/sent_notifications_controller_spec.rb'
|
||||
- 'spec/controllers/sessions_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/features/admin/admin_appearance_spec.rb'
|
||||
- 'spec/features/admin/admin_labels_spec.rb'
|
||||
- 'spec/features/admin/admin_mode/login_spec.rb'
|
||||
- 'spec/features/admin/admin_runners_spec.rb'
|
||||
- 'spec/features/admin/admin_sees_project_statistics_spec.rb'
|
||||
- 'spec/features/admin/admin_sees_projects_statistics_spec.rb'
|
||||
- 'spec/features/admin/admin_users_impersonation_tokens_spec.rb'
|
||||
- 'spec/features/admin/admin_users_spec.rb'
|
||||
- 'spec/features/boards/sidebar_spec.rb'
|
||||
|
@ -975,6 +1131,7 @@ Rails/SaveBang:
|
|||
- 'spec/features/dashboard/projects_spec.rb'
|
||||
- 'spec/features/error_tracking/user_sees_error_index_spec.rb'
|
||||
- 'spec/features/groups/members/request_access_spec.rb'
|
||||
- 'spec/features/issuables/close_reopen_report_toggle_spec.rb'
|
||||
- 'spec/features/issues/bulk_assignment_labels_spec.rb'
|
||||
- 'spec/features/issues/gfm_autocomplete_spec.rb'
|
||||
- 'spec/features/issues/issue_sidebar_spec.rb'
|
||||
|
@ -989,30 +1146,45 @@ Rails/SaveBang:
|
|||
- '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/password_spec.rb'
|
||||
- 'spec/features/profiles/personal_access_tokens_spec.rb'
|
||||
- 'spec/features/projects/features_visibility_spec.rb'
|
||||
- 'spec/features/projects/fork_spec.rb'
|
||||
- 'spec/features/projects/jobs/permissions_spec.rb'
|
||||
- 'spec/features/projects/jobs_spec.rb'
|
||||
- 'spec/features/projects/members/user_requests_access_spec.rb'
|
||||
- 'spec/features/projects/pages_lets_encrypt_spec.rb'
|
||||
- 'spec/features/projects/pages_spec.rb'
|
||||
- 'spec/features/projects/pipelines/pipeline_spec.rb'
|
||||
- 'spec/features/projects/pipelines/pipelines_spec.rb'
|
||||
- 'spec/features/projects/remote_mirror_spec.rb'
|
||||
- 'spec/features/projects/services/user_activates_slack_notifications_spec.rb'
|
||||
- 'spec/features/projects/settings/access_tokens_spec.rb'
|
||||
- 'spec/features/projects/show/user_sees_deletion_failure_message_spec.rb'
|
||||
- 'spec/features/projects/user_sees_sidebar_spec.rb'
|
||||
- 'spec/features/projects/wiki/user_updates_wiki_page_spec.rb'
|
||||
- 'spec/features/projects/wiki/user_views_wiki_page_spec.rb'
|
||||
- 'spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb'
|
||||
- 'spec/features/runners_spec.rb'
|
||||
- 'spec/features/security/project/internal_access_spec.rb'
|
||||
- 'spec/features/security/project/private_access_spec.rb'
|
||||
- 'spec/features/security/project/public_access_spec.rb'
|
||||
- 'spec/features/users/login_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'
|
||||
|
@ -1021,6 +1193,11 @@ Rails/SaveBang:
|
|||
- 'spec/graphql/mutations/merge_requests/set_wip_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'
|
||||
|
@ -1030,18 +1207,23 @@ Rails/SaveBang:
|
|||
- 'spec/lib/after_commit_queue_spec.rb'
|
||||
- 'spec/lib/backup/manager_spec.rb'
|
||||
- 'spec/lib/banzai/reference_parser/external_issue_parser_spec.rb'
|
||||
- 'spec/lib/banzai/reference_redactor_spec.rb'
|
||||
- 'spec/lib/gitlab/alerting/alert_spec.rb'
|
||||
- 'spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb'
|
||||
- 'spec/lib/gitlab/auth/ldap/user_spec.rb'
|
||||
- 'spec/lib/gitlab/auth/o_auth/user_spec.rb'
|
||||
- 'spec/lib/gitlab/auth/saml/user_spec.rb'
|
||||
- 'spec/lib/gitlab/auth_spec.rb'
|
||||
- 'spec/lib/gitlab/authorized_keys_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/backfill_project_repositories_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/digest_column_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/encrypt_columns_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb'
|
||||
|
@ -1056,82 +1238,130 @@ Rails/SaveBang:
|
|||
- 'spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/remove_restricted_todos_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/reset_merge_status_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb'
|
||||
- 'spec/lib/gitlab/bitbucket_server_import/importer_spec.rb'
|
||||
- 'spec/lib/gitlab/ci/ansi2json/style_spec.rb'
|
||||
- 'spec/lib/gitlab/ci/status/build/common_spec.rb'
|
||||
- 'spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb'
|
||||
- 'spec/lib/gitlab/cycle_analytics/events_spec.rb'
|
||||
- 'spec/lib/gitlab/database/custom_structure_spec.rb'
|
||||
- 'spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb'
|
||||
- 'spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb'
|
||||
- 'spec/lib/gitlab/email/handler/create_note_handler_spec.rb'
|
||||
- 'spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb'
|
||||
- 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb'
|
||||
- 'spec/lib/gitlab/git/object_pool_spec.rb'
|
||||
- 'spec/lib/gitlab/git/remote_mirror_spec.rb'
|
||||
- 'spec/lib/gitlab/git/repository_spec.rb'
|
||||
- 'spec/lib/gitlab/git_access_spec.rb'
|
||||
- 'spec/lib/gitlab/gitaly_client/object_pool_service_spec.rb'
|
||||
- 'spec/lib/gitlab/gitaly_client/repository_service_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/avatar_saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/base/relation_factory_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/design_repo_restorer_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/fork_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/group/relation_factory_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/group/tree_saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/importer_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/lfs_restorer_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/lfs_saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/members_mapper_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/project/relation_factory_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/project/tree_saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/repo_restorer_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/snippet_repo_saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/snippets_repo_saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/uploads_manager_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/uploads_saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/wiki_restorer_spec.rb'
|
||||
- 'spec/lib/gitlab/legacy_github_import/importer_spec.rb'
|
||||
- 'spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb'
|
||||
- 'spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb'
|
||||
- 'spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb'
|
||||
- 'spec/lib/gitlab/lets_encrypt/client_spec.rb'
|
||||
- 'spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb'
|
||||
- 'spec/lib/gitlab/markdown_cache/redis/store_spec.rb'
|
||||
- 'spec/lib/gitlab/middleware/go_spec.rb'
|
||||
- 'spec/lib/gitlab/shard_health_cache_spec.rb'
|
||||
- 'spec/lib/mattermost/command_spec.rb'
|
||||
- 'spec/lib/mattermost/session_spec.rb'
|
||||
- 'spec/lib/mattermost/team_spec.rb'
|
||||
- 'spec/mailers/notify_spec.rb'
|
||||
- 'spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb'
|
||||
- 'spec/migrations/20200122123016_backfill_project_settings_spec.rb'
|
||||
- 'spec/migrations/20200123155929_remove_invalid_jira_data_spec.rb'
|
||||
- 'spec/migrations/20200127090233_remove_invalid_issue_tracker_data_spec.rb'
|
||||
- 'spec/migrations/20200130145430_reschedule_migrate_issue_trackers_data_spec.rb'
|
||||
- 'spec/migrations/20200313203550_remove_orphaned_chat_names_spec.rb'
|
||||
- 'spec/migrations/20200406102120_backfill_deployment_clusters_from_deployments_spec.rb'
|
||||
- 'spec/migrations/20200526115436_dedup_mr_metrics_spec.rb'
|
||||
- 'spec/migrations/add_deploy_token_type_to_deploy_tokens_spec.rb'
|
||||
- 'spec/migrations/add_incident_settings_to_all_existing_projects_spec.rb'
|
||||
- 'spec/migrations/add_unique_constraint_to_approvals_user_id_and_merge_request_id_spec.rb'
|
||||
- 'spec/migrations/backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table_spec.rb'
|
||||
- 'spec/migrations/backfill_imported_snippet_repositories_spec.rb'
|
||||
- 'spec/migrations/backfill_releases_table_updated_at_and_add_not_null_constraints_to_timestamps_spec.rb'
|
||||
- 'spec/migrations/backfill_snippet_repositories_spec.rb'
|
||||
- 'spec/migrations/encrypt_plaintext_attributes_on_application_settings_spec.rb'
|
||||
- 'spec/migrations/enqueue_reset_merge_status_second_run_spec.rb'
|
||||
- 'spec/migrations/enqueue_reset_merge_status_spec.rb'
|
||||
- 'spec/migrations/fill_file_store_lfs_objects_spec.rb'
|
||||
- 'spec/migrations/fill_store_uploads_spec.rb'
|
||||
- 'spec/migrations/fix_null_type_labels_spec.rb'
|
||||
- 'spec/migrations/fix_pool_repository_source_project_id_spec.rb'
|
||||
- 'spec/migrations/fix_projects_without_project_feature_spec.rb'
|
||||
- 'spec/migrations/fix_projects_without_prometheus_services_spec.rb'
|
||||
- 'spec/migrations/fix_wrong_pages_access_level_spec.rb'
|
||||
- 'spec/migrations/insert_project_hooks_plan_limits_spec.rb'
|
||||
- 'spec/migrations/migrate_auto_dev_ops_domain_to_cluster_domain_spec.rb'
|
||||
- 'spec/migrations/move_limits_from_plans_spec.rb'
|
||||
- 'spec/migrations/populate_project_statistics_packages_size_spec.rb'
|
||||
- 'spec/migrations/schedule_link_lfs_objects_projects_spec.rb'
|
||||
- 'spec/migrations/schedule_populate_merge_request_assignees_table_spec.rb'
|
||||
- 'spec/migrations/seed_repository_storages_weighted_spec.rb'
|
||||
- 'spec/models/appearance_spec.rb'
|
||||
- 'spec/models/application_record_spec.rb'
|
||||
- 'spec/models/application_setting_spec.rb'
|
||||
- 'spec/models/ci/build_metadata_spec.rb'
|
||||
- 'spec/models/ci/build_spec.rb'
|
||||
- 'spec/models/ci/build_trace_chunk_spec.rb'
|
||||
- 'spec/models/ci/instance_variable_spec.rb'
|
||||
- 'spec/models/ci/legacy_stage_spec.rb'
|
||||
- 'spec/models/ci/persistent_ref_spec.rb'
|
||||
- 'spec/models/ci/pipeline_spec.rb'
|
||||
- 'spec/models/ci/runner_spec.rb'
|
||||
- 'spec/models/clusters/applications/helm_spec.rb'
|
||||
- 'spec/models/commit_spec.rb'
|
||||
- 'spec/models/commit_status_spec.rb'
|
||||
- 'spec/models/concerns/avatarable_spec.rb'
|
||||
- 'spec/models/concerns/bulk_insertable_associations_spec.rb'
|
||||
- 'spec/models/concerns/cache_markdown_field_spec.rb'
|
||||
- 'spec/models/concerns/case_sensitivity_spec.rb'
|
||||
- 'spec/models/concerns/featurable_spec.rb'
|
||||
- 'spec/models/concerns/issuable_spec.rb'
|
||||
- 'spec/models/concerns/mentionable_spec.rb'
|
||||
- 'spec/models/concerns/milestoneable_spec.rb'
|
||||
- 'spec/models/concerns/milestoneish_spec.rb'
|
||||
- 'spec/models/concerns/routable_spec.rb'
|
||||
- 'spec/models/concerns/subscribable_spec.rb'
|
||||
- 'spec/models/concerns/token_authenticatable_spec.rb'
|
||||
- 'spec/models/container_repository_spec.rb'
|
||||
- 'spec/models/cycle_analytics/issue_spec.rb'
|
||||
- 'spec/models/cycle_analytics/plan_spec.rb'
|
||||
- 'spec/models/cycle_analytics/production_spec.rb'
|
||||
- 'spec/models/deploy_keys_project_spec.rb'
|
||||
- 'spec/models/deploy_token_spec.rb'
|
||||
- 'spec/models/deployment_spec.rb'
|
||||
- 'spec/models/design_management/version_spec.rb'
|
||||
- 'spec/models/diff_discussion_spec.rb'
|
||||
- 'spec/models/diff_note_spec.rb'
|
||||
- 'spec/models/email_spec.rb'
|
||||
- 'spec/models/environment_spec.rb'
|
||||
|
@ -1143,7 +1373,9 @@ Rails/SaveBang:
|
|||
- 'spec/models/hooks/system_hook_spec.rb'
|
||||
- 'spec/models/hooks/web_hook_spec.rb'
|
||||
- 'spec/models/identity_spec.rb'
|
||||
- 'spec/models/issue/metrics_spec.rb'
|
||||
- 'spec/models/issue_spec.rb'
|
||||
- 'spec/models/jira_import_state_spec.rb'
|
||||
- 'spec/models/key_spec.rb'
|
||||
- 'spec/models/lfs_objects_project_spec.rb'
|
||||
- 'spec/models/member_spec.rb'
|
||||
|
@ -1155,12 +1387,18 @@ Rails/SaveBang:
|
|||
- 'spec/models/note_spec.rb'
|
||||
- 'spec/models/notification_setting_spec.rb'
|
||||
- 'spec/models/pages_domain_spec.rb'
|
||||
- 'spec/models/project_auto_devops_spec.rb'
|
||||
- 'spec/models/project_feature_spec.rb'
|
||||
- 'spec/models/project_services/bamboo_service_spec.rb'
|
||||
- 'spec/models/project_services/buildkite_service_spec.rb'
|
||||
- 'spec/models/project_services/jira_service_spec.rb'
|
||||
- 'spec/models/project_services/packagist_service_spec.rb'
|
||||
- 'spec/models/project_services/pipelines_email_service_spec.rb'
|
||||
- 'spec/models/project_services/teamcity_service_spec.rb'
|
||||
- 'spec/models/project_spec.rb'
|
||||
- 'spec/models/project_team_spec.rb'
|
||||
- 'spec/models/protectable_dropdown_spec.rb'
|
||||
- 'spec/models/redirect_route_spec.rb'
|
||||
- 'spec/models/release_spec.rb'
|
||||
- 'spec/models/remote_mirror_spec.rb'
|
||||
- 'spec/models/resource_milestone_event_spec.rb'
|
||||
|
@ -1171,47 +1409,77 @@ Rails/SaveBang:
|
|||
- 'spec/models/upload_spec.rb'
|
||||
- 'spec/models/user_preference_spec.rb'
|
||||
- 'spec/models/user_spec.rb'
|
||||
- 'spec/models/user_status_spec.rb'
|
||||
- 'spec/models/wiki_page/meta_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/trigger_presenter_spec.rb'
|
||||
- 'spec/presenters/packages/conan/package_presenter_spec.rb'
|
||||
- 'spec/requests/api/access_requests_spec.rb'
|
||||
- 'spec/requests/api/boards_spec.rb'
|
||||
- 'spec/requests/api/branches_spec.rb'
|
||||
- 'spec/requests/api/ci/runner_spec.rb'
|
||||
- 'spec/requests/api/commit_statuses_spec.rb'
|
||||
- 'spec/requests/api/conan_packages_spec.rb'
|
||||
- 'spec/requests/api/deployments_spec.rb'
|
||||
- 'spec/requests/api/environments_spec.rb'
|
||||
- 'spec/requests/api/go_proxy_spec.rb'
|
||||
- 'spec/requests/api/graphql/mutations/merge_requests/set_labels_spec.rb'
|
||||
- 'spec/requests/api/graphql/user_query_spec.rb'
|
||||
- 'spec/requests/api/graphql_spec.rb'
|
||||
- 'spec/requests/api/group_import_spec.rb'
|
||||
- 'spec/requests/api/group_milestones_spec.rb'
|
||||
- 'spec/requests/api/internal/base_spec.rb'
|
||||
- 'spec/requests/api/issues/get_group_issues_spec.rb'
|
||||
- 'spec/requests/api/issues/post_projects_issues_spec.rb'
|
||||
- 'spec/requests/api/jobs_spec.rb'
|
||||
- 'spec/requests/api/labels_spec.rb'
|
||||
- 'spec/requests/api/maven_packages_spec.rb'
|
||||
- 'spec/requests/api/members_spec.rb'
|
||||
- 'spec/requests/api/merge_request_diffs_spec.rb'
|
||||
- 'spec/requests/api/merge_requests_spec.rb'
|
||||
- 'spec/requests/api/notes_spec.rb'
|
||||
- 'spec/requests/api/pages/internal_access_spec.rb'
|
||||
- 'spec/requests/api/pages/private_access_spec.rb'
|
||||
- 'spec/requests/api/pages/public_access_spec.rb'
|
||||
- 'spec/requests/api/pipeline_schedules_spec.rb'
|
||||
- 'spec/requests/api/project_import_spec.rb'
|
||||
- 'spec/requests/api/project_milestones_spec.rb'
|
||||
- 'spec/requests/api/projects_spec.rb'
|
||||
- 'spec/requests/api/runners_spec.rb'
|
||||
- 'spec/requests/api/snippets_spec.rb'
|
||||
- 'spec/requests/git_http_spec.rb'
|
||||
- 'spec/requests/lfs_http_spec.rb'
|
||||
- 'spec/requests/profiles/notifications_controller_spec.rb'
|
||||
- 'spec/requests/projects/cycle_analytics_events_spec.rb'
|
||||
- 'spec/serializers/environment_status_entity_spec.rb'
|
||||
- 'spec/serializers/issue_entity_spec.rb'
|
||||
- 'spec/serializers/job_entity_spec.rb'
|
||||
- 'spec/serializers/merge_request_poll_widget_entity_spec.rb'
|
||||
- 'spec/serializers/merge_request_widget_entity_spec.rb'
|
||||
- 'spec/services/auth/container_registry_authentication_service_spec.rb'
|
||||
- 'spec/services/auto_merge/base_service_spec.rb'
|
||||
- 'spec/services/auto_merge_service_spec.rb'
|
||||
- 'spec/services/ci/create_cross_project_pipeline_service_spec.rb'
|
||||
- 'spec/services/ci/create_pipeline_service_spec.rb'
|
||||
- 'spec/services/ci/register_job_service_spec.rb'
|
||||
- 'spec/services/ci/retry_build_service_spec.rb'
|
||||
- 'spec/services/ci/update_runner_service_spec.rb'
|
||||
- 'spec/services/clusters/update_service_spec.rb'
|
||||
- 'spec/services/deployments/after_create_service_spec.rb'
|
||||
- 'spec/services/design_management/generate_image_versions_service_spec.rb'
|
||||
- 'spec/services/discussions/resolve_service_spec.rb'
|
||||
- 'spec/services/draft_notes/destroy_service_spec.rb'
|
||||
- 'spec/services/emails/confirm_service_spec.rb'
|
||||
- 'spec/services/groups/destroy_service_spec.rb'
|
||||
- 'spec/services/groups/import_export/import_service_spec.rb'
|
||||
- 'spec/services/issuable/bulk_update_service_spec.rb'
|
||||
- 'spec/services/issuable/clone/attributes_rewriter_spec.rb'
|
||||
- 'spec/services/issuable/common_system_notes_service_spec.rb'
|
||||
- 'spec/services/issues/close_service_spec.rb'
|
||||
|
@ -1221,6 +1489,7 @@ Rails/SaveBang:
|
|||
- 'spec/services/issues/update_service_spec.rb'
|
||||
- 'spec/services/labels/promote_service_spec.rb'
|
||||
- 'spec/services/members/destroy_service_spec.rb'
|
||||
- 'spec/services/merge_requests/build_service_spec.rb'
|
||||
- 'spec/services/merge_requests/conflicts/list_service_spec.rb'
|
||||
- 'spec/services/merge_requests/create_service_spec.rb'
|
||||
- 'spec/services/merge_requests/merge_service_spec.rb'
|
||||
|
@ -1230,11 +1499,16 @@ Rails/SaveBang:
|
|||
- 'spec/services/milestones/destroy_service_spec.rb'
|
||||
- 'spec/services/milestones/promote_service_spec.rb'
|
||||
- 'spec/services/milestones/transfer_service_spec.rb'
|
||||
- 'spec/services/notes/create_service_spec.rb'
|
||||
- 'spec/services/notification_recipients/build_service_spec.rb'
|
||||
- 'spec/services/notification_service_spec.rb'
|
||||
- 'spec/services/packages/conan/create_package_file_service_spec.rb'
|
||||
- 'spec/services/projects/after_rename_service_spec.rb'
|
||||
- 'spec/services/projects/autocomplete_service_spec.rb'
|
||||
- 'spec/services/projects/create_service_spec.rb'
|
||||
- 'spec/services/projects/destroy_service_spec.rb'
|
||||
- 'spec/services/projects/fork_service_spec.rb'
|
||||
- 'spec/services/projects/hashed_storage/base_attachment_service_spec.rb'
|
||||
- 'spec/services/projects/move_access_service_spec.rb'
|
||||
- 'spec/services/projects/move_project_group_links_service_spec.rb'
|
||||
- 'spec/services/projects/overwrite_project_service_spec.rb'
|
||||
|
@ -1243,6 +1517,8 @@ Rails/SaveBang:
|
|||
- 'spec/services/projects/update_pages_service_spec.rb'
|
||||
- 'spec/services/projects/update_service_spec.rb'
|
||||
- 'spec/services/quick_actions/interpret_service_spec.rb'
|
||||
- 'spec/services/reset_project_cache_service_spec.rb'
|
||||
- 'spec/services/resource_events/change_milestone_service_spec.rb'
|
||||
- 'spec/services/system_hooks_service_spec.rb'
|
||||
- 'spec/services/system_note_service_spec.rb'
|
||||
- 'spec/services/system_notes/issuables_service_spec.rb'
|
||||
|
@ -1250,42 +1526,71 @@ Rails/SaveBang:
|
|||
- 'spec/services/todos/destroy/confidential_issue_service_spec.rb'
|
||||
- 'spec/services/users/destroy_service_spec.rb'
|
||||
- 'spec/services/users/repair_ldap_blocked_service_spec.rb'
|
||||
- 'spec/services/verify_pages_domain_service_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_action_cable_connection.rb'
|
||||
- 'spec/support/helpers/stub_object_storage.rb'
|
||||
- 'spec/support/migrations_helpers/cluster_helpers.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/finders/group_projects_finder_shared_contexts.rb'
|
||||
- 'spec/support/shared_contexts/mailers/notify_shared_context.rb'
|
||||
- 'spec/support/shared_examples/controllers/cache_control_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/features/editable_merge_request_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/models/chat_slash_commands_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/models/cluster_application_helm_cert_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/models/concerns/limitable_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/models/concerns/timebox_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/models/diff_note_after_commit_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/models/member_shared_examples.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/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/update_project_statistics_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/models/with_uploads_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/policies/project_policy_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/award_emoji_todo_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/boards_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/serializers/note_entity_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/services/common_system_notes_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/services/issuable_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/services/wiki_pages/destroy_service_shared_examples.rb'
|
||||
- 'spec/tasks/gitlab/web_hook_rake_spec.rb'
|
||||
- 'spec/uploaders/file_uploader_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'
|
||||
|
|
742
CHANGELOG.md
742
CHANGELOG.md
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,7 @@ require_relative 'lib/gitlab/danger/request_helper'
|
|||
danger.import_plugin('danger/plugins/helper.rb')
|
||||
danger.import_plugin('danger/plugins/roulette.rb')
|
||||
danger.import_plugin('danger/plugins/changelog.rb')
|
||||
danger.import_plugin('danger/plugins/sidekiq_queues.rb')
|
||||
|
||||
return if helper.release_automation?
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
13.1.6
|
||||
13.2.1
|
||||
|
|
|
@ -1 +1 @@
|
|||
2.3.0
|
||||
2.4.0
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.18.0
|
||||
1.21.0
|
||||
|
|
|
@ -1 +1 @@
|
|||
8.35.0
|
||||
8.37.0
|
||||
|
|
32
Gemfile
32
Gemfile
|
@ -19,7 +19,7 @@ gem 'default_value_for', '~> 3.3.0'
|
|||
gem 'pg', '~> 1.1'
|
||||
|
||||
gem 'rugged', '~> 0.28'
|
||||
gem 'grape-path-helpers', '~> 1.2'
|
||||
gem 'grape-path-helpers', '~> 1.3'
|
||||
|
||||
gem 'faraday', '~> 0.12'
|
||||
gem 'marginalia', '~> 1.8.0'
|
||||
|
@ -66,7 +66,7 @@ gem 'u2f', '~> 0.2.1'
|
|||
gem 'validates_hostname', '~> 1.0.10'
|
||||
gem 'rubyzip', '~> 2.0.0', require: 'zip'
|
||||
# GitLab Pages letsencrypt support
|
||||
gem 'acme-client', '~> 2.0.5'
|
||||
gem 'acme-client', '~> 2.0', '>= 2.0.6'
|
||||
|
||||
# Browser detection
|
||||
gem 'browser', '~> 2.5'
|
||||
|
@ -81,7 +81,9 @@ gem 'gitlab_omniauth-ldap', '~> 2.1.1', require: 'omniauth-ldap'
|
|||
gem 'net-ldap'
|
||||
|
||||
# API
|
||||
gem 'grape', '~> 1.1.0'
|
||||
# Locked at Grape v1.4.0 until https://github.com/ruby-grape/grape/pull/2088 is merged
|
||||
# Remove config/initializers/grape_patch.rb
|
||||
gem 'grape', '= 1.4.0'
|
||||
gem 'grape-entity', '~> 0.7.1'
|
||||
gem 'rack-cors', '~> 1.0.6', require: 'rack/cors'
|
||||
|
||||
|
@ -140,6 +142,7 @@ gem 'deckar01-task_list', '2.3.1'
|
|||
gem 'gitlab-markup', '~> 1.7.1'
|
||||
gem 'github-markup', '~> 1.7.0', require: 'github/markup'
|
||||
gem 'commonmarker', '~> 0.20'
|
||||
gem 'kramdown', '~> 2.2.1'
|
||||
gem 'RedCloth', '~> 4.3.2'
|
||||
gem 'rdoc', '~> 6.1.2'
|
||||
gem 'org-ruby', '~> 0.9.12'
|
||||
|
@ -148,7 +151,7 @@ gem 'wikicloth', '0.8.1'
|
|||
gem 'asciidoctor', '~> 2.0.10'
|
||||
gem 'asciidoctor-include-ext', '~> 0.3.1', require: false
|
||||
gem 'asciidoctor-plantuml', '~> 0.0.12'
|
||||
gem 'rouge', '~> 3.19.0'
|
||||
gem 'rouge', '~> 3.21.0'
|
||||
gem 'truncato', '~> 0.7.11'
|
||||
gem 'bootstrap_form', '~> 4.2.0'
|
||||
gem 'nokogiri', '~> 1.10.9'
|
||||
|
@ -163,6 +166,8 @@ gem 'diff_match_patch', '~> 0.1.0'
|
|||
|
||||
# Application server
|
||||
gem 'rack', '~> 2.0.9'
|
||||
# https://github.com/sharpstone/rack-timeout/blob/master/README.md#rails-apps-manually
|
||||
gem 'rack-timeout', '~> 0.5.1', require: 'rack/timeout/base'
|
||||
|
||||
group :unicorn do
|
||||
gem 'unicorn', '~> 5.5'
|
||||
|
@ -172,7 +177,6 @@ end
|
|||
group :puma do
|
||||
gem 'gitlab-puma', '~> 4.3.3.gitlab.2', require: false
|
||||
gem 'gitlab-puma_worker_killer', '~> 0.1.1.gitlab.1', require: false
|
||||
gem 'rack-timeout', require: false
|
||||
end
|
||||
|
||||
# State machine
|
||||
|
@ -242,7 +246,9 @@ gem 'slack-messenger', '~> 2.3.3'
|
|||
gem 'hangouts-chat', '~> 0.0.5'
|
||||
|
||||
# Asana integration
|
||||
gem 'asana', '~> 0.9'
|
||||
# asana 0.10.1 needs faraday 1.0
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/224296
|
||||
gem 'asana', '0.10.0'
|
||||
|
||||
# FogBugz integration
|
||||
gem 'ruby-fogbugz', '~> 0.2.1'
|
||||
|
@ -300,7 +306,7 @@ gem 'sentry-raven', '~> 2.9'
|
|||
gem 'premailer-rails', '~> 1.10.3'
|
||||
|
||||
# LabKit: Tracing and Correlation
|
||||
gem 'gitlab-labkit', '0.12.0'
|
||||
gem 'gitlab-labkit', '0.12.1'
|
||||
|
||||
# I18n
|
||||
gem 'ruby_parser', '~> 3.8', require: false
|
||||
|
@ -331,10 +337,9 @@ group :development do
|
|||
gem 'danger', '~> 6.0', require: false
|
||||
|
||||
gem 'letter_opener_web', '~> 1.3.4'
|
||||
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
|
||||
|
||||
# Better errors handler
|
||||
gem 'better_errors', '~> 2.5.0'
|
||||
gem 'better_errors', '~> 2.7.1'
|
||||
gem 'binding_of_caller', '~> 0.8.0'
|
||||
|
||||
# thin instead webrick
|
||||
|
@ -361,7 +366,7 @@ group :development, :test do
|
|||
gem 'spring', '~> 2.0.0'
|
||||
gem 'spring-commands-rspec', '~> 1.0.4'
|
||||
|
||||
gem 'gitlab-styles', '~> 4.2.0', require: false
|
||||
gem 'gitlab-styles', '~> 4.3.0', require: false
|
||||
# Pin these dependencies, otherwise a new rule could break the CI pipelines
|
||||
gem 'rubocop', '~> 0.82.0'
|
||||
gem 'rubocop-performance', '~> 1.5.2'
|
||||
|
@ -370,6 +375,7 @@ group :development, :test do
|
|||
gem 'scss_lint', '~> 0.56.0', require: false
|
||||
gem 'haml_lint', '~> 0.34.0', require: false
|
||||
gem 'simplecov', '~> 0.18.5', require: false
|
||||
gem 'simplecov-cobertura', '~> 1.3.1', require: false
|
||||
gem 'bundler-audit', '~> 0.6.1', require: false
|
||||
|
||||
gem 'benchmark-ips', '~> 2.3.0', require: false
|
||||
|
@ -383,6 +389,8 @@ group :development, :test do
|
|||
gem 'png_quantizator', '~> 0.2.1', require: false
|
||||
|
||||
gem 'parallel', '~> 1.19', require: false
|
||||
|
||||
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
|
||||
end
|
||||
|
||||
# Gems required in omnibus-gitlab pipeline
|
||||
|
@ -452,7 +460,7 @@ group :ed25519 do
|
|||
end
|
||||
|
||||
# Gitaly GRPC protocol definitions
|
||||
gem 'gitaly', '~> 13.1.0.pre.rc1'
|
||||
gem 'gitaly', '~> 13.2.0.pre.rc2'
|
||||
|
||||
gem 'grpc', '~> 1.24.0'
|
||||
|
||||
|
@ -497,3 +505,5 @@ gem 'valid_email', '~> 0.1'
|
|||
# JSON
|
||||
gem 'json', '~> 2.3.0'
|
||||
gem 'json-schema', '~> 2.8.0'
|
||||
gem 'oj', '~> 3.10.6'
|
||||
gem 'multi_json', '~> 1.14.1'
|
||||
|
|
107
Gemfile.lock
107
Gemfile.lock
|
@ -4,8 +4,8 @@ GEM
|
|||
RedCloth (4.3.2)
|
||||
abstract_type (0.0.7)
|
||||
ace-rails-ap (4.1.2)
|
||||
acme-client (2.0.5)
|
||||
faraday (~> 0.9, >= 0.9.1)
|
||||
acme-client (2.0.6)
|
||||
faraday (>= 0.17, < 2.0.0)
|
||||
actioncable (6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
nio4r (~> 2.0)
|
||||
|
@ -76,7 +76,7 @@ GEM
|
|||
apollo_upload_server (2.0.0.beta.3)
|
||||
graphql (>= 1.8)
|
||||
rails (>= 4.2)
|
||||
asana (0.9.3)
|
||||
asana (0.10.0)
|
||||
faraday (~> 0.9)
|
||||
faraday_middleware (~> 0.9)
|
||||
faraday_middleware-multi_json (~> 0.0)
|
||||
|
@ -103,10 +103,6 @@ GEM
|
|||
aws-sdk-core (= 2.11.374)
|
||||
aws-sigv4 (1.1.0)
|
||||
aws-eventstream (~> 1.0, >= 1.0.2)
|
||||
axiom-types (0.1.1)
|
||||
descendants_tracker (~> 0.0.4)
|
||||
ice_nine (~> 0.11.0)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
babosa (1.0.2)
|
||||
base32 (0.3.2)
|
||||
batch-loader (1.4.0)
|
||||
|
@ -115,7 +111,7 @@ GEM
|
|||
benchmark-ips (2.3.0)
|
||||
benchmark-memory (0.1.2)
|
||||
memory_profiler (~> 0.9)
|
||||
better_errors (2.5.0)
|
||||
better_errors (2.7.1)
|
||||
coderay (>= 1.0.0)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
|
@ -164,8 +160,6 @@ GEM
|
|||
nap
|
||||
open4 (~> 1.3)
|
||||
coderay (1.1.2)
|
||||
coercible (1.0.0)
|
||||
descendants_tracker (~> 0.0.1)
|
||||
colored2 (3.1.2)
|
||||
commonmarker (0.20.1)
|
||||
ruby-enum (~> 0.5)
|
||||
|
@ -221,8 +215,6 @@ GEM
|
|||
ruby-statistics (>= 2.1)
|
||||
thor (>= 0.19, < 2)
|
||||
unicode_plot (>= 0.0.4, < 1.0.0)
|
||||
descendants_tracker (0.0.4)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
device_detector (1.0.0)
|
||||
devise (4.7.1)
|
||||
bcrypt (~> 3.0)
|
||||
|
@ -249,6 +241,28 @@ GEM
|
|||
doorkeeper-openid_connect (1.6.3)
|
||||
doorkeeper (>= 5.0, < 5.2)
|
||||
json-jwt (~> 1.6)
|
||||
dry-configurable (0.11.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 0.4, >= 0.4.7)
|
||||
dry-equalizer (~> 0.2)
|
||||
dry-container (0.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-configurable (~> 0.1, >= 0.1.3)
|
||||
dry-core (0.4.9)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-equalizer (0.3.0)
|
||||
dry-inflector (0.2.0)
|
||||
dry-logic (1.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 0.2)
|
||||
dry-equalizer (~> 0.2)
|
||||
dry-types (1.4.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-container (~> 0.3)
|
||||
dry-core (~> 0.4, >= 0.4.4)
|
||||
dry-equalizer (~> 0.3)
|
||||
dry-inflector (~> 0.1, >= 0.1.2)
|
||||
dry-logic (~> 1.0, >= 1.0.2)
|
||||
ed25519 (1.2.4)
|
||||
elasticsearch (6.8.0)
|
||||
elasticsearch-api (= 6.8.0)
|
||||
|
@ -290,7 +304,7 @@ GEM
|
|||
multipart-post (>= 1.2, < 3)
|
||||
faraday-http-cache (2.0.0)
|
||||
faraday (~> 0.8)
|
||||
faraday_middleware (0.12.2)
|
||||
faraday_middleware (0.14.0)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
faraday_middleware-aws-signers-v4 (0.1.7)
|
||||
aws-sdk-resources (~> 2)
|
||||
|
@ -377,12 +391,12 @@ GEM
|
|||
po_to_json (>= 1.0.0)
|
||||
rails (>= 3.2.0)
|
||||
git (1.5.0)
|
||||
gitaly (13.1.0.pre.rc1)
|
||||
gitaly (13.2.0.pre.rc2)
|
||||
grpc (~> 1.0)
|
||||
github-markup (1.7.0)
|
||||
gitlab-chronic (0.10.5)
|
||||
numerizer (~> 0.2)
|
||||
gitlab-labkit (0.12.0)
|
||||
gitlab-labkit (0.12.1)
|
||||
actionpack (>= 5.0.0, < 6.1.0)
|
||||
activesupport (>= 5.0.0, < 6.1.0)
|
||||
grpc (~> 1.19)
|
||||
|
@ -400,7 +414,7 @@ GEM
|
|||
gitlab-puma (>= 2.7, < 5)
|
||||
gitlab-sidekiq-fetcher (0.5.2)
|
||||
sidekiq (~> 5)
|
||||
gitlab-styles (4.2.0)
|
||||
gitlab-styles (4.3.0)
|
||||
rubocop (~> 0.82.0)
|
||||
rubocop-gitlab-security (~> 0.1.0)
|
||||
rubocop-performance (~> 1.5.2)
|
||||
|
@ -439,19 +453,19 @@ GEM
|
|||
signet (~> 0.14)
|
||||
gpgme (2.0.20)
|
||||
mini_portile2 (~> 2.3)
|
||||
grape (1.1.0)
|
||||
grape (1.4.0)
|
||||
activesupport
|
||||
builder
|
||||
dry-types (>= 1.1)
|
||||
mustermann-grape (~> 1.0.0)
|
||||
rack (>= 1.3.0)
|
||||
rack-accept
|
||||
virtus (>= 1.0.0)
|
||||
grape-entity (0.7.1)
|
||||
activesupport (>= 4.0)
|
||||
multi_json (>= 1.3.2)
|
||||
grape-path-helpers (1.2.0)
|
||||
grape-path-helpers (1.3.0)
|
||||
activesupport
|
||||
grape (~> 1.0)
|
||||
grape (~> 1.3)
|
||||
rake (~> 12)
|
||||
grape_logging (1.8.3)
|
||||
grape
|
||||
|
@ -575,7 +589,8 @@ GEM
|
|||
kgio (2.11.3)
|
||||
knapsack (1.17.0)
|
||||
rake
|
||||
kramdown (2.1.0)
|
||||
kramdown (2.2.1)
|
||||
rexml
|
||||
kramdown-parser-gfm (1.1.0)
|
||||
kramdown (~> 2.0)
|
||||
kubeclient (4.6.0)
|
||||
|
@ -641,9 +656,10 @@ GEM
|
|||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
murmurhash3 (0.1.6)
|
||||
mustermann (1.0.3)
|
||||
mustermann-grape (1.0.0)
|
||||
mustermann (~> 1.0.0)
|
||||
mustermann (1.1.1)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
mustermann-grape (1.0.1)
|
||||
mustermann (>= 1.0.0)
|
||||
nakayoshi_fork (0.0.4)
|
||||
nap (1.1.0)
|
||||
nenv (0.3.0)
|
||||
|
@ -671,6 +687,7 @@ GEM
|
|||
octokit (4.15.0)
|
||||
faraday (>= 0.9)
|
||||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
oj (3.10.6)
|
||||
omniauth (1.9.0)
|
||||
hashie (>= 3.4.6, < 3.7.0)
|
||||
rack (>= 1.6.2, < 3)
|
||||
|
@ -801,7 +818,7 @@ GEM
|
|||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-timeout (0.5.1)
|
||||
rack-timeout (0.5.2)
|
||||
rails (6.0.3.1)
|
||||
actioncable (= 6.0.3.1)
|
||||
actionmailbox (= 6.0.3.1)
|
||||
|
@ -890,7 +907,7 @@ GEM
|
|||
rexml (3.2.4)
|
||||
rinku (2.0.0)
|
||||
rotp (2.1.2)
|
||||
rouge (3.19.0)
|
||||
rouge (3.21.0)
|
||||
rqrcode (0.7.0)
|
||||
chunky_png
|
||||
rqrcode-rails3 (0.1.7)
|
||||
|
@ -958,6 +975,7 @@ GEM
|
|||
ruby-saml (1.7.2)
|
||||
nokogiri (>= 1.5.10)
|
||||
ruby-statistics (2.1.2)
|
||||
ruby2_keywords (0.0.2)
|
||||
ruby_dep (1.5.0)
|
||||
ruby_parser (3.13.1)
|
||||
sexp_processor (~> 4.9)
|
||||
|
@ -1003,11 +1021,11 @@ GEM
|
|||
shellany (0.0.1)
|
||||
shoulda-matchers (4.0.1)
|
||||
activesupport (>= 4.2.0)
|
||||
sidekiq (5.2.7)
|
||||
sidekiq (5.2.9)
|
||||
connection_pool (~> 2.2, >= 2.2.2)
|
||||
rack (>= 1.5.0)
|
||||
rack (~> 2.0)
|
||||
rack-protection (>= 1.5.0)
|
||||
redis (>= 3.3.5, < 5)
|
||||
redis (>= 3.3.5, < 4.2)
|
||||
sidekiq-cron (1.0.4)
|
||||
fugit (~> 1.1)
|
||||
sidekiq (>= 4.2.1)
|
||||
|
@ -1020,6 +1038,8 @@ GEM
|
|||
simplecov (0.18.5)
|
||||
docile (~> 1.1)
|
||||
simplecov-html (~> 0.11)
|
||||
simplecov-cobertura (1.3.1)
|
||||
simplecov (~> 0.8)
|
||||
simplecov-html (0.12.2)
|
||||
sixarm_ruby_unaccent (1.2.0)
|
||||
slack-messenger (2.3.3)
|
||||
|
@ -1119,11 +1139,6 @@ GEM
|
|||
activerecord (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
version_sorter (2.2.4)
|
||||
virtus (1.0.5)
|
||||
axiom-types (~> 0.1)
|
||||
coercible (~> 1.0)
|
||||
descendants_tracker (~> 0.0, >= 0.0.3)
|
||||
equalizer (~> 0.0, >= 0.0.9)
|
||||
vmstat (2.3.0)
|
||||
warden (1.2.8)
|
||||
rack (>= 2.0.6)
|
||||
|
@ -1155,13 +1170,13 @@ PLATFORMS
|
|||
DEPENDENCIES
|
||||
RedCloth (~> 4.3.2)
|
||||
ace-rails-ap (~> 4.1.0)
|
||||
acme-client (~> 2.0.5)
|
||||
acme-client (~> 2.0, >= 2.0.6)
|
||||
activerecord-explain-analyze (~> 0.1)
|
||||
acts-as-taggable-on (~> 6.0)
|
||||
addressable (~> 2.7)
|
||||
akismet (~> 3.0)
|
||||
apollo_upload_server (~> 2.0.0.beta3)
|
||||
asana (~> 0.9)
|
||||
asana (= 0.10.0)
|
||||
asciidoctor (~> 2.0.10)
|
||||
asciidoctor-include-ext (~> 0.3.1)
|
||||
asciidoctor-plantuml (~> 0.0.12)
|
||||
|
@ -1175,7 +1190,7 @@ DEPENDENCIES
|
|||
bcrypt_pbkdf (~> 1.0)
|
||||
benchmark-ips (~> 2.3.0)
|
||||
benchmark-memory (~> 0.1)
|
||||
better_errors (~> 2.5.0)
|
||||
better_errors (~> 2.7.1)
|
||||
binding_of_caller (~> 0.8.0)
|
||||
bootsnap (~> 1.4.6)
|
||||
bootstrap_form (~> 4.2.0)
|
||||
|
@ -1236,10 +1251,10 @@ DEPENDENCIES
|
|||
gettext (~> 3.2.2)
|
||||
gettext_i18n_rails (~> 1.8.0)
|
||||
gettext_i18n_rails_js (~> 1.3)
|
||||
gitaly (~> 13.1.0.pre.rc1)
|
||||
gitaly (~> 13.2.0.pre.rc2)
|
||||
github-markup (~> 1.7.0)
|
||||
gitlab-chronic (~> 0.10.5)
|
||||
gitlab-labkit (= 0.12.0)
|
||||
gitlab-labkit (= 0.12.1)
|
||||
gitlab-license (~> 1.0)
|
||||
gitlab-mail_room (~> 0.0.6)
|
||||
gitlab-markup (~> 1.7.1)
|
||||
|
@ -1247,16 +1262,16 @@ DEPENDENCIES
|
|||
gitlab-puma (~> 4.3.3.gitlab.2)
|
||||
gitlab-puma_worker_killer (~> 0.1.1.gitlab.1)
|
||||
gitlab-sidekiq-fetcher (= 0.5.2)
|
||||
gitlab-styles (~> 4.2.0)
|
||||
gitlab-styles (~> 4.3.0)
|
||||
gitlab_chronic_duration (~> 0.10.6.2)
|
||||
gitlab_omniauth-ldap (~> 2.1.1)
|
||||
gon (~> 6.2)
|
||||
google-api-client (~> 0.33)
|
||||
google-protobuf (~> 3.8.0)
|
||||
gpgme (~> 2.0.19)
|
||||
grape (~> 1.1.0)
|
||||
grape (= 1.4.0)
|
||||
grape-entity (~> 0.7.1)
|
||||
grape-path-helpers (~> 1.2)
|
||||
grape-path-helpers (~> 1.3)
|
||||
grape_logging (~> 1.7)
|
||||
graphiql-rails (~> 1.4.10)
|
||||
graphql (~> 1.10.5)
|
||||
|
@ -1282,6 +1297,7 @@ DEPENDENCIES
|
|||
jwt (~> 2.1.0)
|
||||
kaminari (~> 1.0)
|
||||
knapsack (~> 1.17)
|
||||
kramdown (~> 2.2.1)
|
||||
kubeclient (~> 4.6.0)
|
||||
letter_opener_web (~> 1.3.4)
|
||||
license_finder (~> 5.4)
|
||||
|
@ -1297,6 +1313,7 @@ DEPENDENCIES
|
|||
mimemagic (~> 0.3.2)
|
||||
mini_magick
|
||||
minitest (~> 5.11.0)
|
||||
multi_json (~> 1.14.1)
|
||||
nakayoshi_fork (~> 0.0.4)
|
||||
net-ldap
|
||||
net-ntp
|
||||
|
@ -1304,6 +1321,7 @@ DEPENDENCIES
|
|||
nokogiri (~> 1.10.9)
|
||||
oauth2 (~> 1.4)
|
||||
octokit (~> 4.15)
|
||||
oj (~> 3.10.6)
|
||||
omniauth (~> 1.8)
|
||||
omniauth-auth0 (~> 2.0.0)
|
||||
omniauth-authentiq (~> 0.3.3)
|
||||
|
@ -1335,7 +1353,7 @@ DEPENDENCIES
|
|||
rack-cors (~> 1.0.6)
|
||||
rack-oauth2 (~> 1.9.3)
|
||||
rack-proxy (~> 0.6.0)
|
||||
rack-timeout
|
||||
rack-timeout (~> 0.5.1)
|
||||
rails (~> 6.0.3.1)
|
||||
rails-controller-testing
|
||||
rails-i18n (~> 6.0)
|
||||
|
@ -1352,7 +1370,7 @@ DEPENDENCIES
|
|||
request_store (~> 1.5)
|
||||
responders (~> 3.0)
|
||||
retriable (~> 3.1.2)
|
||||
rouge (~> 3.19.0)
|
||||
rouge (~> 3.21.0)
|
||||
rqrcode-rails3 (~> 0.1.7)
|
||||
rspec-parameterized
|
||||
rspec-rails (~> 4.0.0)
|
||||
|
@ -1380,6 +1398,7 @@ DEPENDENCIES
|
|||
sidekiq-cron (~> 1.0)
|
||||
simple_po_parser (~> 1.1.2)
|
||||
simplecov (~> 0.18.5)
|
||||
simplecov-cobertura (~> 1.3.1)
|
||||
slack-messenger (~> 2.3.3)
|
||||
snowplow-tracker (~> 0.6.1)
|
||||
spring (~> 2.0.0)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
13.1.6
|
||||
13.2.1
|
||||
|
|
1
app/assets/images/confluence.svg
Normal file
1
app/assets/images/confluence.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a"><stop offset="0" stop-color="#344563"/><stop offset=".68" stop-color="#637088"/><stop offset="1" stop-color="#7a869a"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="14.873" x2="5.739" xlink:href="#a" y1="15.883" y2="10.625"/><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="-168376" x2="-168177" xlink:href="#a" y1="-6722.4" y2="-6493.53"/><path d="m1.517 11.68c-.15.243-.32.53-.453.757a.462.462 0 0 0 .155.63l3.013 1.863a.466.466 0 0 0 .645-.158l.445-.735c1.197-1.97 2.402-1.732 4.571-.703l2.995 1.424a.468.468 0 0 0 .626-.232l1.448-3.24a.466.466 0 0 0 -.229-.606c-.633-.298-1.89-.89-3.016-1.434-4.089-2.004-7.551-1.86-10.2 2.434z" fill="url(#b)"/><path d="m14.479 4.315c.15-.243.324-.53.456-.758a.46.46 0 0 0 -.158-.63l-3.025-1.857a.464.464 0 0 0 -.644.158 22.81 22.81 0 0 1 -.446.736c-1.196 1.972-2.4 1.733-4.567.703l-2.993-1.424a.468.468 0 0 0 -.625.231l-1.437 3.246a.46.46 0 0 0 .225.607c.633.298 1.892.89 3.014 1.435 4.097 1.99 7.556 1.858 10.199-2.446z" fill="url(#c)"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
1
app/assets/images/logos/jira-gray.svg
Normal file
1
app/assets/images/logos/jira-gray.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg id="Logos" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="80" height="80" viewBox="0 0 80 80"><defs><style>.cls-1{fill:#7a869a;}.cls-2{fill:url(#linear-gradient);}.cls-3{fill:url(#linear-gradient-2);}</style><linearGradient id="linear-gradient" x1="38.11" y1="18.54" x2="23.17" y2="33.48" gradientUnits="userSpaceOnUse"><stop offset="0.18" stop-color="#344563"/><stop offset="1" stop-color="#7a869a"/></linearGradient><linearGradient id="linear-gradient-2" x1="42.07" y1="61.47" x2="56.98" y2="46.55" xlink:href="#linear-gradient"/></defs><title>jira software-icon-gradient-neutral</title><path class="cls-1" d="M74.18,38,43,6.9l-3-3h0L16.58,27.32h0L5.86,38a2.86,2.86,0,0,0,0,4.05L27.28,63.51,40,76.25,63.47,52.81l.36-.36L74.18,42.09A2.86,2.86,0,0,0,74.18,38ZM40,50.77l-10.7-10.7L40,29.37l10.7,10.7Z"/><path class="cls-2" d="M40,29.37A18,18,0,0,1,40,4L16.54,27.37,29.28,40.11,40,29.37Z"/><path class="cls-3" d="M50.75,40,40,50.77a18,18,0,0,1,0,25.48h0L63.5,52.78Z"/></svg>
|
After Width: | Height: | Size: 1,016 B |
|
@ -12,18 +12,21 @@ import {
|
|||
GlTable,
|
||||
} from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import query from '../graphql/queries/details.query.graphql';
|
||||
import alertQuery from '../graphql/queries/details.query.graphql';
|
||||
import sidebarStatusQuery from '../graphql/queries/sidebar_status.query.graphql';
|
||||
import { fetchPolicies } from '~/lib/graphql';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
|
||||
import initUserPopovers from '~/user_popovers';
|
||||
import { ALERTS_SEVERITY_LABELS, trackAlertsDetailsViewsOptions } from '../constants';
|
||||
import createIssueQuery from '../graphql/mutations/create_issue_from_alert.graphql';
|
||||
import createIssueMutation from '../graphql/mutations/create_issue_from_alert.mutation.graphql';
|
||||
import toggleSidebarStatusMutation from '../graphql/mutations/toggle_sidebar_status.mutation.graphql';
|
||||
import { visitUrl, joinPaths } from '~/lib/utils/url_utility';
|
||||
import Tracking from '~/tracking';
|
||||
import { toggleContainerClasses } from '~/lib/utils/dom_utils';
|
||||
import SystemNote from './system_notes/system_note.vue';
|
||||
import AlertSidebar from './alert_sidebar.vue';
|
||||
import AlertMetrics from './alert_metrics.vue';
|
||||
|
||||
const containerEl = document.querySelector('.page-with-contextual-sidebar');
|
||||
|
||||
|
@ -34,6 +37,7 @@ export default {
|
|||
),
|
||||
fullAlertDetailsTitle: s__('AlertManagement|Alert details'),
|
||||
overviewTitle: s__('AlertManagement|Overview'),
|
||||
metricsTitle: s__('AlertManagement|Metrics'),
|
||||
reportedAt: s__('AlertManagement|Reported %{when}'),
|
||||
reportedAtWithTool: s__('AlertManagement|Reported %{when} by %{tool}'),
|
||||
},
|
||||
|
@ -51,25 +55,29 @@ export default {
|
|||
TimeAgoTooltip,
|
||||
AlertSidebar,
|
||||
SystemNote,
|
||||
AlertMetrics,
|
||||
},
|
||||
props: {
|
||||
inject: {
|
||||
projectPath: {
|
||||
default: '',
|
||||
},
|
||||
alertId: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
projectPath: {
|
||||
projectId: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
projectIssuesPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
alert: {
|
||||
fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
|
||||
query,
|
||||
query: alertQuery,
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.projectPath,
|
||||
|
@ -84,15 +92,18 @@ export default {
|
|||
Sentry.captureException(error);
|
||||
},
|
||||
},
|
||||
sidebarStatus: {
|
||||
query: sidebarStatusQuery,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
alert: null,
|
||||
errored: false,
|
||||
sidebarStatus: false,
|
||||
isErrorDismissed: false,
|
||||
createIssueError: '',
|
||||
issueCreationInProgress: false,
|
||||
sidebarCollapsed: false,
|
||||
sidebarErrorMessage: '',
|
||||
};
|
||||
},
|
||||
|
@ -128,10 +139,10 @@ export default {
|
|||
this.sidebarErrorMessage = '';
|
||||
},
|
||||
toggleSidebar() {
|
||||
this.sidebarCollapsed = !this.sidebarCollapsed;
|
||||
this.$apollo.mutate({ mutation: toggleSidebarStatusMutation });
|
||||
toggleContainerClasses(containerEl, {
|
||||
'right-sidebar-collapsed': this.sidebarCollapsed,
|
||||
'right-sidebar-expanded': !this.sidebarCollapsed,
|
||||
'right-sidebar-collapsed': !this.sidebarStatus,
|
||||
'right-sidebar-expanded': this.sidebarStatus,
|
||||
});
|
||||
},
|
||||
handleAlertSidebarError(errorMessage) {
|
||||
|
@ -143,7 +154,7 @@ export default {
|
|||
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: createIssueQuery,
|
||||
mutation: createIssueMutation,
|
||||
variables: {
|
||||
iid: this.alert.iid,
|
||||
projectPath: this.projectPath,
|
||||
|
@ -169,9 +180,6 @@ export default {
|
|||
const { category, action } = trackAlertsDetailsViewsOptions;
|
||||
Tracking.event(category, action);
|
||||
},
|
||||
alertRefresh() {
|
||||
this.$apollo.queries.alert.refetch();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -179,7 +187,7 @@ export default {
|
|||
<template>
|
||||
<div>
|
||||
<gl-alert v-if="showErrorMsg" variant="danger" @dismiss="dismissError">
|
||||
{{ sidebarErrorMessage || $options.i18n.errorMsg }}
|
||||
<p v-html="sidebarErrorMessage || $options.i18n.errorMsg"></p>
|
||||
</gl-alert>
|
||||
<gl-alert
|
||||
v-if="createIssueError"
|
||||
|
@ -193,10 +201,10 @@ export default {
|
|||
<div
|
||||
v-if="alert"
|
||||
class="alert-management-details gl-relative"
|
||||
:class="{ 'pr-sm-8': sidebarCollapsed }"
|
||||
:class="{ 'pr-sm-8': sidebarStatus }"
|
||||
>
|
||||
<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-200 gl-border-b-solid flex-column flex-sm-row"
|
||||
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"
|
||||
>
|
||||
<div
|
||||
data-testid="alert-header"
|
||||
|
@ -324,14 +332,14 @@ export default {
|
|||
</template>
|
||||
</gl-table>
|
||||
</gl-tab>
|
||||
<gl-tab data-testId="metricsTab" :title="$options.i18n.metricsTitle">
|
||||
<alert-metrics :dashboard-url="alert.metricsDashboardUrl" />
|
||||
</gl-tab>
|
||||
</gl-tabs>
|
||||
<alert-sidebar
|
||||
:project-path="projectPath"
|
||||
:alert="alert"
|
||||
:sidebar-collapsed="sidebarCollapsed"
|
||||
@alert-refresh="alertRefresh"
|
||||
@toggle-sidebar="toggleSidebar"
|
||||
@alert-sidebar-error="handleAlertSidebarError"
|
||||
@alert-error="handleAlertSidebarError"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<script>
|
||||
import { GlEmptyState, GlButton } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
emptyState: {
|
||||
opsgenie: {
|
||||
title: s__('AlertManagement|Opsgenie is enabled'),
|
||||
info: s__(
|
||||
'AlertManagement|You have enabled the Opsgenie integration. Your alerts will be visible directly in Opsgenie.',
|
||||
),
|
||||
buttonText: s__('AlertManagement|View alerts in Opsgenie'),
|
||||
},
|
||||
gitlab: {
|
||||
title: s__('AlertManagement|Surface alerts in GitLab'),
|
||||
info: s__(
|
||||
'AlertManagement|Display alerts from all your monitoring tools directly within GitLab. Streamline the investigation of your alerts and the escalation of alerts to incidents.',
|
||||
),
|
||||
buttonText: s__('AlertManagement|Authorize external service'),
|
||||
},
|
||||
},
|
||||
moreInformation: s__('AlertManagement|More information'),
|
||||
},
|
||||
components: {
|
||||
GlEmptyState,
|
||||
GlButton,
|
||||
},
|
||||
props: {
|
||||
enableAlertManagementPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
userCanEnableAlertManagement: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
emptyAlertSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
opsgenieMvcEnabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
opsgenieMvcTargetUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
emptyState() {
|
||||
return {
|
||||
...(this.opsgenieMvcEnabled
|
||||
? this.$options.i18n.emptyState.opsgenie
|
||||
: this.$options.i18n.emptyState.gitlab),
|
||||
link: this.opsgenieMvcEnabled ? this.opsgenieMvcTargetUrl : this.enableAlertManagementPath,
|
||||
};
|
||||
},
|
||||
alertsCanBeEnabled() {
|
||||
return this.userCanEnableAlertManagement || this.opsgenieMvcEnabled;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<gl-empty-state :title="emptyState.title" :svg-path="emptyAlertSvgPath">
|
||||
<template #description>
|
||||
<div class="gl-display-block">
|
||||
<span>{{ emptyState.info }}</span>
|
||||
<a
|
||||
v-if="!opsgenieMvcEnabled"
|
||||
href="/help/user/project/operations/alert_management.html"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $options.i18n.moreInformation }}
|
||||
</a>
|
||||
</div>
|
||||
<div v-if="alertsCanBeEnabled" class="gl-display-block center gl-pt-4">
|
||||
<gl-button category="primary" variant="success" :href="emptyState.link">
|
||||
{{ emptyState.buttonText }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</template>
|
||||
</gl-empty-state>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,75 @@
|
|||
<script>
|
||||
import Tracking from '~/tracking';
|
||||
import { trackAlertListViewsOptions } from '../constants';
|
||||
import AlertManagementEmptyState from './alert_management_empty_state.vue';
|
||||
import AlertManagementTable from './alert_management_table.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AlertManagementEmptyState,
|
||||
AlertManagementTable,
|
||||
},
|
||||
props: {
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
alertManagementEnabled: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
enableAlertManagementPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
populatingAlertsHelpUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
userCanEnableAlertManagement: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
emptyAlertSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
opsgenieMvcEnabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
opsgenieMvcTargetUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.trackPageViews();
|
||||
},
|
||||
methods: {
|
||||
trackPageViews() {
|
||||
const { category, action } = trackAlertListViewsOptions;
|
||||
Tracking.event(category, action);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<alert-management-table
|
||||
v-if="alertManagementEnabled"
|
||||
:populating-alerts-help-url="populatingAlertsHelpUrl"
|
||||
:project-path="projectPath"
|
||||
/>
|
||||
<alert-management-empty-state
|
||||
v-else
|
||||
:empty-alert-svg-path="emptyAlertSvgPath"
|
||||
:enable-alert-management-path="enableAlertManagementPath"
|
||||
:user-can-enable-alert-management="userCanEnableAlertManagement"
|
||||
:opsgenie-mvc-enabled="opsgenieMvcEnabled"
|
||||
:opsgenie-mvc-target-url="opsgenieMvcTargetUrl"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
|
@ -1,23 +1,24 @@
|
|||
<script>
|
||||
import {
|
||||
GlEmptyState,
|
||||
GlDeprecatedButton,
|
||||
GlLoadingIcon,
|
||||
GlTable,
|
||||
GlAlert,
|
||||
GlIcon,
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlLink,
|
||||
GlTabs,
|
||||
GlTab,
|
||||
GlBadge,
|
||||
GlPagination,
|
||||
GlSearchBoxByType,
|
||||
GlSprintf,
|
||||
} from '@gitlab/ui';
|
||||
import createFlash from '~/flash';
|
||||
import { s__ } from '~/locale';
|
||||
import { __, s__ } from '~/locale';
|
||||
import { debounce, trim } from 'lodash';
|
||||
import { joinPaths, visitUrl } from '~/lib/utils/url_utility';
|
||||
import { fetchPolicies } from '~/lib/graphql';
|
||||
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import { convertToSnakeCase } from '~/lib/utils/text_utility';
|
||||
import Tracking from '~/tracking';
|
||||
import getAlerts from '../graphql/queries/get_alerts.query.graphql';
|
||||
import getAlertsCountByStatus from '../graphql/queries/get_count_by_status.query.graphql';
|
||||
import {
|
||||
|
@ -27,11 +28,10 @@ import {
|
|||
trackAlertListViewsOptions,
|
||||
trackAlertStatusUpdateOptions,
|
||||
} from '../constants';
|
||||
import updateAlertStatus from '../graphql/mutations/update_alert_status.graphql';
|
||||
import { convertToSnakeCase } from '~/lib/utils/text_utility';
|
||||
import Tracking from '~/tracking';
|
||||
import AlertStatus from './alert_status.vue';
|
||||
|
||||
const tdClass = 'table-col gl-display-flex d-md-table-cell gl-align-items-center';
|
||||
const tdClass =
|
||||
'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
|
||||
const thClass = 'gl-hover-bg-blue-50';
|
||||
const bodyTrClass =
|
||||
'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-bg-blue-50 gl-hover-cursor-pointer gl-hover-border-b-solid gl-hover-border-blue-200';
|
||||
|
@ -44,54 +44,57 @@ const initialPaginationState = {
|
|||
lastPageSize: null,
|
||||
};
|
||||
|
||||
const TWELVE_HOURS_IN_MS = 12 * 60 * 60 * 1000;
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
noAlertsMsg: s__(
|
||||
"AlertManagement|No alerts available to display. If you think you're seeing this message in error, refresh the page.",
|
||||
'AlertManagement|No alerts available to display. See %{linkStart}enabling alert management%{linkEnd} for more information on adding alerts to the list.',
|
||||
),
|
||||
errorMsg: s__(
|
||||
"AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear.",
|
||||
),
|
||||
searchPlaceholder: __('Search or filter results...'),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
key: 'severity',
|
||||
label: s__('AlertManagement|Severity'),
|
||||
tdClass: `${tdClass} rounded-top text-capitalize`,
|
||||
thClass,
|
||||
thClass: `${thClass} gl-w-eighth`,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
key: 'startedAt',
|
||||
label: s__('AlertManagement|Start time'),
|
||||
thClass: `${thClass} js-started-at`,
|
||||
tdClass,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
key: 'endedAt',
|
||||
label: s__('AlertManagement|End time'),
|
||||
thClass,
|
||||
thClass: `${thClass} js-started-at w-15p`,
|
||||
tdClass,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
key: 'title',
|
||||
label: s__('AlertManagement|Alert'),
|
||||
thClass: `${thClass} w-30p gl-pointer-events-none`,
|
||||
thClass: `gl-pointer-events-none`,
|
||||
tdClass,
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
key: 'eventCount',
|
||||
label: s__('AlertManagement|Events'),
|
||||
thClass: `${thClass} text-right gl-pr-9 w-3rem`,
|
||||
thClass: `${thClass} text-right gl-w-12`,
|
||||
tdClass: `${tdClass} text-md-right`,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
key: 'issue',
|
||||
label: s__('AlertManagement|Issue'),
|
||||
thClass: 'gl-w-12 gl-pointer-events-none',
|
||||
tdClass,
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
key: 'assignees',
|
||||
label: s__('AlertManagement|Assignees'),
|
||||
thClass: 'gl-w-eighth gl-pointer-events-none',
|
||||
tdClass,
|
||||
},
|
||||
{
|
||||
|
@ -102,46 +105,29 @@ export default {
|
|||
sortable: true,
|
||||
},
|
||||
],
|
||||
statuses: {
|
||||
TRIGGERED: s__('AlertManagement|Triggered'),
|
||||
ACKNOWLEDGED: s__('AlertManagement|Acknowledged'),
|
||||
RESOLVED: s__('AlertManagement|Resolved'),
|
||||
},
|
||||
severityLabels: ALERTS_SEVERITY_LABELS,
|
||||
statusTabs: ALERTS_STATUS_TABS,
|
||||
components: {
|
||||
GlEmptyState,
|
||||
GlLoadingIcon,
|
||||
GlTable,
|
||||
GlAlert,
|
||||
GlDeprecatedButton,
|
||||
TimeAgo,
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlIcon,
|
||||
GlLink,
|
||||
GlTabs,
|
||||
GlTab,
|
||||
GlBadge,
|
||||
GlPagination,
|
||||
GlSearchBoxByType,
|
||||
GlSprintf,
|
||||
AlertStatus,
|
||||
},
|
||||
props: {
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
alertManagementEnabled: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
enableAlertManagementPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
userCanEnableAlertManagement: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
emptyAlertSvgPath: {
|
||||
populatingAlertsHelpUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
@ -152,6 +138,7 @@ export default {
|
|||
query: getAlerts,
|
||||
variables() {
|
||||
return {
|
||||
searchTerm: this.searchTerm,
|
||||
projectPath: this.projectPath,
|
||||
statuses: this.statusFilter,
|
||||
sort: this.sort,
|
||||
|
@ -164,9 +151,20 @@ export default {
|
|||
update(data) {
|
||||
const { alertManagementAlerts: { nodes: list = [], pageInfo = {} } = {} } =
|
||||
data.project || {};
|
||||
const now = new Date();
|
||||
|
||||
const listWithData = list.map(alert => {
|
||||
const then = new Date(alert.startedAt);
|
||||
const diff = now - then;
|
||||
|
||||
return {
|
||||
...alert,
|
||||
isNew: diff < TWELVE_HOURS_IN_MS,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
list,
|
||||
list: listWithData,
|
||||
pageInfo,
|
||||
};
|
||||
},
|
||||
|
@ -178,6 +176,7 @@ export default {
|
|||
query: getAlertsCountByStatus,
|
||||
variables() {
|
||||
return {
|
||||
searchTerm: this.searchTerm,
|
||||
projectPath: this.projectPath,
|
||||
};
|
||||
},
|
||||
|
@ -188,7 +187,9 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
searchTerm: '',
|
||||
errored: false,
|
||||
errorMessage: '',
|
||||
isAlertDismissed: false,
|
||||
isErrorAlertDismissed: false,
|
||||
sort: 'STARTED_AT_DESC',
|
||||
|
@ -203,7 +204,11 @@ export default {
|
|||
computed: {
|
||||
showNoAlertsMsg() {
|
||||
return (
|
||||
!this.errored && !this.loading && this.alertsCount?.all === 0 && !this.isAlertDismissed
|
||||
!this.errored &&
|
||||
!this.loading &&
|
||||
this.alertsCount?.all === 0 &&
|
||||
!this.searchTerm &&
|
||||
!this.isAlertDismissed
|
||||
);
|
||||
},
|
||||
showErrorMsg() {
|
||||
|
@ -215,9 +220,6 @@ export default {
|
|||
hasAlerts() {
|
||||
return this.alerts?.list?.length;
|
||||
},
|
||||
tbodyTrClass() {
|
||||
return !this.loading && this.hasAlerts ? bodyTrClass : '';
|
||||
},
|
||||
showPaginationControls() {
|
||||
return Boolean(this.prevPage || this.nextPage);
|
||||
},
|
||||
|
@ -249,30 +251,13 @@ export default {
|
|||
this.resetPagination();
|
||||
this.sort = `${sortingColumn}_${sortingDirection}`;
|
||||
},
|
||||
updateAlertStatus(status, iid) {
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: updateAlertStatus,
|
||||
variables: {
|
||||
iid,
|
||||
status: status.toUpperCase(),
|
||||
projectPath: this.projectPath,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.trackStatusUpdate(status);
|
||||
this.$apollo.queries.alerts.refetch();
|
||||
this.$apollo.queries.alertsCount.refetch();
|
||||
this.resetPagination();
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash(
|
||||
s__(
|
||||
'AlertManagement|There was an error while updating the status of the alert. Please try again.',
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
onInputChange: debounce(function debounceSearch(input) {
|
||||
const trimmedInput = trim(input);
|
||||
if (trimmedInput !== this.searchTerm) {
|
||||
this.resetPagination();
|
||||
this.searchTerm = trimmedInput;
|
||||
}
|
||||
}, 500),
|
||||
navigateToAlertDetails({ iid }) {
|
||||
return visitUrl(joinPaths(window.location.pathname, iid, 'details'));
|
||||
},
|
||||
|
@ -290,6 +275,9 @@ export default {
|
|||
? assignees.nodes[0]?.username
|
||||
: s__('AlertManagement|Unassigned');
|
||||
},
|
||||
getIssueLink(item) {
|
||||
return joinPaths('/', this.projectPath, '-', 'issues', item.issueIid);
|
||||
},
|
||||
handlePageChange(page) {
|
||||
const { startCursor, endCursor } = this.alerts.pageInfo;
|
||||
|
||||
|
@ -312,20 +300,49 @@ export default {
|
|||
resetPagination() {
|
||||
this.pagination = initialPaginationState;
|
||||
},
|
||||
tbodyTrClass(item) {
|
||||
return {
|
||||
[bodyTrClass]: !this.loading && this.hasAlerts,
|
||||
'new-alert': item?.isNew,
|
||||
};
|
||||
},
|
||||
handleAlertError(errorMessage) {
|
||||
this.errored = true;
|
||||
this.errorMessage = errorMessage;
|
||||
},
|
||||
dismissError() {
|
||||
this.isErrorAlertDismissed = true;
|
||||
this.errorMessage = '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="alertManagementEnabled" class="alert-management-list">
|
||||
<div class="alert-management-list">
|
||||
<gl-alert v-if="showNoAlertsMsg" @dismiss="isAlertDismissed = true">
|
||||
{{ $options.i18n.noAlertsMsg }}
|
||||
<gl-sprintf :message="$options.i18n.noAlertsMsg">
|
||||
<template #link="{ content }">
|
||||
<gl-link
|
||||
class="gl-display-inline-block"
|
||||
:href="populatingAlertsHelpUrl"
|
||||
target="_blank"
|
||||
>
|
||||
{{ content }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</gl-alert>
|
||||
<gl-alert v-if="showErrorMsg" variant="danger" @dismiss="isErrorAlertDismissed = true">
|
||||
{{ $options.i18n.errorMsg }}
|
||||
<gl-alert
|
||||
v-if="showErrorMsg"
|
||||
variant="danger"
|
||||
data-testid="alert-error"
|
||||
@dismiss="dismissError"
|
||||
>
|
||||
<p v-html="errorMessage || $options.i18n.errorMsg"></p>
|
||||
</gl-alert>
|
||||
|
||||
<gl-tabs @input="filterAlertsByStatus">
|
||||
<gl-tabs content-class="gl-p-0" @input="filterAlertsByStatus">
|
||||
<gl-tab v-for="tab in $options.statusTabs" :key="tab.status">
|
||||
<template slot="title">
|
||||
<span>{{ tab.title }}</span>
|
||||
|
@ -336,11 +353,19 @@ export default {
|
|||
</gl-tab>
|
||||
</gl-tabs>
|
||||
|
||||
<div class="gl-bg-gray-10 gl-p-5 gl-border-b-solid gl-border-b-1 gl-border-gray-100">
|
||||
<gl-search-box-by-type
|
||||
class="gl-bg-white"
|
||||
:placeholder="$options.i18n.searchPlaceholder"
|
||||
@input="onInputChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h4 class="d-block d-md-none my-3">
|
||||
{{ s__('AlertManagement|Alerts') }}
|
||||
</h4>
|
||||
<gl-table
|
||||
class="alert-management-table mt-3"
|
||||
class="alert-management-table"
|
||||
:items="alerts ? alerts.list : []"
|
||||
:fields="$options.fields"
|
||||
:show-empty="true"
|
||||
|
@ -352,6 +377,7 @@ export default {
|
|||
:sort-desc.sync="sortDesc"
|
||||
:sort-by.sync="sortBy"
|
||||
sort-icon-left
|
||||
fixed
|
||||
@row-clicked="navigateToAlertDetails"
|
||||
@sort-changed="fetchSortedData"
|
||||
>
|
||||
|
@ -374,16 +400,19 @@ export default {
|
|||
<time-ago v-if="item.startedAt" :time="item.startedAt" />
|
||||
</template>
|
||||
|
||||
<template #cell(endedAt)="{ item }">
|
||||
<time-ago v-if="item.endedAt" :time="item.endedAt" />
|
||||
</template>
|
||||
|
||||
<template #cell(eventCount)="{ item }">
|
||||
{{ item.eventCount }}
|
||||
</template>
|
||||
|
||||
<template #cell(title)="{ item }">
|
||||
<div class="gl-max-w-full text-truncate">{{ item.title }}</div>
|
||||
<div class="gl-max-w-full text-truncate" :title="item.title">{{ item.title }}</div>
|
||||
</template>
|
||||
|
||||
<template #cell(issue)="{ item }">
|
||||
<gl-link v-if="item.issueIid" data-testid="issueField" :href="getIssueLink(item)">
|
||||
#{{ item.issueIid }}
|
||||
</gl-link>
|
||||
<div v-else data-testid="issueField">{{ s__('AlertManagement|None') }}</div>
|
||||
</template>
|
||||
|
||||
<template #cell(assignees)="{ item }">
|
||||
|
@ -393,22 +422,12 @@ export default {
|
|||
</template>
|
||||
|
||||
<template #cell(status)="{ item }">
|
||||
<gl-dropdown :text="$options.statuses[item.status]" class="w-100" right>
|
||||
<gl-dropdown-item
|
||||
v-for="(label, field) in $options.statuses"
|
||||
:key="field"
|
||||
@click="updateAlertStatus(label, item.iid)"
|
||||
>
|
||||
<span class="d-flex">
|
||||
<gl-icon
|
||||
class="flex-shrink-0 append-right-4"
|
||||
:class="{ invisible: label.toUpperCase() !== item.status }"
|
||||
name="mobile-issue-close"
|
||||
/>
|
||||
{{ label }}
|
||||
</span>
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
<alert-status
|
||||
:alert="item"
|
||||
:project-path="projectPath"
|
||||
:is-sidebar="false"
|
||||
@alert-error="handleAlertError"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #empty>
|
||||
|
@ -426,36 +445,9 @@ export default {
|
|||
:prev-page="prevPage"
|
||||
:next-page="nextPage"
|
||||
align="center"
|
||||
class="gl-pagination prepend-top-default"
|
||||
class="gl-pagination gl-mt-3"
|
||||
@input="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
<gl-empty-state
|
||||
v-else
|
||||
:title="s__('AlertManagement|Surface alerts in GitLab')"
|
||||
:svg-path="emptyAlertSvgPath"
|
||||
>
|
||||
<template #description>
|
||||
<div class="d-block">
|
||||
<span>{{
|
||||
s__(
|
||||
'AlertManagement|Display alerts from all your monitoring tools directly within GitLab. Streamline the investigation of your alerts and the escalation of alerts to incidents.',
|
||||
)
|
||||
}}</span>
|
||||
<a href="/help/user/project/operations/alert_management.html" target="_blank">
|
||||
{{ s__('AlertManagement|More information') }}
|
||||
</a>
|
||||
</div>
|
||||
<div v-if="userCanEnableAlertManagement" class="d-block center pt-4">
|
||||
<gl-deprecated-button
|
||||
category="primary"
|
||||
variant="success"
|
||||
:href="enableAlertManagementPath"
|
||||
>
|
||||
{{ s__('AlertManagement|Authorize external service') }}
|
||||
</gl-deprecated-button>
|
||||
</div>
|
||||
</template>
|
||||
</gl-empty-state>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,56 @@
|
|||
<script>
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import * as Sentry from '@sentry/browser';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
dashboardUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
metricEmbedComponent: null,
|
||||
namespace: 'alertMetrics',
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.dashboardUrl) {
|
||||
Promise.all([
|
||||
import('~/monitoring/components/embeds/metric_embed.vue'),
|
||||
import('~/monitoring/stores'),
|
||||
])
|
||||
.then(([{ default: MetricEmbed }, { monitoringDashboard }]) => {
|
||||
this.$store = new Vuex.Store({
|
||||
modules: {
|
||||
[this.namespace]: monitoringDashboard,
|
||||
},
|
||||
});
|
||||
this.metricEmbedComponent = MetricEmbed;
|
||||
})
|
||||
.catch(e => Sentry.captureException(e));
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-py-3">
|
||||
<div v-if="dashboardUrl" ref="metricsChart">
|
||||
<component
|
||||
:is="metricEmbedComponent"
|
||||
v-if="metricEmbedComponent"
|
||||
:dashboard-url="dashboardUrl"
|
||||
:namespace="namespace"
|
||||
/>
|
||||
</div>
|
||||
<div v-else ref="emptyState">
|
||||
{{ s__("AlertManagement|Metrics weren't available in the alerts payload.") }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -4,6 +4,8 @@ import SidebarTodo from './sidebar/sidebar_todo.vue';
|
|||
import SidebarStatus from './sidebar/sidebar_status.vue';
|
||||
import SidebarAssignees from './sidebar/sidebar_assignees.vue';
|
||||
|
||||
import sidebarStatusQuery from '../graphql/queries/sidebar_status.query.graphql';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SidebarAssignees,
|
||||
|
@ -11,23 +13,34 @@ export default {
|
|||
SidebarTodo,
|
||||
SidebarStatus,
|
||||
},
|
||||
props: {
|
||||
sidebarCollapsed: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
inject: {
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
projectId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
props: {
|
||||
alert: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
sidebarStatus: {
|
||||
query: sidebarStatusQuery,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sidebarStatus: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
sidebarCollapsedClass() {
|
||||
return this.sidebarCollapsed ? 'right-sidebar-collapsed' : 'right-sidebar-expanded';
|
||||
return this.sidebarStatus ? 'right-sidebar-collapsed' : 'right-sidebar-expanded';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -37,23 +50,32 @@ export default {
|
|||
<aside :class="sidebarCollapsedClass" class="right-sidebar alert-sidebar">
|
||||
<div class="issuable-sidebar js-issuable-update">
|
||||
<sidebar-header
|
||||
:sidebar-collapsed="sidebarCollapsed"
|
||||
:sidebar-collapsed="sidebarStatus"
|
||||
:project-path="projectPath"
|
||||
:alert="alert"
|
||||
@toggle-sidebar="$emit('toggle-sidebar')"
|
||||
@alert-error="$emit('alert-error', $event)"
|
||||
/>
|
||||
<sidebar-todo
|
||||
v-if="sidebarStatus"
|
||||
:project-path="projectPath"
|
||||
:alert="alert"
|
||||
:sidebar-collapsed="sidebarStatus"
|
||||
@alert-error="$emit('alert-error', $event)"
|
||||
/>
|
||||
<sidebar-todo v-if="sidebarCollapsed" :sidebar-collapsed="sidebarCollapsed" />
|
||||
<sidebar-status
|
||||
:project-path="projectPath"
|
||||
:alert="alert"
|
||||
@toggle-sidebar="$emit('toggle-sidebar')"
|
||||
@alert-sidebar-error="$emit('alert-sidebar-error', $event)"
|
||||
@alert-error="$emit('alert-error', $event)"
|
||||
/>
|
||||
<sidebar-assignees
|
||||
:project-path="projectPath"
|
||||
:project-id="projectId"
|
||||
:alert="alert"
|
||||
:sidebar-collapsed="sidebarCollapsed"
|
||||
@alert-refresh="$emit('alert-refresh')"
|
||||
:sidebar-collapsed="sidebarStatus"
|
||||
@toggle-sidebar="$emit('toggle-sidebar')"
|
||||
@alert-sidebar-error="$emit('alert-sidebar-error', $event)"
|
||||
@alert-error="$emit('alert-error', $event)"
|
||||
/>
|
||||
<div class="block"></div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
<script>
|
||||
import { GlDropdown, GlDropdownItem, GlButton } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import Tracking from '~/tracking';
|
||||
import { trackAlertStatusUpdateOptions } from '../constants';
|
||||
import updateAlertStatus from '../graphql/mutations/update_alert_status.mutation.graphql';
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
UPDATE_ALERT_STATUS_ERROR: s__(
|
||||
'AlertManagement|There was an error while updating the status of the alert.',
|
||||
),
|
||||
UPDATE_ALERT_STATUS_INSTRUCTION: s__('AlertManagement|Please try again.'),
|
||||
},
|
||||
statuses: {
|
||||
TRIGGERED: s__('AlertManagement|Triggered'),
|
||||
ACKNOWLEDGED: s__('AlertManagement|Acknowledged'),
|
||||
RESOLVED: s__('AlertManagement|Resolved'),
|
||||
},
|
||||
components: {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlButton,
|
||||
},
|
||||
props: {
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
alert: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isDropdownShowing: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
isSidebar: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
dropdownClass() {
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
return this.isSidebar ? (this.isDropdownShowing ? 'show' : 'gl-display-none') : '';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateAlertStatus(status) {
|
||||
this.$emit('handle-updating', true);
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: updateAlertStatus,
|
||||
variables: {
|
||||
iid: this.alert.iid,
|
||||
status: status.toUpperCase(),
|
||||
projectPath: this.projectPath,
|
||||
},
|
||||
})
|
||||
.then(resp => {
|
||||
this.trackStatusUpdate(status);
|
||||
this.$emit('hide-dropdown');
|
||||
|
||||
const errors = resp.data?.updateAlertStatus?.errors || [];
|
||||
|
||||
if (errors[0]) {
|
||||
this.$emit(
|
||||
'alert-error',
|
||||
`${this.$options.i18n.UPDATE_ALERT_STATUS_ERROR} ${errors[0]}`,
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$emit(
|
||||
'alert-error',
|
||||
`${this.$options.i18n.UPDATE_ALERT_STATUS_ERROR} ${this.$options.i18n.UPDATE_ALERT_STATUS_INSTRUCTION}`,
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
this.$emit('handle-updating', false);
|
||||
});
|
||||
},
|
||||
trackStatusUpdate(status) {
|
||||
const { category, action, label } = trackAlertStatusUpdateOptions;
|
||||
Tracking.event(category, action, { label, property: status });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dropdown dropdown-menu-selectable" :class="dropdownClass">
|
||||
<gl-dropdown
|
||||
ref="dropdown"
|
||||
right
|
||||
:text="$options.statuses[alert.status]"
|
||||
class="w-100"
|
||||
toggle-class="dropdown-menu-toggle"
|
||||
variant="outline-default"
|
||||
@keydown.esc.native="$emit('hide-dropdown')"
|
||||
@hide="$emit('hide-dropdown')"
|
||||
>
|
||||
<div v-if="isSidebar" class="dropdown-title text-center">
|
||||
<span class="alert-title">{{ s__('AlertManagement|Assign status') }}</span>
|
||||
<gl-button
|
||||
:aria-label="__('Close')"
|
||||
variant="link"
|
||||
class="dropdown-title-button dropdown-menu-close"
|
||||
icon="close"
|
||||
@click="$emit('hide-dropdown')"
|
||||
/>
|
||||
</div>
|
||||
<div class="dropdown-content dropdown-body">
|
||||
<gl-dropdown-item
|
||||
v-for="(label, field) in $options.statuses"
|
||||
:key="field"
|
||||
data-testid="statusDropdownItem"
|
||||
class="gl-vertical-align-middle"
|
||||
:active="label.toUpperCase() === alert.status"
|
||||
:active-class="'is-active'"
|
||||
@click="updateAlertStatus(label)"
|
||||
>
|
||||
{{ label }}
|
||||
</gl-dropdown-item>
|
||||
</div>
|
||||
</gl-dropdown>
|
||||
</div>
|
||||
</template>
|
|
@ -11,20 +11,26 @@ import {
|
|||
GlSprintf,
|
||||
} from '@gitlab/ui';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { s__ } from '~/locale';
|
||||
import alertSetAssignees from '../../graphql/mutations/alert_set_assignees.graphql';
|
||||
import { s__, __ } from '~/locale';
|
||||
import alertSetAssignees from '../../graphql/mutations/alert_set_assignees.mutation.graphql';
|
||||
import SidebarAssignee from './sidebar_assignee.vue';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
const DATA_REFETCH_DELAY = 250;
|
||||
|
||||
export default {
|
||||
FETCH_USERS_ERROR: s__(
|
||||
'AlertManagement|There was an error while updating the assignee(s) list. Please try again.',
|
||||
),
|
||||
UPDATE_ALERT_ASSIGNEES_ERROR: s__(
|
||||
'AlertManagement|There was an error while updating the assignee(s) of the alert. Please try again.',
|
||||
),
|
||||
i18n: {
|
||||
FETCH_USERS_ERROR: s__(
|
||||
'AlertManagement|There was an error while updating the assignee(s) list. Please try again.',
|
||||
),
|
||||
UPDATE_ALERT_ASSIGNEES_ERROR: s__(
|
||||
'AlertManagement|There was an error while updating the assignee(s) of the alert. Please try again.',
|
||||
),
|
||||
UPDATE_ALERT_ASSIGNEES_GRAPHQL_ERROR: s__(
|
||||
'AlertManagement|This assignee cannot be assigned to this alert.',
|
||||
),
|
||||
ASSIGNEES_BLOCK: s__('AlertManagement|Alert assignee(s): %{assignees}'),
|
||||
},
|
||||
components: {
|
||||
GlIcon,
|
||||
GlDropdown,
|
||||
|
@ -38,6 +44,10 @@ export default {
|
|||
SidebarAssignee,
|
||||
},
|
||||
props: {
|
||||
projectId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -73,7 +83,7 @@ export default {
|
|||
return this.alert?.assignees?.nodes[0]?.username;
|
||||
},
|
||||
assignedUser() {
|
||||
return this.userName || s__('AlertManagement|None');
|
||||
return this.userName || __('None');
|
||||
},
|
||||
sortedUsers() {
|
||||
return this.users
|
||||
|
@ -122,20 +132,20 @@ export default {
|
|||
updateAssigneesDropdown() {
|
||||
this.isDropdownSearching = true;
|
||||
return axios
|
||||
.get(this.buildUrl(gon.relative_url_root, '/autocomplete/users.json'), {
|
||||
.get(this.buildUrl(gon.relative_url_root, '/-/autocomplete/users.json'), {
|
||||
params: {
|
||||
search: this.search,
|
||||
per_page: 20,
|
||||
active: true,
|
||||
current_user: true,
|
||||
project_id: gon?.current_project_id,
|
||||
project_id: this.projectId,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
this.users = data;
|
||||
})
|
||||
.catch(() => {
|
||||
this.$emit('alert-sidebar-error', this.$options.FETCH_USERS_ERROR);
|
||||
this.$emit('alert-error', this.$options.i18n.FETCH_USERS_ERROR);
|
||||
})
|
||||
.finally(() => {
|
||||
this.isDropdownSearching = false;
|
||||
|
@ -152,12 +162,18 @@ export default {
|
|||
projectPath: this.projectPath,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
.then(({ data: { alertSetAssignees: { errors } = [] } = {} } = {}) => {
|
||||
this.hideDropdown();
|
||||
this.$emit('alert-refresh');
|
||||
|
||||
if (errors[0]) {
|
||||
this.$emit(
|
||||
'alert-error',
|
||||
`${this.$options.i18n.UPDATE_ALERT_ASSIGNEES_GRAPHQL_ERROR} ${errors[0]}.`,
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$emit('alert-sidebar-error', this.$options.UPDATE_ALERT_ASSIGNEES_ERROR);
|
||||
this.$emit('alert-error', this.$options.i18n.UPDATE_ALERT_ASSIGNEES_ERROR);
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdating = false;
|
||||
|
@ -174,7 +190,7 @@ export default {
|
|||
<gl-loading-icon v-if="isUpdating" />
|
||||
</div>
|
||||
<gl-tooltip :target="() => $refs.status" boundary="viewport" placement="left">
|
||||
<gl-sprintf :message="s__('AlertManagement|Alert assignee(s): %{assignees}')">
|
||||
<gl-sprintf :message="$options.i18n.ASSIGNEES_BLOCK">
|
||||
<template #assignees>
|
||||
{{ assignedUser }}
|
||||
</template>
|
||||
|
@ -183,7 +199,7 @@ export default {
|
|||
|
||||
<div class="hide-collapsed">
|
||||
<p class="title gl-display-flex gl-justify-content-space-between">
|
||||
{{ s__('AlertManagement|Assignee') }}
|
||||
{{ __('Assignee') }}
|
||||
<a
|
||||
v-if="isEditable"
|
||||
ref="editButton"
|
||||
|
@ -192,7 +208,7 @@ export default {
|
|||
@click="toggleFormDropdown"
|
||||
@keydown.esc="hideDropdown"
|
||||
>
|
||||
{{ s__('AlertManagement|Edit') }}
|
||||
{{ __('Edit') }}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
@ -207,7 +223,7 @@ export default {
|
|||
@hide="hideDropdown"
|
||||
>
|
||||
<div class="dropdown-title">
|
||||
<span class="alert-title">{{ s__('AlertManagement|Assign To') }}</span>
|
||||
<span class="alert-title">{{ __('Assign To') }}</span>
|
||||
<gl-button
|
||||
:aria-label="__('Close')"
|
||||
variant="link"
|
||||
|
@ -232,12 +248,12 @@ export default {
|
|||
active-class="is-active"
|
||||
@click="updateAlertAssignees('')"
|
||||
>
|
||||
{{ s__('AlertManagement|Unassigned') }}
|
||||
{{ __('Unassigned') }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-divider />
|
||||
|
||||
<gl-dropdown-header class="mt-0">
|
||||
{{ s__('AlertManagement|Assignee') }}
|
||||
{{ __('Assignee') }}
|
||||
</gl-dropdown-header>
|
||||
<sidebar-assignee
|
||||
v-for="user in sortedUsers"
|
||||
|
@ -248,7 +264,7 @@ export default {
|
|||
/>
|
||||
</template>
|
||||
<gl-dropdown-item v-else-if="userListEmpty">
|
||||
{{ s__('AlertManagement|No Matching Results') }}
|
||||
{{ __('No Matching Results') }}
|
||||
</gl-dropdown-item>
|
||||
<gl-loading-icon v-else />
|
||||
</div>
|
||||
|
@ -261,7 +277,7 @@ export default {
|
|||
assignedUser
|
||||
}}</span>
|
||||
<span v-else class="gl-display-flex gl-align-items-center">
|
||||
{{ s__('AlertManagement|None -') }}
|
||||
{{ __('None') }} -
|
||||
<gl-button
|
||||
class="gl-pl-2"
|
||||
href="#"
|
||||
|
@ -269,7 +285,7 @@ export default {
|
|||
data-testid="unassigned-users"
|
||||
@click="updateAlertAssignees(currentUser)"
|
||||
>
|
||||
{{ s__('AlertManagement| assign yourself') }}
|
||||
{{ __('assign yourself') }}
|
||||
</gl-button>
|
||||
</span>
|
||||
</p>
|
||||
|
|
|
@ -8,6 +8,14 @@ export default {
|
|||
SidebarTodo,
|
||||
},
|
||||
props: {
|
||||
alert: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
sidebarCollapsed: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
|
@ -17,18 +25,17 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="block d-flex justify-content-between">
|
||||
<div class="block gl-display-flex gl-justify-content-space-between">
|
||||
<span class="issuable-header-text hide-collapsed">
|
||||
{{ __('Quick actions') }}
|
||||
{{ __('To Do') }}
|
||||
</span>
|
||||
<toggle-sidebar
|
||||
:collapsed="sidebarCollapsed"
|
||||
css-classes="ml-auto"
|
||||
@toggle="$emit('toggle-sidebar')"
|
||||
<sidebar-todo
|
||||
v-if="!sidebarCollapsed"
|
||||
:project-path="projectPath"
|
||||
:alert="alert"
|
||||
:sidebar-collapsed="sidebarCollapsed"
|
||||
@alert-error="$emit('alert-error', $event)"
|
||||
/>
|
||||
<!-- TODO: Implement after or as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/215946 -->
|
||||
<template v-if="false">
|
||||
<sidebar-todo v-if="!sidebarCollapsed" :sidebar-collapsed="sidebarCollapsed" />
|
||||
</template>
|
||||
<toggle-sidebar :collapsed="sidebarCollapsed" @toggle="$emit('toggle-sidebar')" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,17 +1,7 @@
|
|||
<script>
|
||||
import {
|
||||
GlIcon,
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlLoadingIcon,
|
||||
GlTooltip,
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
} from '@gitlab/ui';
|
||||
import { GlIcon, GlLoadingIcon, GlTooltip, GlSprintf } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import Tracking from '~/tracking';
|
||||
import { trackAlertStatusUpdateOptions } from '../../constants';
|
||||
import updateAlertStatus from '../../graphql/mutations/update_alert_status.graphql';
|
||||
import AlertStatus from '../alert_status.vue';
|
||||
|
||||
export default {
|
||||
statuses: {
|
||||
|
@ -21,12 +11,10 @@ export default {
|
|||
},
|
||||
components: {
|
||||
GlIcon,
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlLoadingIcon,
|
||||
GlTooltip,
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
AlertStatus,
|
||||
},
|
||||
props: {
|
||||
projectPath: {
|
||||
|
@ -60,44 +48,13 @@ export default {
|
|||
},
|
||||
toggleFormDropdown() {
|
||||
this.isDropdownShowing = !this.isDropdownShowing;
|
||||
const { dropdown } = this.$refs.dropdown.$refs;
|
||||
const { dropdown } = this.$children[2].$refs.dropdown.$refs;
|
||||
if (dropdown && this.isDropdownShowing) {
|
||||
dropdown.show();
|
||||
}
|
||||
},
|
||||
isSelected(status) {
|
||||
return this.alert.status === status;
|
||||
},
|
||||
updateAlertStatus(status) {
|
||||
this.isUpdating = true;
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: updateAlertStatus,
|
||||
variables: {
|
||||
iid: this.alert.iid,
|
||||
status: status.toUpperCase(),
|
||||
projectPath: this.projectPath,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.trackStatusUpdate(status);
|
||||
this.hideDropdown();
|
||||
})
|
||||
.catch(() => {
|
||||
this.$emit(
|
||||
'alert-sidebar-error',
|
||||
s__(
|
||||
'AlertManagement|There was an error while updating the status of the alert. Please try again.',
|
||||
),
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdating = false;
|
||||
});
|
||||
},
|
||||
trackStatusUpdate(status) {
|
||||
const { category, action, label } = trackAlertStatusUpdateOptions;
|
||||
Tracking.event(category, action, { label, property: status });
|
||||
handleUpdating(updating) {
|
||||
this.isUpdating = updating;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -132,41 +89,15 @@ export default {
|
|||
</a>
|
||||
</p>
|
||||
|
||||
<div class="dropdown dropdown-menu-selectable" :class="dropdownClass">
|
||||
<gl-dropdown
|
||||
ref="dropdown"
|
||||
:text="$options.statuses[alert.status]"
|
||||
class="w-100"
|
||||
toggle-class="dropdown-menu-toggle"
|
||||
variant="outline-default"
|
||||
@keydown.esc.native="hideDropdown"
|
||||
@hide="hideDropdown"
|
||||
>
|
||||
<div class="dropdown-title">
|
||||
<span class="alert-title">{{ s__('AlertManagement|Assign status') }}</span>
|
||||
<gl-button
|
||||
:aria-label="__('Close')"
|
||||
variant="link"
|
||||
class="dropdown-title-button dropdown-menu-close"
|
||||
icon="close"
|
||||
@click="hideDropdown"
|
||||
/>
|
||||
</div>
|
||||
<div class="dropdown-content dropdown-body">
|
||||
<gl-dropdown-item
|
||||
v-for="(label, field) in $options.statuses"
|
||||
:key="field"
|
||||
data-testid="statusDropdownItem"
|
||||
class="gl-vertical-align-middle"
|
||||
:active="label.toUpperCase() === alert.status"
|
||||
:active-class="'is-active'"
|
||||
@click="updateAlertStatus(label)"
|
||||
>
|
||||
{{ label }}
|
||||
</gl-dropdown-item>
|
||||
</div>
|
||||
</gl-dropdown>
|
||||
</div>
|
||||
<alert-status
|
||||
:alert="alert"
|
||||
:project-path="projectPath"
|
||||
:is-dropdown-showing="isDropdownShowing"
|
||||
:is-sidebar="true"
|
||||
@alert-error="$emit('alert-error', $event)"
|
||||
@hide-dropdown="hideDropdown"
|
||||
@handle-updating="handleUpdating"
|
||||
/>
|
||||
|
||||
<gl-loading-icon v-if="isUpdating" :inline="true" />
|
||||
<p
|
||||
|
|
|
@ -1,29 +1,123 @@
|
|||
<script>
|
||||
import { s__ } from '~/locale';
|
||||
import Todo from '~/sidebar/components/todo_toggle/todo.vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import createAlertTodo from '../../graphql/mutations/alert_todo_create.graphql';
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
UPDATE_ALERT_TODO_ERROR: s__(
|
||||
'AlertManagement|There was an error while updating the To Do of the alert.',
|
||||
),
|
||||
},
|
||||
components: {
|
||||
Todo,
|
||||
},
|
||||
props: {
|
||||
alert: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
sidebarCollapsed: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isUpdating: false,
|
||||
isTodo: false,
|
||||
todo: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
alertID() {
|
||||
return parseInt(this.alert.iid, 10);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateToDoCount(add) {
|
||||
const oldCount = parseInt(document.querySelector('.todos-count').innerText, 10);
|
||||
const count = add ? oldCount + 1 : oldCount - 1;
|
||||
const headerTodoEvent = new CustomEvent('todo:toggle', {
|
||||
detail: {
|
||||
count,
|
||||
},
|
||||
});
|
||||
|
||||
return document.dispatchEvent(headerTodoEvent);
|
||||
},
|
||||
toggleTodo() {
|
||||
if (this.todo) {
|
||||
return this.markAsDone();
|
||||
}
|
||||
|
||||
this.isUpdating = true;
|
||||
return this.$apollo
|
||||
.mutate({
|
||||
mutation: createAlertTodo,
|
||||
variables: {
|
||||
iid: this.alert.iid,
|
||||
projectPath: this.projectPath,
|
||||
},
|
||||
})
|
||||
.then(({ data: { alertTodoCreate: { todo = {}, errors = [] } } = {} } = {}) => {
|
||||
if (errors[0]) {
|
||||
return this.$emit(
|
||||
'alert-error',
|
||||
`${this.$options.i18n.UPDATE_ALERT_TODO_ERROR} ${errors[0]}.`,
|
||||
);
|
||||
}
|
||||
|
||||
this.todo = todo.id;
|
||||
return this.updateToDoCount(true);
|
||||
})
|
||||
.catch(() => {
|
||||
this.$emit(
|
||||
'alert-error',
|
||||
`${this.$options.i18n.UPDATE_ALERT_TODO_ERROR} ${s__(
|
||||
'AlertManagement|Please try again.',
|
||||
)}`,
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdating = false;
|
||||
});
|
||||
},
|
||||
markAsDone() {
|
||||
this.isUpdating = true;
|
||||
|
||||
return axios
|
||||
.delete(`/dashboard/todos/${this.todo.split('/').pop()}`)
|
||||
.then(() => {
|
||||
this.todo = '';
|
||||
return this.updateToDoCount(false);
|
||||
})
|
||||
.catch(() => {
|
||||
this.$emit('alert-error', this.$options.i18n.UPDATE_ALERT_TODO_ERROR);
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdating = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- TODO: Implement after or as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/215946 -->
|
||||
<template>
|
||||
<div v-if="false" :class="{ 'block todo': sidebarCollapsed }">
|
||||
<div :class="{ 'block todo': sidebarCollapsed, 'gl-ml-auto': !sidebarCollapsed }">
|
||||
<todo
|
||||
data-testid="alert-todo-button"
|
||||
:collapsed="sidebarCollapsed"
|
||||
:issuable-id="1"
|
||||
:is-todo="false"
|
||||
:is-action-active="false"
|
||||
:issuable-id="alertID"
|
||||
:is-todo="todo !== ''"
|
||||
:is-action-active="isUpdating"
|
||||
issuable-type="alert"
|
||||
@toggleTodo="() => {}"
|
||||
@toggleTodo="toggleTodo"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -24,7 +24,7 @@ export default {
|
|||
return { ...author, id: id?.split('/').pop() };
|
||||
},
|
||||
iconHtml() {
|
||||
return spriteIcon('user');
|
||||
return spriteIcon(this.note?.systemNoteIconName);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,45 +3,59 @@ import VueApollo from 'vue-apollo';
|
|||
import createDefaultClient from '~/lib/graphql';
|
||||
import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
|
||||
import AlertDetails from './components/alert_details.vue';
|
||||
import sidebarStatusQuery from './graphql/queries/sidebar_status.query.graphql';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
export default selector => {
|
||||
const domEl = document.querySelector(selector);
|
||||
const { alertId, projectPath, projectIssuesPath } = domEl.dataset;
|
||||
const { alertId, projectPath, projectIssuesPath, projectId } = domEl.dataset;
|
||||
|
||||
const resolvers = {
|
||||
Mutation: {
|
||||
toggleSidebarStatus: (_, __, { cache }) => {
|
||||
const data = cache.readQuery({ query: sidebarStatusQuery });
|
||||
data.sidebarStatus = !data.sidebarStatus;
|
||||
cache.writeQuery({ query: sidebarStatusQuery, data });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(
|
||||
{},
|
||||
{
|
||||
cacheConfig: {
|
||||
dataIdFromObject: object => {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
if (object.__typename === 'AlertManagementAlert') {
|
||||
return object.iid;
|
||||
}
|
||||
return defaultDataIdFromObject(object);
|
||||
},
|
||||
defaultClient: createDefaultClient(resolvers, {
|
||||
cacheConfig: {
|
||||
dataIdFromObject: object => {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
if (object.__typename === 'AlertManagementAlert') {
|
||||
return object.iid;
|
||||
}
|
||||
return defaultDataIdFromObject(object);
|
||||
},
|
||||
},
|
||||
),
|
||||
}),
|
||||
});
|
||||
|
||||
apolloProvider.clients.defaultClient.cache.writeData({
|
||||
data: {
|
||||
sidebarStatus: false,
|
||||
},
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new Vue({
|
||||
el: selector,
|
||||
provide: {
|
||||
projectPath,
|
||||
alertId,
|
||||
projectIssuesPath,
|
||||
projectId,
|
||||
},
|
||||
apolloProvider,
|
||||
components: {
|
||||
AlertDetails,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('alert-details', {
|
||||
props: {
|
||||
alertId,
|
||||
projectPath,
|
||||
projectIssuesPath,
|
||||
},
|
||||
});
|
||||
return createElement('alert-details', {});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
#import "~/graphql_shared/fragments/author.fragment.graphql"
|
||||
|
||||
fragment AlertNote on Note {
|
||||
id
|
||||
author {
|
||||
id
|
||||
author {
|
||||
id
|
||||
state
|
||||
...Author
|
||||
}
|
||||
body
|
||||
bodyHtml
|
||||
createdAt
|
||||
discussion {
|
||||
id
|
||||
}
|
||||
state
|
||||
...Author
|
||||
}
|
||||
body
|
||||
bodyHtml
|
||||
createdAt
|
||||
discussion {
|
||||
id
|
||||
}
|
||||
systemNoteIconName
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@ fragment AlertDetailItem on AlertManagementAlert {
|
|||
...AlertListItem
|
||||
createdAt
|
||||
monitoringTool
|
||||
metricsDashboardUrl
|
||||
service
|
||||
description
|
||||
updatedAt
|
||||
endedAt
|
||||
details
|
||||
notes {
|
||||
nodes {
|
||||
|
|
|
@ -4,7 +4,6 @@ fragment AlertListItem on AlertManagementAlert {
|
|||
severity
|
||||
status
|
||||
startedAt
|
||||
endedAt
|
||||
eventCount
|
||||
issueIid
|
||||
assignees {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
mutation($projectPath: ID!, $assigneeUsernames: [String!]!, $iid: String!) {
|
||||
#import "../fragments/alert_note.fragment.graphql"
|
||||
|
||||
mutation alertSetAssignees($projectPath: ID!, $assigneeUsernames: [String!]!, $iid: String!) {
|
||||
alertSetAssignees(
|
||||
input: { iid: $iid, assigneeUsernames: $assigneeUsernames, projectPath: $projectPath }
|
||||
) {
|
||||
|
@ -10,6 +12,11 @@ mutation($projectPath: ID!, $assigneeUsernames: [String!]!, $iid: String!) {
|
|||
username
|
||||
}
|
||||
}
|
||||
notes {
|
||||
nodes {
|
||||
...AlertNote
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
mutation($projectPath: ID!, $iid: String!) {
|
||||
alertTodoCreate(input: { iid: $iid, projectPath: $projectPath }) {
|
||||
errors
|
||||
alert {
|
||||
iid
|
||||
}
|
||||
todo {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
mutation ($projectPath: ID!, $iid: String!) {
|
||||
createAlertIssue(input: { iid: $iid, projectPath: $projectPath }) {
|
||||
errors
|
||||
issue {
|
||||
iid
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
mutation createAlertIssue($projectPath: ID!, $iid: String!) {
|
||||
createAlertIssue(input: { iid: $iid, projectPath: $projectPath }) {
|
||||
errors
|
||||
issue {
|
||||
iid
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
mutation toggleSidebarStatus {
|
||||
toggleSidebarStatus @client
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
mutation ($projectPath: ID!, $status: AlertManagementStatus!, $iid: String!) {
|
||||
updateAlertStatus(input: { iid: $iid, status: $status, projectPath: $projectPath }) {
|
||||
errors
|
||||
alert {
|
||||
iid,
|
||||
status,
|
||||
endedAt
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#import "../fragments/alert_note.fragment.graphql"
|
||||
|
||||
mutation updateAlertStatus($projectPath: ID!, $status: AlertManagementStatus!, $iid: String!) {
|
||||
updateAlertStatus(input: { iid: $iid, status: $status, projectPath: $projectPath }) {
|
||||
errors
|
||||
alert {
|
||||
iid
|
||||
status
|
||||
endedAt
|
||||
notes {
|
||||
nodes {
|
||||
...AlertNote
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
#import "../fragments/detail_item.fragment.graphql"
|
||||
|
||||
query alertDetails($fullPath: ID!, $alertId: String) {
|
||||
project(fullPath: $fullPath) {
|
||||
alertManagementAlerts(iid: $alertId) {
|
||||
nodes {
|
||||
...AlertDetailItem
|
||||
}
|
||||
}
|
||||
project(fullPath: $fullPath) {
|
||||
alertManagementAlerts(iid: $alertId) {
|
||||
nodes {
|
||||
...AlertDetailItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
#import "../fragments/list_item.fragment.graphql"
|
||||
|
||||
query getAlerts(
|
||||
$projectPath: ID!,
|
||||
$statuses: [AlertManagementStatus!],
|
||||
$sort: AlertManagementAlertSort,
|
||||
$firstPageSize: Int,
|
||||
$lastPageSize: Int,
|
||||
$prevPageCursor: String = ""
|
||||
$nextPageCursor: String = ""
|
||||
$searchTerm: String
|
||||
$projectPath: ID!
|
||||
$statuses: [AlertManagementStatus!]
|
||||
$sort: AlertManagementAlertSort
|
||||
$firstPageSize: Int
|
||||
$lastPageSize: Int
|
||||
$prevPageCursor: String = ""
|
||||
$nextPageCursor: String = ""
|
||||
) {
|
||||
project(fullPath: $projectPath, ) {
|
||||
alertManagementAlerts(
|
||||
statuses: $statuses,
|
||||
sort: $sort,
|
||||
first: $firstPageSize
|
||||
last: $lastPageSize,
|
||||
after: $nextPageCursor,
|
||||
before: $prevPageCursor
|
||||
) {
|
||||
nodes {
|
||||
...AlertListItem
|
||||
},
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
}
|
||||
}
|
||||
project(fullPath: $projectPath) {
|
||||
alertManagementAlerts(
|
||||
search: $searchTerm
|
||||
statuses: $statuses
|
||||
sort: $sort
|
||||
first: $firstPageSize
|
||||
last: $lastPageSize
|
||||
after: $nextPageCursor
|
||||
before: $prevPageCursor
|
||||
) {
|
||||
nodes {
|
||||
...AlertListItem
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
query getAlertsCount($projectPath: ID!) {
|
||||
project(fullPath: $projectPath) {
|
||||
alertManagementAlertStatusCounts {
|
||||
all
|
||||
open
|
||||
acknowledged
|
||||
resolved
|
||||
triggered
|
||||
}
|
||||
query getAlertsCount($searchTerm: String, $projectPath: ID!) {
|
||||
project(fullPath: $projectPath) {
|
||||
alertManagementAlertStatusCounts(search: $searchTerm) {
|
||||
all
|
||||
open
|
||||
acknowledged
|
||||
resolved
|
||||
triggered
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
query sidebarStatus {
|
||||
sidebarStatus @client
|
||||
}
|
|
@ -3,7 +3,7 @@ import VueApollo from 'vue-apollo';
|
|||
import createDefaultClient from '~/lib/graphql';
|
||||
import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import AlertManagementList from './components/alert_management_list.vue';
|
||||
import AlertManagementList from './components/alert_management_list_wrapper.vue';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
|
@ -11,11 +11,18 @@ export default () => {
|
|||
const selector = '#js-alert_management';
|
||||
|
||||
const domEl = document.querySelector(selector);
|
||||
const { projectPath, enableAlertManagementPath, emptyAlertSvgPath } = domEl.dataset;
|
||||
let { alertManagementEnabled, userCanEnableAlertManagement } = domEl.dataset;
|
||||
const {
|
||||
projectPath,
|
||||
enableAlertManagementPath,
|
||||
emptyAlertSvgPath,
|
||||
populatingAlertsHelpUrl,
|
||||
opsgenieMvcTargetUrl,
|
||||
} = domEl.dataset;
|
||||
let { alertManagementEnabled, userCanEnableAlertManagement, opsgenieMvcEnabled } = domEl.dataset;
|
||||
|
||||
alertManagementEnabled = parseBoolean(alertManagementEnabled);
|
||||
userCanEnableAlertManagement = parseBoolean(userCanEnableAlertManagement);
|
||||
opsgenieMvcEnabled = parseBoolean(opsgenieMvcEnabled);
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(
|
||||
|
@ -45,9 +52,12 @@ export default () => {
|
|||
props: {
|
||||
projectPath,
|
||||
enableAlertManagementPath,
|
||||
populatingAlertsHelpUrl,
|
||||
emptyAlertSvgPath,
|
||||
alertManagementEnabled,
|
||||
userCanEnableAlertManagement,
|
||||
opsgenieMvcTargetUrl,
|
||||
opsgenieMvcEnabled,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
@ -64,6 +64,11 @@ export default {
|
|||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
isDisabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -142,7 +147,7 @@ export default {
|
|||
<gl-form-group :label="__('Active')" label-for="activated" label-class="label-bold">
|
||||
<toggle-button
|
||||
id="activated"
|
||||
:disabled-input="loadingActivated"
|
||||
:disabled-input="loadingActivated || isDisabled"
|
||||
:is-loading="loadingActivated"
|
||||
:value="activated"
|
||||
@change="toggleActivated"
|
||||
|
@ -152,7 +157,11 @@ export default {
|
|||
<div class="input-group">
|
||||
<gl-form-input id="url" :readonly="true" :value="url" />
|
||||
<span class="input-group-append">
|
||||
<clipboard-button :text="url" :title="$options.COPY_TO_CLIPBOARD" />
|
||||
<clipboard-button
|
||||
:text="url"
|
||||
:title="$options.COPY_TO_CLIPBOARD"
|
||||
:disabled="isDisabled"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</gl-form-group>
|
||||
|
@ -164,10 +173,16 @@ export default {
|
|||
<div class="input-group">
|
||||
<gl-form-input id="authorization-key" :readonly="true" :value="authorizationKey" />
|
||||
<span class="input-group-append">
|
||||
<clipboard-button :text="authorizationKey" :title="$options.COPY_TO_CLIPBOARD" />
|
||||
<clipboard-button
|
||||
:text="authorizationKey"
|
||||
:title="$options.COPY_TO_CLIPBOARD"
|
||||
:disabled="isDisabled"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<gl-button v-gl-modal.authKeyModal class="mt-2">{{ $options.RESET_KEY }}</gl-button>
|
||||
<gl-button v-gl-modal.authKeyModal class="mt-2" :disabled="isDisabled">{{
|
||||
$options.RESET_KEY
|
||||
}}</gl-button>
|
||||
<gl-modal
|
||||
modal-id="authKeyModal"
|
||||
:title="$options.RESET_KEY"
|
||||
|
|
|
@ -14,8 +14,11 @@ export default el => {
|
|||
formPath,
|
||||
authorizationKey,
|
||||
url,
|
||||
disabled,
|
||||
} = el.dataset;
|
||||
|
||||
const activated = parseBoolean(activatedStr);
|
||||
const isDisabled = parseBoolean(disabled);
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
|
@ -28,6 +31,7 @@ export default el => {
|
|||
formPath,
|
||||
initialAuthorizationKey: authorizationKey,
|
||||
url,
|
||||
isDisabled,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
@ -0,0 +1,563 @@
|
|||
<script>
|
||||
import {
|
||||
GlAlert,
|
||||
GlButton,
|
||||
GlForm,
|
||||
GlFormGroup,
|
||||
GlFormInput,
|
||||
GlFormInputGroup,
|
||||
GlFormTextarea,
|
||||
GlLink,
|
||||
GlModal,
|
||||
GlModalDirective,
|
||||
GlSprintf,
|
||||
GlFormSelect,
|
||||
} from '@gitlab/ui';
|
||||
import { debounce } from 'lodash';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import ToggleButton from '~/vue_shared/components/toggle_button.vue';
|
||||
import csrf from '~/lib/utils/csrf';
|
||||
import service from '../services';
|
||||
import {
|
||||
i18n,
|
||||
serviceOptions,
|
||||
JSON_VALIDATE_DELAY,
|
||||
targetPrometheusUrlPlaceholder,
|
||||
targetOpsgenieUrlPlaceholder,
|
||||
} from '../constants';
|
||||
|
||||
export default {
|
||||
i18n,
|
||||
csrf,
|
||||
targetOpsgenieUrlPlaceholder,
|
||||
targetPrometheusUrlPlaceholder,
|
||||
components: {
|
||||
GlAlert,
|
||||
GlButton,
|
||||
GlForm,
|
||||
GlFormGroup,
|
||||
GlFormInput,
|
||||
GlFormInputGroup,
|
||||
GlFormSelect,
|
||||
GlFormTextarea,
|
||||
GlLink,
|
||||
GlModal,
|
||||
GlSprintf,
|
||||
ClipboardButton,
|
||||
ToggleButton,
|
||||
},
|
||||
directives: {
|
||||
'gl-modal': GlModalDirective,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
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() {
|
||||
return {
|
||||
activated: {
|
||||
generic: this.generic.activated,
|
||||
prometheus: this.prometheus.activated,
|
||||
opsgenie: this.opsgenie?.activated,
|
||||
},
|
||||
loading: false,
|
||||
authorizationKey: {
|
||||
generic: this.generic.initialAuthorizationKey,
|
||||
prometheus: this.prometheus.prometheusAuthorizationKey,
|
||||
},
|
||||
selectedEndpoint: serviceOptions[0].value,
|
||||
options: serviceOptions,
|
||||
targetUrl: null,
|
||||
feedback: {
|
||||
variant: 'danger',
|
||||
feedbackMessage: null,
|
||||
isFeedbackDismissed: false,
|
||||
},
|
||||
serverError: null,
|
||||
testAlert: {
|
||||
json: null,
|
||||
error: null,
|
||||
},
|
||||
canSaveForm: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
sections() {
|
||||
return [
|
||||
{
|
||||
text: this.$options.i18n.usageSection,
|
||||
url: this.generic.alertsUsageUrl,
|
||||
},
|
||||
{
|
||||
text: this.$options.i18n.setupSection,
|
||||
url: this.generic.alertsSetupUrl,
|
||||
},
|
||||
];
|
||||
},
|
||||
isPrometheus() {
|
||||
return this.selectedEndpoint === 'prometheus';
|
||||
},
|
||||
isOpsgenie() {
|
||||
return this.selectedEndpoint === 'opsgenie';
|
||||
},
|
||||
selectedService() {
|
||||
switch (this.selectedEndpoint) {
|
||||
case 'generic': {
|
||||
return {
|
||||
url: this.generic.url,
|
||||
authKey: this.authorizationKey.generic,
|
||||
active: this.activated.generic,
|
||||
resetKey: this.resetGenericKey.bind(this),
|
||||
};
|
||||
}
|
||||
case 'prometheus': {
|
||||
return {
|
||||
url: this.prometheus.prometheusUrl,
|
||||
authKey: this.authorizationKey.prometheus,
|
||||
active: this.activated.prometheus,
|
||||
resetKey: this.resetPrometheusKey.bind(this),
|
||||
targetUrl: this.prometheus.prometheusApiUrl,
|
||||
};
|
||||
}
|
||||
case 'opsgenie': {
|
||||
return {
|
||||
targetUrl: this.opsgenie.opsgenieMvcTargetUrl,
|
||||
active: this.activated.opsgenie,
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
showFeedbackMsg() {
|
||||
return this.feedback.feedbackMessage && !this.isFeedbackDismissed;
|
||||
},
|
||||
showAlertSave() {
|
||||
return (
|
||||
this.feedback.feedbackMessage === this.$options.i18n.testAlertFailed &&
|
||||
!this.isFeedbackDismissed
|
||||
);
|
||||
},
|
||||
prometheusInfo() {
|
||||
return this.isPrometheus ? this.$options.i18n.prometheusInfo : '';
|
||||
},
|
||||
jsonIsValid() {
|
||||
return this.testAlert.error === null;
|
||||
},
|
||||
canTestAlert() {
|
||||
return this.selectedService.active && this.testAlert.json !== null;
|
||||
},
|
||||
canSaveConfig() {
|
||||
return !this.loading && this.canSaveForm;
|
||||
},
|
||||
baseUrlPlaceholder() {
|
||||
return this.isOpsgenie
|
||||
? this.$options.targetOpsgenieUrlPlaceholder
|
||||
: this.$options.targetPrometheusUrlPlaceholder;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'testAlert.json': debounce(function debouncedJsonValidate() {
|
||||
this.validateJson();
|
||||
}, JSON_VALIDATE_DELAY),
|
||||
targetUrl(oldVal, newVal) {
|
||||
if (newVal && oldVal !== this.selectedService.targetUrl) {
|
||||
this.canSaveForm = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (
|
||||
this.activated.prometheus ||
|
||||
this.activated.generic ||
|
||||
!this.opsgenie.opsgenieMvcIsAvailable
|
||||
) {
|
||||
this.removeOpsGenieOption();
|
||||
} else if (this.activated.opsgenie) {
|
||||
this.setOpsgenieAsDefault();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createUserErrorMessage(errors) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
this.serverError = Object.values(errors)[0][0];
|
||||
},
|
||||
setOpsgenieAsDefault() {
|
||||
this.options = this.options.map(el => {
|
||||
if (el.value !== 'opsgenie') {
|
||||
return { ...el, disabled: true };
|
||||
}
|
||||
return { ...el, disabled: false };
|
||||
});
|
||||
this.selectedEndpoint = this.options.find(({ value }) => value === 'opsgenie').value;
|
||||
if (this.targetUrl === null) {
|
||||
this.targetUrl = this.selectedService.targetUrl;
|
||||
}
|
||||
},
|
||||
removeOpsGenieOption() {
|
||||
this.options = this.options.map(el => {
|
||||
if (el.value !== 'opsgenie') {
|
||||
return { ...el, disabled: false };
|
||||
}
|
||||
return { ...el, disabled: true };
|
||||
});
|
||||
},
|
||||
resetFormValues() {
|
||||
this.testAlert.json = null;
|
||||
this.targetUrl = this.selectedService.targetUrl;
|
||||
},
|
||||
dismissFeedback() {
|
||||
this.serverError = null;
|
||||
this.feedback = { ...this.feedback, feedbackMessage: null };
|
||||
this.isFeedbackDismissed = false;
|
||||
},
|
||||
resetGenericKey() {
|
||||
return service
|
||||
.updateGenericKey({ endpoint: this.generic.formPath, params: { service: { token: '' } } })
|
||||
.then(({ data: { token } }) => {
|
||||
this.authorizationKey.generic = token;
|
||||
this.setFeedback({ feedbackMessage: this.$options.i18n.authKeyRest, variant: 'success' });
|
||||
})
|
||||
.catch(() => {
|
||||
this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' });
|
||||
});
|
||||
},
|
||||
resetPrometheusKey() {
|
||||
return service
|
||||
.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) {
|
||||
this.canSaveForm = true;
|
||||
if (this.isPrometheus) {
|
||||
this.activated.prometheus = value;
|
||||
} else {
|
||||
this.activated[this.selectedEndpoint] = value;
|
||||
}
|
||||
},
|
||||
toggle(value) {
|
||||
return this.isPrometheus ? this.togglePrometheusActive(value) : this.toggleActivated(value);
|
||||
},
|
||||
toggleActivated(value) {
|
||||
this.loading = true;
|
||||
return service
|
||||
.updateGenericActive({
|
||||
endpoint: this[this.selectedEndpoint].formPath,
|
||||
params: this.isOpsgenie
|
||||
? { service: { opsgenie_mvc_target_url: this.targetUrl, opsgenie_mvc_enabled: value } }
|
||||
: { service: { active: value } },
|
||||
})
|
||||
.then(() => {
|
||||
this.activated[this.selectedEndpoint] = value;
|
||||
this.toggleSuccess(value);
|
||||
|
||||
if (!this.isOpsgenie && value) {
|
||||
if (!this.selectedService.authKey) {
|
||||
return window.location.reload();
|
||||
}
|
||||
|
||||
return this.removeOpsGenieOption();
|
||||
}
|
||||
|
||||
if (this.isOpsgenie && value) {
|
||||
return this.setOpsgenieAsDefault();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-return-assign
|
||||
return (this.options = serviceOptions);
|
||||
})
|
||||
.catch(({ response: { data: { errors } = {} } = {} }) => {
|
||||
this.createUserErrorMessage(errors);
|
||||
this.setFeedback({
|
||||
feedbackMessage: `${this.$options.i18n.errorMsg}.`,
|
||||
variant: 'danger',
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
this.canSaveForm = false;
|
||||
});
|
||||
},
|
||||
togglePrometheusActive(value) {
|
||||
this.loading = true;
|
||||
return service
|
||||
.updatePrometheusActive({
|
||||
endpoint: this.prometheus.prometheusFormPath,
|
||||
params: {
|
||||
token: this.$options.csrf.token,
|
||||
config: value,
|
||||
url: this.targetUrl,
|
||||
redirect: window.location,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.activated.prometheus = value;
|
||||
this.toggleSuccess(value);
|
||||
this.removeOpsGenieOption();
|
||||
})
|
||||
.catch(({ response: { data: { errors } = {} } = {} }) => {
|
||||
this.createUserErrorMessage(errors);
|
||||
this.setFeedback({
|
||||
feedbackMessage: `${this.$options.i18n.errorMsg}.`,
|
||||
variant: 'danger',
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
this.canSaveForm = false;
|
||||
});
|
||||
},
|
||||
toggleSuccess(value) {
|
||||
if (value) {
|
||||
this.setFeedback({
|
||||
feedbackMessage: this.$options.i18n.endPointActivated,
|
||||
variant: 'info',
|
||||
});
|
||||
} else {
|
||||
this.setFeedback({
|
||||
feedbackMessage: this.$options.i18n.changesSaved,
|
||||
variant: 'info',
|
||||
});
|
||||
}
|
||||
},
|
||||
setFeedback({ feedbackMessage, variant }) {
|
||||
this.feedback = { feedbackMessage, variant };
|
||||
},
|
||||
validateJson() {
|
||||
this.testAlert.error = null;
|
||||
try {
|
||||
JSON.parse(this.testAlert.json);
|
||||
} catch (e) {
|
||||
this.testAlert.error = JSON.stringify(e.message);
|
||||
}
|
||||
},
|
||||
validateTestAlert() {
|
||||
this.loading = true;
|
||||
this.validateJson();
|
||||
return service
|
||||
.updateTestAlert({
|
||||
endpoint: this.selectedService.url,
|
||||
data: this.testAlert.json,
|
||||
authKey: this.selectedService.authKey,
|
||||
})
|
||||
.then(() => {
|
||||
this.setFeedback({
|
||||
feedbackMessage: this.$options.i18n.testAlertSuccess,
|
||||
variant: 'success',
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.setFeedback({
|
||||
feedbackMessage: this.$options.i18n.testAlertFailed,
|
||||
variant: 'danger',
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
onSubmit() {
|
||||
this.toggle(this.selectedService.active);
|
||||
},
|
||||
onReset() {
|
||||
this.testAlert.json = null;
|
||||
this.dismissFeedback();
|
||||
this.targetUrl = this.selectedService.targetUrl;
|
||||
|
||||
if (this.canSaveForm) {
|
||||
this.canSaveForm = false;
|
||||
this.activated[this.selectedEndpoint] = this[this.selectedEndpoint].activated;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<gl-alert v-if="showFeedbackMsg" :variant="feedback.variant" @dismiss="dismissFeedback">
|
||||
{{ feedback.feedbackMessage }}
|
||||
<br />
|
||||
<i v-if="serverError">{{ __('Error message:') }} {{ serverError }}</i>
|
||||
<gl-button
|
||||
v-if="showAlertSave"
|
||||
variant="danger"
|
||||
category="primary"
|
||||
class="gl-display-block gl-mt-3"
|
||||
@click="toggle(selectedService.active)"
|
||||
>
|
||||
{{ __('Save anyway') }}
|
||||
</gl-button>
|
||||
</gl-alert>
|
||||
<div data-testid="alert-settings-description" class="gl-mt-5">
|
||||
<p v-for="section in sections" :key="section.text">
|
||||
<gl-sprintf :message="section.text">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="section.url" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
</div>
|
||||
<gl-form @submit.prevent="onSubmit" @reset.prevent="onReset">
|
||||
<gl-form-group
|
||||
:label="$options.i18n.integrationsLabel"
|
||||
label-for="integrations"
|
||||
label-class="label-bold"
|
||||
>
|
||||
<gl-form-select
|
||||
v-model="selectedEndpoint"
|
||||
:options="options"
|
||||
data-testid="alert-settings-select"
|
||||
@change="resetFormValues"
|
||||
/>
|
||||
<span class="gl-text-gray-400">
|
||||
<gl-sprintf :message="$options.i18n.integrationsInfo">
|
||||
<template #link="{ content }">
|
||||
<gl-link
|
||||
class="gl-display-inline-block"
|
||||
href="https://gitlab.com/groups/gitlab-org/-/epics/3362"
|
||||
target="_blank"
|
||||
>{{ content }}</gl-link
|
||||
>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</span>
|
||||
</gl-form-group>
|
||||
<gl-form-group
|
||||
:label="$options.i18n.activeLabel"
|
||||
label-for="activated"
|
||||
label-class="label-bold"
|
||||
>
|
||||
<toggle-button
|
||||
id="activated"
|
||||
:disabled-input="loading"
|
||||
:is-loading="loading"
|
||||
:value="selectedService.active"
|
||||
@change="toggleService"
|
||||
/>
|
||||
</gl-form-group>
|
||||
<gl-form-group
|
||||
v-if="isOpsgenie || isPrometheus"
|
||||
:label="$options.i18n.apiBaseUrlLabel"
|
||||
label-for="api-url"
|
||||
label-class="label-bold"
|
||||
>
|
||||
<gl-form-input
|
||||
id="api-url"
|
||||
v-model="targetUrl"
|
||||
type="url"
|
||||
:placeholder="baseUrlPlaceholder"
|
||||
:disabled="!selectedService.active"
|
||||
/>
|
||||
<span class="gl-text-gray-400">
|
||||
{{ $options.i18n.apiBaseUrlHelpText }}
|
||||
</span>
|
||||
</gl-form-group>
|
||||
<template v-if="!isOpsgenie">
|
||||
<gl-form-group :label="$options.i18n.urlLabel" label-for="url" label-class="label-bold">
|
||||
<gl-form-input-group id="url" readonly :value="selectedService.url">
|
||||
<template #append>
|
||||
<clipboard-button
|
||||
:text="selectedService.url"
|
||||
:title="$options.i18n.copyToClipboard"
|
||||
class="gl-m-0!"
|
||||
/>
|
||||
</template>
|
||||
</gl-form-input-group>
|
||||
<span class="gl-text-gray-400">
|
||||
{{ prometheusInfo }}
|
||||
</span>
|
||||
</gl-form-group>
|
||||
<gl-form-group
|
||||
:label="$options.i18n.authKeyLabel"
|
||||
label-for="authorization-key"
|
||||
label-class="label-bold"
|
||||
>
|
||||
<gl-form-input-group
|
||||
id="authorization-key"
|
||||
class="gl-mb-2"
|
||||
readonly
|
||||
:value="selectedService.authKey"
|
||||
>
|
||||
<template #append>
|
||||
<clipboard-button
|
||||
:text="selectedService.authKey || ''"
|
||||
:title="$options.i18n.copyToClipboard"
|
||||
class="gl-m-0!"
|
||||
/>
|
||||
</template>
|
||||
</gl-form-input-group>
|
||||
<gl-button v-gl-modal.authKeyModal :disabled="!selectedService.active" class="gl-mt-3">{{
|
||||
$options.i18n.resetKey
|
||||
}}</gl-button>
|
||||
<gl-modal
|
||||
modal-id="authKeyModal"
|
||||
:title="$options.i18n.resetKey"
|
||||
:ok-title="$options.i18n.resetKey"
|
||||
ok-variant="danger"
|
||||
@ok="selectedService.resetKey"
|
||||
>
|
||||
{{ $options.i18n.restKeyInfo }}
|
||||
</gl-modal>
|
||||
</gl-form-group>
|
||||
<gl-form-group
|
||||
:label="$options.i18n.alertJson"
|
||||
label-for="alert-json"
|
||||
label-class="label-bold"
|
||||
:invalid-feedback="testAlert.error"
|
||||
>
|
||||
<gl-form-textarea
|
||||
id="alert-json"
|
||||
v-model.trim="testAlert.json"
|
||||
:disabled="!selectedService.active"
|
||||
:state="jsonIsValid"
|
||||
:placeholder="$options.i18n.alertJsonPlaceholder"
|
||||
rows="6"
|
||||
max-rows="10"
|
||||
/>
|
||||
</gl-form-group>
|
||||
<gl-button :disabled="!canTestAlert" @click="validateTestAlert">{{
|
||||
$options.i18n.testAlertInfo
|
||||
}}</gl-button>
|
||||
</template>
|
||||
<div class="footer-block row-content-block gl-display-flex gl-justify-content-space-between">
|
||||
<gl-button
|
||||
variant="success"
|
||||
category="primary"
|
||||
:disabled="!canSaveConfig"
|
||||
@click="onSubmit"
|
||||
>
|
||||
{{ __('Save changes') }}
|
||||
</gl-button>
|
||||
<gl-button variant="default" category="primary" :disabled="!canSaveConfig" @click="onReset">
|
||||
{{ __('Cancel') }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</gl-form>
|
||||
</div>
|
||||
</template>
|
50
app/assets/javascripts/alerts_settings/constants.js
Normal file
50
app/assets/javascripts/alerts_settings/constants.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { s__ } from '~/locale';
|
||||
|
||||
export const i18n = {
|
||||
usageSection: s__(
|
||||
'AlertSettings|You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page.',
|
||||
),
|
||||
setupSection: s__(
|
||||
"AlertSettings|Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.",
|
||||
),
|
||||
errorMsg: s__('AlertSettings|There was an error updating the alert settings'),
|
||||
errorKeyMsg: s__(
|
||||
'AlertSettings|There was an error while trying to reset the key. Please refresh the page to try again.',
|
||||
),
|
||||
restKeyInfo: s__(
|
||||
'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.',
|
||||
),
|
||||
endPointActivated: s__('AlertSettings|Alerts endpoint successfully activated.'),
|
||||
changesSaved: s__('AlertSettings|Your changes were successfully updated.'),
|
||||
prometheusInfo: s__('AlertSettings|Add URL and auth key to your Prometheus config file'),
|
||||
integrationsInfo: s__(
|
||||
'AlertSettings|Learn more about our %{linkStart}upcoming integrations%{linkEnd}',
|
||||
),
|
||||
resetKey: s__('AlertSettings|Reset key'),
|
||||
copyToClipboard: s__('AlertSettings|Copy'),
|
||||
integrationsLabel: s__('AlertSettings|Integrations'),
|
||||
apiBaseUrlLabel: s__('AlertSettings|API URL'),
|
||||
authKeyLabel: s__('AlertSettings|Authorization key'),
|
||||
urlLabel: s__('AlertSettings|Webhook URL'),
|
||||
activeLabel: s__('AlertSettings|Active'),
|
||||
apiBaseUrlHelpText: s__('AlertSettings|URL cannot be blank and must start with http or https'),
|
||||
testAlertInfo: s__('AlertSettings|Test alert payload'),
|
||||
alertJson: s__('AlertSettings|Alert test payload'),
|
||||
alertJsonPlaceholder: s__('AlertSettings|Enter test alert JSON....'),
|
||||
testAlertFailed: s__('AlertSettings|Test failed. Do you still want to save your changes anyway?'),
|
||||
testAlertSuccess: s__(
|
||||
'AlertSettings|Test alert sent successfully. If you have made other changes, please save them now.',
|
||||
),
|
||||
authKeyRest: s__('AlertSettings|Authorization key has been successfully reset'),
|
||||
};
|
||||
|
||||
export const serviceOptions = [
|
||||
{ value: 'generic', text: s__('AlertSettings|Generic') },
|
||||
{ value: 'prometheus', text: s__('AlertSettings|External Prometheus') },
|
||||
{ value: 'opsgenie', text: s__('AlertSettings|Opsgenie') },
|
||||
];
|
||||
|
||||
export const JSON_VALIDATE_DELAY = 250;
|
||||
|
||||
export const targetPrometheusUrlPlaceholder = 'http://prometheus.example.com/';
|
||||
export const targetOpsgenieUrlPlaceholder = 'https://app.opsgenie.com/alert/list/';
|
67
app/assets/javascripts/alerts_settings/index.js
Normal file
67
app/assets/javascripts/alerts_settings/index.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
import Vue from 'vue';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import AlertSettingsForm from './components/alerts_settings_form.vue';
|
||||
|
||||
export default el => {
|
||||
if (!el) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
prometheusActivated,
|
||||
prometheusUrl,
|
||||
prometheusAuthorizationKey,
|
||||
prometheusFormPath,
|
||||
prometheusResetKeyPath,
|
||||
prometheusApiUrl,
|
||||
activated: activatedStr,
|
||||
alertsSetupUrl,
|
||||
alertsUsageUrl,
|
||||
formPath,
|
||||
authorizationKey,
|
||||
url,
|
||||
opsgenieMvcAvailable,
|
||||
opsgenieMvcFormPath,
|
||||
opsgenieMvcEnabled,
|
||||
opsgenieMvcTargetUrl,
|
||||
} = el.dataset;
|
||||
|
||||
const genericActivated = parseBoolean(activatedStr);
|
||||
const prometheusIsActivated = parseBoolean(prometheusActivated);
|
||||
const opsgenieMvcActivated = parseBoolean(opsgenieMvcEnabled);
|
||||
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({
|
||||
el,
|
||||
render(createElement) {
|
||||
return createElement(AlertSettingsForm, {
|
||||
props,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
36
app/assets/javascripts/alerts_settings/services/index.js
Normal file
36
app/assets/javascripts/alerts_settings/services/index.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
export default {
|
||||
updateGenericKey({ endpoint, params }) {
|
||||
return axios.put(endpoint, params);
|
||||
},
|
||||
updatePrometheusKey({ endpoint }) {
|
||||
return axios.post(endpoint);
|
||||
},
|
||||
updateGenericActive({ endpoint, params }) {
|
||||
return axios.put(endpoint, params);
|
||||
},
|
||||
updatePrometheusActive({ endpoint, params: { token, config, url, redirect } }) {
|
||||
const data = new FormData();
|
||||
data.set('_method', 'put');
|
||||
data.set('authenticity_token', token);
|
||||
data.set('service[manual_configuration]', config);
|
||||
data.set('service[api_url]', url);
|
||||
data.set('redirect_to', redirect);
|
||||
|
||||
return axios.post(endpoint, data, {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
});
|
||||
},
|
||||
updateTestAlert({ endpoint, data, authKey }) {
|
||||
return axios.post(endpoint, data, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${authKey}`,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
|
@ -11,6 +11,9 @@ const Api = {
|
|||
groupMembersPath: '/api/:version/groups/:id/members',
|
||||
subgroupsPath: '/api/:version/groups/:id/subgroups',
|
||||
namespacesPath: '/api/:version/namespaces.json',
|
||||
groupPackagesPath: '/api/:version/groups/:id/packages',
|
||||
projectPackagesPath: '/api/:version/projects/:id/packages',
|
||||
projectPackagePath: '/api/:version/projects/:id/packages/:package_id',
|
||||
groupProjectsPath: '/api/:version/groups/:id/projects.json',
|
||||
projectsPath: '/api/:version/projects.json',
|
||||
projectPath: '/api/:version/projects/:id',
|
||||
|
@ -36,7 +39,9 @@ const Api = {
|
|||
userStatusPath: '/api/:version/users/:id/status',
|
||||
userProjectsPath: '/api/:version/users/:id/projects',
|
||||
userPostStatusPath: '/api/:version/user/status',
|
||||
commitPath: '/api/:version/projects/:id/repository/commits',
|
||||
commitPath: '/api/:version/projects/:id/repository/commits/:sha',
|
||||
commitsPath: '/api/:version/projects/:id/repository/commits',
|
||||
|
||||
applySuggestionPath: '/api/:version/suggestions/:id/apply',
|
||||
applySuggestionBatchPath: '/api/:version/suggestions/batch_apply',
|
||||
commitPipelinesPath: '/:project_id/commit/:sha/pipelines',
|
||||
|
@ -64,6 +69,32 @@ const Api = {
|
|||
});
|
||||
},
|
||||
|
||||
groupPackages(id, options = {}) {
|
||||
const url = Api.buildUrl(this.groupPackagesPath).replace(':id', id);
|
||||
return axios.get(url, options);
|
||||
},
|
||||
|
||||
projectPackages(id, options = {}) {
|
||||
const url = Api.buildUrl(this.projectPackagesPath).replace(':id', id);
|
||||
return axios.get(url, options);
|
||||
},
|
||||
|
||||
buildProjectPackageUrl(projectId, packageId) {
|
||||
return Api.buildUrl(this.projectPackagePath)
|
||||
.replace(':id', projectId)
|
||||
.replace(':package_id', packageId);
|
||||
},
|
||||
|
||||
projectPackage(projectId, packageId) {
|
||||
const url = this.buildProjectPackageUrl(projectId, packageId);
|
||||
return axios.get(url);
|
||||
},
|
||||
|
||||
deleteProjectPackage(projectId, packageId) {
|
||||
const url = this.buildProjectPackageUrl(projectId, packageId);
|
||||
return axios.delete(url);
|
||||
},
|
||||
|
||||
groupMembers(id, options) {
|
||||
const url = Api.buildUrl(this.groupMembersPath).replace(':id', encodeURIComponent(id));
|
||||
|
||||
|
@ -308,9 +339,17 @@ const Api = {
|
|||
.catch(() => flash(__('Something went wrong while fetching projects')));
|
||||
},
|
||||
|
||||
commit(id, sha, params = {}) {
|
||||
const url = Api.buildUrl(this.commitPath)
|
||||
.replace(':id', encodeURIComponent(id))
|
||||
.replace(':sha', encodeURIComponent(sha));
|
||||
|
||||
return axios.get(url, { params });
|
||||
},
|
||||
|
||||
commitMultiple(id, data) {
|
||||
// see https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
|
||||
const url = Api.buildUrl(Api.commitPath).replace(':id', encodeURIComponent(id));
|
||||
const url = Api.buildUrl(Api.commitsPath).replace(':id', encodeURIComponent(id));
|
||||
return axios.post(url, JSON.stringify(data), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
|
|
|
@ -9,14 +9,10 @@ import { updateTooltipTitle } from './lib/utils/common_utils';
|
|||
import { isInVueNoteablePage } from './lib/utils/dom_utils';
|
||||
import flash from './flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import * as Emoji from '~/emoji';
|
||||
|
||||
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
|
||||
const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd';
|
||||
const requestAnimationFrame =
|
||||
window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.setTimeout;
|
||||
|
||||
const FROM_SENTENCE_REGEX = /(?:, and | and |, )/; // For separating lists produced by ruby's Array#toSentence
|
||||
|
||||
|
@ -619,7 +615,7 @@ export class AwardsHandler {
|
|||
let awardsHandlerPromise = null;
|
||||
export default function loadAwardsHandler(reload = false) {
|
||||
if (!awardsHandlerPromise || reload) {
|
||||
awardsHandlerPromise = import(/* webpackChunkName: 'emoji' */ './emoji').then(Emoji => {
|
||||
awardsHandlerPromise = Emoji.initEmojiMap().then(() => {
|
||||
const awardsHandler = new AwardsHandler(Emoji);
|
||||
awardsHandler.bindEvents();
|
||||
return awardsHandler;
|
||||
|
|
|
@ -164,7 +164,7 @@ export default {
|
|||
<template>
|
||||
<form
|
||||
:class="{ 'was-validated': wasValidated }"
|
||||
class="prepend-top-default append-bottom-default needs-validation"
|
||||
class="gl-mt-3 gl-mb-3 needs-validation"
|
||||
novalidate
|
||||
@submit.prevent.stop="onSubmit"
|
||||
>
|
||||
|
|
|
@ -51,6 +51,7 @@ export default {
|
|||
'scrollToDraft',
|
||||
'toggleResolveDiscussion',
|
||||
]),
|
||||
...mapActions(['setSelectedCommentPositionHover']),
|
||||
update(data) {
|
||||
this.updateDraft(data);
|
||||
},
|
||||
|
@ -67,12 +68,16 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<article class="draft-note-component note-wrapper">
|
||||
<article
|
||||
class="draft-note-component note-wrapper"
|
||||
@mouseenter="setSelectedCommentPositionHover(draft.position.line_range)"
|
||||
@mouseleave="setSelectedCommentPositionHover()"
|
||||
>
|
||||
<ul class="notes draft-notes">
|
||||
<noteable-note
|
||||
:note="draft"
|
||||
:diff-lines="diffFile.highlighted_diff_lines"
|
||||
:line="line"
|
||||
:discussion-root="true"
|
||||
class="draft-note"
|
||||
@handleEdit="handleEditing"
|
||||
@cancelForm="handleNotEditing"
|
||||
|
@ -81,7 +86,7 @@ export default {
|
|||
@handleUpdateNote="update"
|
||||
@toggleResolveStatus="toggleResolveDiscussion(draft.id)"
|
||||
>
|
||||
<strong slot="note-header-info" class="badge draft-pending-label append-right-4">
|
||||
<strong slot="note-header-info" class="badge draft-pending-label gl-mr-2">
|
||||
{{ __('Pending') }}
|
||||
</strong>
|
||||
</noteable-note>
|
||||
|
|
|
@ -35,11 +35,15 @@ export default {
|
|||
<tr :class="className" class="notes_holder">
|
||||
<td class="notes_line old"></td>
|
||||
<td class="notes-content parallel old" colspan="2">
|
||||
<div v-if="leftDraft.isDraft" class="content"><draft-note :draft="leftDraft" /></div>
|
||||
<div v-if="leftDraft.isDraft" class="content">
|
||||
<draft-note :draft="leftDraft" :line="line.left" />
|
||||
</div>
|
||||
</td>
|
||||
<td class="notes_line new"></td>
|
||||
<td class="notes-content parallel new" colspan="2">
|
||||
<div v-if="rightDraft.isDraft" class="content"><draft-note :draft="rightDraft" /></div>
|
||||
<div v-if="rightDraft.isDraft" class="content">
|
||||
<draft-note :draft="rightDraft" :line="line.right" />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
|
|
@ -96,7 +96,7 @@ export default {
|
|||
<preview-item :draft="draft" :is-last="isLast(index)" />
|
||||
</li>
|
||||
</ul>
|
||||
<gl-loading-icon v-else size="lg" class="prepend-top-default append-bottom-default" />
|
||||
<gl-loading-icon v-else size="lg" class="gl-mt-3 gl-mb-3" />
|
||||
</div>
|
||||
<div class="dropdown-footer">
|
||||
<publish-button
|
||||
|
|
|
@ -52,14 +52,12 @@ export default {
|
|||
});
|
||||
},
|
||||
linePosition() {
|
||||
if (this.draft.position && this.draft.position.position_type === IMAGE_DIFF_POSITION_TYPE) {
|
||||
if (this.position?.position_type === IMAGE_DIFF_POSITION_TYPE) {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `${this.draft.position.x}x ${this.draft.position.y}y`;
|
||||
return `${this.position.x}x ${this.position.y}y`;
|
||||
}
|
||||
|
||||
const position = this.discussion ? this.discussion.position : this.draft.position;
|
||||
|
||||
return position?.new_line || position?.old_line;
|
||||
return this.position?.new_line || this.position?.old_line;
|
||||
},
|
||||
content() {
|
||||
const el = document.createElement('div');
|
||||
|
@ -70,11 +68,14 @@ export default {
|
|||
showLinePosition() {
|
||||
return this.draft.file_hash || this.isDiffDiscussion;
|
||||
},
|
||||
position() {
|
||||
return this.draft.position || this.discussion.position;
|
||||
},
|
||||
startLineNumber() {
|
||||
return getStartLineNumber(this.draft.position?.line_range);
|
||||
return getStartLineNumber(this.position?.line_range);
|
||||
},
|
||||
endLineNumber() {
|
||||
return getEndLineNumber(this.draft.position?.line_range);
|
||||
return getEndLineNumber(this.position?.line_range);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import $ from 'jquery';
|
||||
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
|
||||
|
||||
/**
|
||||
* This behavior collapses the right sidebar
|
||||
* if the window size changes
|
||||
*
|
||||
* @sentrify
|
||||
*/
|
||||
export default () => {
|
||||
const $sidebarGutterToggle = $('.js-sidebar-toggle');
|
||||
let bootstrapBreakpoint = bp.getBreakpointSize();
|
||||
|
||||
$(window).on('resize.app', () => {
|
||||
const oldBootstrapBreakpoint = bootstrapBreakpoint;
|
||||
bootstrapBreakpoint = bp.getBreakpointSize();
|
||||
|
||||
if (bootstrapBreakpoint !== oldBootstrapBreakpoint) {
|
||||
const breakpointSizes = ['md', 'sm', 'xs'];
|
||||
|
||||
if (breakpointSizes.includes(bootstrapBreakpoint)) {
|
||||
const $gutterIcon = $sidebarGutterToggle.find('i');
|
||||
if ($gutterIcon.hasClass('fa-angle-double-right')) {
|
||||
$sidebarGutterToggle.trigger('click');
|
||||
}
|
||||
|
||||
const sidebarGutterVueToggleEl = document.querySelector('.js-sidebar-vue-toggle');
|
||||
|
||||
// Sidebar has an icon which corresponds to collapsing the sidebar
|
||||
// only then trigger the click.
|
||||
if (sidebarGutterVueToggleEl) {
|
||||
const collapseIcon = sidebarGutterVueToggleEl.querySelector('i.fa-angle-double-right');
|
||||
|
||||
if (collapseIcon) {
|
||||
collapseIcon.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
|
@ -1,47 +1,69 @@
|
|||
import 'document-register-element';
|
||||
import isEmojiUnicodeSupported from '../emoji/support';
|
||||
import { initEmojiMap, getEmojiInfo, emojiFallbackImageSrc, emojiImageTag } from '../emoji';
|
||||
|
||||
class GlEmoji extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const emojiUnicode = this.textContent.trim();
|
||||
const { name, unicodeVersion, fallbackSrc, fallbackSpriteClass } = this.dataset;
|
||||
this.initialize();
|
||||
}
|
||||
initialize() {
|
||||
let emojiUnicode = this.textContent.trim();
|
||||
const { fallbackSpriteClass, fallbackSrc } = this.dataset;
|
||||
let { name, unicodeVersion } = this.dataset;
|
||||
|
||||
const isEmojiUnicode =
|
||||
this.childNodes &&
|
||||
Array.prototype.every.call(this.childNodes, childNode => childNode.nodeType === 3);
|
||||
const hasImageFallback = fallbackSrc && fallbackSrc.length > 0;
|
||||
const hasCssSpriteFalback = fallbackSpriteClass && fallbackSpriteClass.length > 0;
|
||||
return initEmojiMap().then(() => {
|
||||
if (!unicodeVersion) {
|
||||
const emojiInfo = getEmojiInfo(name);
|
||||
|
||||
if (emojiUnicode && isEmojiUnicode && !isEmojiUnicodeSupported(emojiUnicode, unicodeVersion)) {
|
||||
// CSS sprite fallback takes precedence over image fallback
|
||||
if (hasCssSpriteFalback) {
|
||||
if (!gon.emoji_sprites_css_added && gon.emoji_sprites_css_path) {
|
||||
const emojiSpriteLinkTag = document.createElement('link');
|
||||
emojiSpriteLinkTag.setAttribute('rel', 'stylesheet');
|
||||
emojiSpriteLinkTag.setAttribute('href', gon.emoji_sprites_css_path);
|
||||
document.head.appendChild(emojiSpriteLinkTag);
|
||||
gon.emoji_sprites_css_added = true;
|
||||
if (emojiInfo) {
|
||||
if (name !== emojiInfo.name) {
|
||||
({ name } = emojiInfo);
|
||||
this.dataset.name = emojiInfo.name;
|
||||
}
|
||||
unicodeVersion = emojiInfo.u;
|
||||
this.dataset.unicodeVersion = unicodeVersion;
|
||||
|
||||
emojiUnicode = emojiInfo.e;
|
||||
this.innerHTML = emojiInfo.e;
|
||||
|
||||
this.title = emojiInfo.d;
|
||||
}
|
||||
// IE 11 doesn't like adding multiple at once :(
|
||||
this.classList.add('emoji-icon');
|
||||
this.classList.add(fallbackSpriteClass);
|
||||
} else {
|
||||
import(/* webpackChunkName: 'emoji' */ '../emoji')
|
||||
.then(({ emojiImageTag, emojiFallbackImageSrc }) => {
|
||||
if (hasImageFallback) {
|
||||
this.innerHTML = emojiImageTag(name, fallbackSrc);
|
||||
} else {
|
||||
const src = emojiFallbackImageSrc(name);
|
||||
this.innerHTML = emojiImageTag(name, src);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// do nothing
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const isEmojiUnicode =
|
||||
this.childNodes &&
|
||||
Array.prototype.every.call(this.childNodes, childNode => childNode.nodeType === 3);
|
||||
|
||||
if (
|
||||
emojiUnicode &&
|
||||
isEmojiUnicode &&
|
||||
!isEmojiUnicodeSupported(emojiUnicode, unicodeVersion)
|
||||
) {
|
||||
const hasImageFallback = fallbackSrc && fallbackSrc.length > 0;
|
||||
const hasCssSpriteFallback = fallbackSpriteClass && fallbackSpriteClass.length > 0;
|
||||
|
||||
// CSS sprite fallback takes precedence over image fallback
|
||||
if (hasCssSpriteFallback) {
|
||||
if (!gon.emoji_sprites_css_added && gon.emoji_sprites_css_path) {
|
||||
const emojiSpriteLinkTag = document.createElement('link');
|
||||
emojiSpriteLinkTag.setAttribute('rel', 'stylesheet');
|
||||
emojiSpriteLinkTag.setAttribute('href', gon.emoji_sprites_css_path);
|
||||
document.head.appendChild(emojiSpriteLinkTag);
|
||||
gon.emoji_sprites_css_added = true;
|
||||
}
|
||||
// IE 11 doesn't like adding multiple at once :(
|
||||
this.classList.add('emoji-icon');
|
||||
this.classList.add(fallbackSpriteClass);
|
||||
} else if (hasImageFallback) {
|
||||
this.innerHTML = emojiImageTag(name, fallbackSrc);
|
||||
} else {
|
||||
const src = emojiFallbackImageSrc(name);
|
||||
this.innerHTML = emojiImageTag(name, src);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,13 @@ import './requires_input';
|
|||
import initPageShortcuts from './shortcuts';
|
||||
import './toggler_behavior';
|
||||
import './preview_markdown';
|
||||
import initCollapseSidebarOnWindowResize from './collapse_sidebar_on_window_resize';
|
||||
import initSelect2Dropdowns from './select2';
|
||||
|
||||
installGlEmojiElement();
|
||||
initGFMInput();
|
||||
initCopyAsGFM();
|
||||
initCopyToClipboard();
|
||||
initPageShortcuts();
|
||||
initCollapseSidebarOnWindowResize();
|
||||
initSelect2Dropdowns();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import $ from 'jquery';
|
||||
import { getSelectedFragment } from '~/lib/utils/common_utils';
|
||||
import { getSelectedFragment, insertText } from '~/lib/utils/common_utils';
|
||||
|
||||
export class CopyAsGFM {
|
||||
constructor() {
|
||||
|
@ -79,7 +79,7 @@ export class CopyAsGFM {
|
|||
}
|
||||
|
||||
static insertPastedText(target, text, gfm) {
|
||||
window.gl.utils.insertText(target, textBefore => {
|
||||
insertText(target, textBefore => {
|
||||
// If the text before the cursor contains an odd number of backticks,
|
||||
// we are either inside an inline code span that starts with 1 backtick
|
||||
// or a code block that starts with 3 backticks.
|
||||
|
|
|
@ -174,7 +174,7 @@ export default function renderMermaid($els) {
|
|||
if (!$els.length) return;
|
||||
|
||||
const visibleMermaids = $els.filter(function filter() {
|
||||
return $(this).closest('details').length === 0;
|
||||
return $(this).closest('details').length === 0 && $(this).is(':visible');
|
||||
});
|
||||
|
||||
renderMermaids(visibleMermaids);
|
||||
|
|
23
app/assets/javascripts/behaviors/select2.js
Normal file
23
app/assets/javascripts/behaviors/select2.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import $ from 'jquery';
|
||||
|
||||
export default () => {
|
||||
if ($('select.select2').length) {
|
||||
import(/* webpackChunkName: 'select2' */ 'select2/select2')
|
||||
.then(() => {
|
||||
$('select.select2').select2({
|
||||
width: 'resolve',
|
||||
minimumResultsForSearch: 10,
|
||||
dropdownAutoWidth: true,
|
||||
});
|
||||
|
||||
// Close select2 on escape
|
||||
$('.js-select2').on('select2-close', () => {
|
||||
setTimeout(() => {
|
||||
$('.select2-container-active').removeClass('select2-container-active');
|
||||
$(':focus').blur();
|
||||
}, 1);
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
};
|
|
@ -1,11 +1,10 @@
|
|||
<script>
|
||||
import { GlToggle, GlSprintf } from '@gitlab/ui';
|
||||
import { GlToggle } from '@gitlab/ui';
|
||||
import AccessorUtilities from '~/lib/utils/accessor';
|
||||
import { disableShortcuts, enableShortcuts, shouldDisableShortcuts } from './shortcuts_toggle';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlSprintf,
|
||||
GlToggle,
|
||||
},
|
||||
data() {
|
||||
|
@ -32,29 +31,10 @@ export default {
|
|||
<gl-toggle
|
||||
v-model="shortcutsEnabled"
|
||||
aria-describedby="shortcutsToggle"
|
||||
class="prepend-left-10 mb-0"
|
||||
label-position="right"
|
||||
label="Keyboard shortcuts"
|
||||
label-position="left"
|
||||
@change="onChange"
|
||||
>
|
||||
<template #labelOn>
|
||||
<gl-sprintf
|
||||
:message="__('%{screenreaderOnlyStart}Keyboard shorcuts%{screenreaderOnlyEnd} Enabled')"
|
||||
>
|
||||
<template #screenreaderOnly="{ content }">
|
||||
<span class="sr-only">{{ content }}</span>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
<template #labelOff>
|
||||
<gl-sprintf
|
||||
:message="__('%{screenreaderOnlyStart}Keyboard shorcuts%{screenreaderOnlyEnd} Disabled')"
|
||||
>
|
||||
<template #screenreaderOnly="{ content }">
|
||||
<span class="sr-only">{{ content }}</span>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
</gl-toggle>
|
||||
/>
|
||||
<div id="shortcutsToggle" class="sr-only">{{ __('Enable or disable keyboard shortcuts') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlDeprecatedButton, GlButtonGroup, GlIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { GlButton, GlButtonGroup, GlIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||
import {
|
||||
RICH_BLOB_VIEWER,
|
||||
RICH_BLOB_VIEWER_TITLE,
|
||||
|
@ -11,7 +11,7 @@ export default {
|
|||
components: {
|
||||
GlIcon,
|
||||
GlButtonGroup,
|
||||
GlDeprecatedButton,
|
||||
GlButton,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
|
@ -46,7 +46,7 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<gl-button-group class="js-blob-viewer-switcher mx-2">
|
||||
<gl-deprecated-button
|
||||
<gl-button
|
||||
v-gl-tooltip.hover
|
||||
:aria-label="$options.SIMPLE_BLOB_VIEWER_TITLE"
|
||||
:title="$options.SIMPLE_BLOB_VIEWER_TITLE"
|
||||
|
@ -55,8 +55,8 @@ export default {
|
|||
@click="switchToViewer($options.SIMPLE_BLOB_VIEWER)"
|
||||
>
|
||||
<gl-icon name="code" :size="14" />
|
||||
</gl-deprecated-button>
|
||||
<gl-deprecated-button
|
||||
</gl-button>
|
||||
<gl-button
|
||||
v-gl-tooltip.hover
|
||||
:aria-label="$options.RICH_BLOB_VIEWER_TITLE"
|
||||
:title="$options.RICH_BLOB_VIEWER_TITLE"
|
||||
|
@ -65,6 +65,6 @@ export default {
|
|||
@click="switchToViewer($options.RICH_BLOB_VIEWER)"
|
||||
>
|
||||
<gl-icon name="document" :size="14" />
|
||||
</gl-deprecated-button>
|
||||
</gl-button>
|
||||
</gl-button-group>
|
||||
</template>
|
||||
|
|
|
@ -25,7 +25,7 @@ export const BLOB_RENDER_ERRORS = {
|
|||
TOO_LARGE: {
|
||||
id: 'too_large',
|
||||
text: sprintf(__('it is larger than %{limit}'), {
|
||||
limit: numberToHumanSize(104857600), // 100MB in bytes
|
||||
limit: numberToHumanSize(10485760), // 10MB in bytes
|
||||
}),
|
||||
},
|
||||
EXTERNAL: {
|
||||
|
|
|
@ -62,9 +62,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="js-notebook-viewer-mounted container-fluid md prepend-top-default append-bottom-default"
|
||||
>
|
||||
<div class="js-notebook-viewer-mounted container-fluid md gl-mt-3 gl-mb-3">
|
||||
<div v-if="loading && !error" class="text-center loading">
|
||||
<gl-loading-icon class="mt-5" size="lg" />
|
||||
</div>
|
||||
|
|
|
@ -34,7 +34,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="js-pdf-viewer container-fluid md prepend-top-default append-bottom-default">
|
||||
<div class="js-pdf-viewer container-fluid md gl-mt-3 gl-mb-3">
|
||||
<div v-if="loading && !error" class="text-center loading">
|
||||
<gl-loading-icon class="mt-5" size="lg" />
|
||||
</div>
|
||||
|
|
|
@ -56,7 +56,7 @@ export default class SketchLoader {
|
|||
error() {
|
||||
const errorMsg = document.createElement('p');
|
||||
|
||||
errorMsg.className = 'prepend-top-default append-bottom-default text-center';
|
||||
errorMsg.className = 'gl-mt-3 gl-mb-3 text-center';
|
||||
errorMsg.textContent = __(`
|
||||
Cannot show preview. For previews on sketch files, they must have the file format
|
||||
introduced by Sketch version 43 and above.
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import { GlPopover, GlSprintf, GlDeprecatedButton, GlIcon } from '@gitlab/ui';
|
||||
import { parseBoolean, scrollToElement, setCookie, getCookie } from '~/lib/utils/common_utils';
|
||||
import { s__ } from '~/locale';
|
||||
import { glEmojiTag } from '~/emoji';
|
||||
import Tracking from '~/tracking';
|
||||
|
||||
const trackingMixin = Tracking.mixin();
|
||||
|
@ -11,14 +10,16 @@ const popoverStates = {
|
|||
suggest_gitlab_ci_yml: {
|
||||
title: s__(`suggestPipeline|1/2: Choose a template`),
|
||||
content: s__(
|
||||
`suggestPipeline|We recommend the %{boldStart}Code Quality%{boldEnd} template, which will add a report widget to your Merge Requests. This way you’ll learn about code quality degradations much sooner. %{footerStart} Goodbye technical debt! %{footerEnd}`,
|
||||
`suggestPipeline|We’re adding a GitLab CI configuration file to add a pipeline to the project. You could create it manually, but we recommend that you start with a GitLab template that works out of the box.`,
|
||||
),
|
||||
footer: s__(
|
||||
`suggestPipeline|Choose %{boldStart}Code Quality%{boldEnd} to add a pipeline that tests the quality of your code.`,
|
||||
),
|
||||
emoji: glEmojiTag('wave'),
|
||||
},
|
||||
suggest_commit_first_project_gitlab_ci_yml: {
|
||||
title: s__(`suggestPipeline|2/2: Commit your changes`),
|
||||
content: s__(
|
||||
`suggestPipeline|Commit the changes and your pipeline will automatically run for the first time.`,
|
||||
`suggestPipeline|The template is ready! You can now commit it to create your first pipeline.`,
|
||||
),
|
||||
},
|
||||
};
|
||||
|
@ -66,6 +67,9 @@ export default {
|
|||
suggestContent() {
|
||||
return popoverStates[this.trackLabel].content || '';
|
||||
},
|
||||
suggestFooter() {
|
||||
return popoverStates[this.trackLabel].footer || '';
|
||||
},
|
||||
emoji() {
|
||||
return popoverStates[this.trackLabel].emoji || '';
|
||||
},
|
||||
|
@ -123,16 +127,13 @@ export default {
|
|||
</span>
|
||||
</template>
|
||||
|
||||
<gl-sprintf :message="suggestContent">
|
||||
<template #bold="{content}">
|
||||
<strong> {{ content }} </strong>
|
||||
</template>
|
||||
<template #footer="{content}">
|
||||
<div class="mt-3">
|
||||
{{ content }}
|
||||
<span v-html="emoji"></span>
|
||||
</div>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
<gl-sprintf :message="suggestContent" />
|
||||
<div class="mt-3">
|
||||
<gl-sprintf :message="suggestFooter">
|
||||
<template #bold="{ content }">
|
||||
<strong> {{ content }} </strong>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</gl-popover>
|
||||
</template>
|
||||
|
|
|
@ -3,6 +3,7 @@ import '~/behaviors/markdown/render_gfm';
|
|||
import Flash from '../../flash';
|
||||
import { handleLocationHash } from '../../lib/utils/common_utils';
|
||||
import axios from '../../lib/utils/axios_utils';
|
||||
import eventHub from '../../notes/event_hub';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
const loadRichBlobViewer = type => {
|
||||
|
@ -178,6 +179,10 @@ export default class BlobViewer {
|
|||
viewer.innerHTML = data.html;
|
||||
viewer.setAttribute('data-loaded', 'true');
|
||||
|
||||
if (window.gon?.features?.codeNavigation) {
|
||||
eventHub.$emit('showBlobInteractionZones', viewer.dataset.path);
|
||||
}
|
||||
|
||||
return viewer;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import NewCommitForm from '../new_commit_form';
|
|||
import EditBlob from './edit_blob';
|
||||
import BlobFileDropzone from '../blob/blob_file_dropzone';
|
||||
import initPopover from '~/blob/suggest_gitlab_ci_yml';
|
||||
import { setCookie } from '~/lib/utils/common_utils';
|
||||
import { disableButtonIfEmptyField, setCookie } from '~/lib/utils/common_utils';
|
||||
import Tracking from '~/tracking';
|
||||
|
||||
export default () => {
|
||||
|
@ -51,10 +51,7 @@ export default () => {
|
|||
new BlobFileDropzone(uploadBlobForm, method);
|
||||
new NewCommitForm(uploadBlobForm);
|
||||
|
||||
window.gl.utils.disableButtonIfEmptyField(
|
||||
uploadBlobForm.find('.js-commit-message'),
|
||||
'.btn-upload-file',
|
||||
);
|
||||
disableButtonIfEmptyField(uploadBlobForm.find('.js-commit-message'), '.btn-upload-file');
|
||||
}
|
||||
|
||||
if (deleteBlobForm.length) {
|
||||
|
|
4
app/assets/javascripts/blob_edit/constants.js
Normal file
4
app/assets/javascripts/blob_edit/constants.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { __ } from '~/locale';
|
||||
|
||||
export const BLOB_EDITOR_ERROR = __('An error occurred while rendering the editor');
|
||||
export const BLOB_PREVIEW_ERROR = __('An error occurred previewing the blob');
|
|
@ -3,39 +3,87 @@
|
|||
import $ from 'jquery';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import createFlash from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import { BLOB_EDITOR_ERROR, BLOB_PREVIEW_ERROR } from './constants';
|
||||
import TemplateSelectorMediator from '../blob/file_template_mediator';
|
||||
import getModeByFileExtension from '~/lib/utils/ace_utils';
|
||||
import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
|
||||
|
||||
const monacoEnabledGlobally = window.gon.features?.monacoBlobs;
|
||||
|
||||
export default class EditBlob {
|
||||
// The options object has:
|
||||
// assetsPath, filePath, currentAction, projectId, isMarkdown
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
this.configureAceEditor();
|
||||
this.initModePanesAndLinks();
|
||||
this.initSoftWrap();
|
||||
this.initFileSelectors();
|
||||
this.options.monacoEnabled = this.options.monacoEnabled ?? monacoEnabledGlobally;
|
||||
const { isMarkdown, monacoEnabled } = this.options;
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
return monacoEnabled ? this.configureMonacoEditor() : this.configureAceEditor();
|
||||
})
|
||||
.then(() => {
|
||||
this.initModePanesAndLinks();
|
||||
this.initFileSelectors();
|
||||
this.initSoftWrap();
|
||||
if (isMarkdown) {
|
||||
addEditorMarkdownListeners(this.editor);
|
||||
}
|
||||
this.editor.focus();
|
||||
})
|
||||
.catch(() => createFlash(BLOB_EDITOR_ERROR));
|
||||
}
|
||||
|
||||
configureMonacoEditor() {
|
||||
const EditorPromise = import(
|
||||
/* webpackChunkName: 'monaco_editor_lite' */ '~/editor/editor_lite'
|
||||
);
|
||||
const MarkdownExtensionPromise = this.options.isMarkdown
|
||||
? import('~/editor/editor_markdown_ext')
|
||||
: Promise.resolve(false);
|
||||
|
||||
return Promise.all([EditorPromise, MarkdownExtensionPromise])
|
||||
.then(([EditorModule, MarkdownExtension]) => {
|
||||
const EditorLite = EditorModule.default;
|
||||
const editorEl = document.getElementById('editor');
|
||||
const fileNameEl =
|
||||
document.getElementById('file_path') || document.getElementById('file_name');
|
||||
const fileContentEl = document.getElementById('file-content');
|
||||
const form = document.querySelector('.js-edit-blob-form');
|
||||
|
||||
this.editor = new EditorLite();
|
||||
|
||||
if (MarkdownExtension) {
|
||||
this.editor.use(MarkdownExtension.default);
|
||||
}
|
||||
|
||||
this.editor.createInstance({
|
||||
el: editorEl,
|
||||
blobPath: fileNameEl.value,
|
||||
blobContent: editorEl.innerText,
|
||||
});
|
||||
|
||||
fileNameEl.addEventListener('change', () => {
|
||||
this.editor.updateModelLanguage(fileNameEl.value);
|
||||
});
|
||||
|
||||
form.addEventListener('submit', () => {
|
||||
fileContentEl.value = this.editor.getValue();
|
||||
});
|
||||
})
|
||||
.catch(() => createFlash(BLOB_EDITOR_ERROR));
|
||||
}
|
||||
|
||||
configureAceEditor() {
|
||||
const { filePath, assetsPath, isMarkdown } = this.options;
|
||||
const { filePath, assetsPath } = this.options;
|
||||
ace.config.set('modePath', `${assetsPath}/ace`);
|
||||
ace.config.loadModule('ace/ext/searchbox');
|
||||
ace.config.loadModule('ace/ext/modelist');
|
||||
|
||||
this.editor = ace.edit('editor');
|
||||
|
||||
if (isMarkdown) {
|
||||
addEditorMarkdownListeners(this.editor);
|
||||
}
|
||||
|
||||
// This prevents warnings re: automatic scrolling being logged
|
||||
this.editor.$blockScrolling = Infinity;
|
||||
|
||||
this.editor.focus();
|
||||
|
||||
if (filePath) {
|
||||
this.editor.getSession().setMode(getModeByFileExtension(filePath));
|
||||
}
|
||||
|
@ -81,7 +129,7 @@ export default class EditBlob {
|
|||
currentPane.empty().append(data);
|
||||
currentPane.renderGFM();
|
||||
})
|
||||
.catch(() => createFlash(__('An error occurred previewing the blob')));
|
||||
.catch(() => createFlash(BLOB_PREVIEW_ERROR));
|
||||
}
|
||||
|
||||
this.$toggleButton.show();
|
||||
|
@ -90,14 +138,19 @@ export default class EditBlob {
|
|||
}
|
||||
|
||||
initSoftWrap() {
|
||||
this.isSoftWrapped = false;
|
||||
this.isSoftWrapped = Boolean(this.options.monacoEnabled);
|
||||
this.$toggleButton = $('.soft-wrap-toggle');
|
||||
this.$toggleButton.toggleClass('soft-wrap-active', this.isSoftWrapped);
|
||||
this.$toggleButton.on('click', () => this.toggleSoftWrap());
|
||||
}
|
||||
|
||||
toggleSoftWrap() {
|
||||
this.isSoftWrapped = !this.isSoftWrapped;
|
||||
this.$toggleButton.toggleClass('soft-wrap-active', this.isSoftWrapped);
|
||||
this.editor.getSession().setUseWrapMode(this.isSoftWrapped);
|
||||
if (this.options.monacoEnabled) {
|
||||
this.editor.updateOptions({ wordWrap: this.isSoftWrapped ? 'on' : 'off' });
|
||||
} else {
|
||||
this.editor.getSession().setUseWrapMode(this.isSoftWrapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,192 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import Sortable from 'sortablejs';
|
||||
import Vue from 'vue';
|
||||
import { GlButtonGroup, GlDeprecatedButton, GlLabel, GlTooltip } from '@gitlab/ui';
|
||||
import isWipLimitsOn from 'ee_else_ce/boards/mixins/is_wip_limits';
|
||||
import { s__, __, sprintf } from '~/locale';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
import Tooltip from '~/vue_shared/directives/tooltip';
|
||||
import AccessorUtilities from '../../lib/utils/accessor';
|
||||
import BoardBlankState from './board_blank_state.vue';
|
||||
import BoardDelete from './board_delete';
|
||||
import BoardList from './board_list.vue';
|
||||
import IssueCount from './issue_count.vue';
|
||||
import boardsStore from '../stores/boards_store';
|
||||
import { getBoardSortableDefaultOptions, sortableEnd } from '../mixins/sortable_default_options';
|
||||
import { ListType } from '../constants';
|
||||
import { isScopedLabel } from '~/lib/utils/common_utils';
|
||||
|
||||
/**
|
||||
* Please don't edit this file, have a look at:
|
||||
* ./board_column.vue
|
||||
* https://gitlab.com/gitlab-org/gitlab/-/issues/212300
|
||||
*
|
||||
* This file here will be deleted soon
|
||||
* @deprecated
|
||||
*/
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
BoardBlankState,
|
||||
BoardDelete,
|
||||
BoardList,
|
||||
Icon,
|
||||
GlButtonGroup,
|
||||
IssueCount,
|
||||
GlDeprecatedButton,
|
||||
GlLabel,
|
||||
GlTooltip,
|
||||
},
|
||||
directives: {
|
||||
Tooltip,
|
||||
},
|
||||
mixins: [isWipLimitsOn],
|
||||
props: {
|
||||
list: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
required: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
boardId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
// Does not do anything but is used
|
||||
// to support the API of the new board_column.vue
|
||||
canAdminList: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
detailIssue: boardsStore.detail,
|
||||
filter: boardsStore.filter,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isLoggedIn() {
|
||||
return Boolean(gon.current_user_id);
|
||||
},
|
||||
showListHeaderButton() {
|
||||
return (
|
||||
!this.disabled && this.list.type !== ListType.closed && this.list.type !== ListType.blank
|
||||
);
|
||||
},
|
||||
issuesTooltip() {
|
||||
const { issuesSize } = this.list;
|
||||
|
||||
return sprintf(__('%{issuesSize} issues'), { issuesSize });
|
||||
},
|
||||
// Only needed to make karma pass.
|
||||
weightCountToolTip() {}, // eslint-disable-line vue/return-in-computed-property
|
||||
caretTooltip() {
|
||||
return this.list.isExpanded ? s__('Boards|Collapse') : s__('Boards|Expand');
|
||||
},
|
||||
isNewIssueShown() {
|
||||
return this.list.type === ListType.backlog || this.showListHeaderButton;
|
||||
},
|
||||
isSettingsShown() {
|
||||
return (
|
||||
this.list.type !== ListType.backlog &&
|
||||
this.showListHeaderButton &&
|
||||
this.list.isExpanded &&
|
||||
this.isWipLimitsOn
|
||||
);
|
||||
},
|
||||
showBoardListAndBoardInfo() {
|
||||
return this.list.type !== ListType.blank && this.list.type !== ListType.promotion;
|
||||
},
|
||||
uniqueKey() {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `boards.${this.boardId}.${this.list.type}.${this.list.id}`;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
filter: {
|
||||
handler() {
|
||||
this.list.page = 1;
|
||||
this.list.getIssues(true).catch(() => {
|
||||
// TODO: handle request error
|
||||
});
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const instance = this;
|
||||
|
||||
const sortableOptions = getBoardSortableDefaultOptions({
|
||||
disabled: this.disabled,
|
||||
group: 'boards',
|
||||
draggable: '.is-draggable',
|
||||
handle: '.js-board-handle',
|
||||
onEnd(e) {
|
||||
sortableEnd();
|
||||
|
||||
const sortable = this;
|
||||
|
||||
if (e.newIndex !== undefined && e.oldIndex !== e.newIndex) {
|
||||
const order = sortable.toArray();
|
||||
const list = boardsStore.findList('id', parseInt(e.item.dataset.id, 10));
|
||||
|
||||
instance.$nextTick(() => {
|
||||
boardsStore.moveList(list, order);
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Sortable.create(this.$el.parentNode, sortableOptions);
|
||||
},
|
||||
created() {
|
||||
if (
|
||||
this.list.isExpandable &&
|
||||
AccessorUtilities.isLocalStorageAccessSafe() &&
|
||||
!this.isLoggedIn
|
||||
) {
|
||||
const isCollapsed = localStorage.getItem(`${this.uniqueKey}.expanded`) === 'false';
|
||||
|
||||
this.list.isExpanded = !isCollapsed;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showScopedLabels(label) {
|
||||
return boardsStore.scopedLabels.enabled && isScopedLabel(label);
|
||||
},
|
||||
|
||||
showNewIssueForm() {
|
||||
this.$refs['board-list'].showIssueForm = !this.$refs['board-list'].showIssueForm;
|
||||
},
|
||||
toggleExpanded() {
|
||||
if (this.list.isExpandable) {
|
||||
this.list.isExpanded = !this.list.isExpanded;
|
||||
|
||||
if (AccessorUtilities.isLocalStorageAccessSafe() && !this.isLoggedIn) {
|
||||
localStorage.setItem(`${this.uniqueKey}.expanded`, this.list.isExpanded);
|
||||
}
|
||||
|
||||
if (this.isLoggedIn) {
|
||||
this.list.update();
|
||||
}
|
||||
|
||||
// When expanding/collapsing, the tooltip on the caret button sometimes stays open.
|
||||
// Close all tooltips manually to prevent dangling tooltips.
|
||||
$('.tooltip').tooltip('hide');
|
||||
}
|
||||
},
|
||||
},
|
||||
template: '#js-board-template',
|
||||
});
|
|
@ -54,7 +54,7 @@ export default {
|
|||
<div>
|
||||
<div
|
||||
v-if="!isSwimlanesOn"
|
||||
class="boards-list w-100 py-3 px-2 text-nowrap"
|
||||
class="boards-list gl-w-full gl-py-5 gl-px-3 gl-white-space-nowrap"
|
||||
data-qa-selector="boards_list"
|
||||
>
|
||||
<board-column
|
||||
|
@ -77,6 +77,7 @@ export default {
|
|||
:can-admin-list="canAdminList"
|
||||
:disabled="disabled"
|
||||
:board-id="boardId"
|
||||
:group-id="groupId"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -5,10 +5,11 @@ import {
|
|||
GlLabel,
|
||||
GlTooltip,
|
||||
GlIcon,
|
||||
GlSprintf,
|
||||
GlTooltipDirective,
|
||||
} from '@gitlab/ui';
|
||||
import isWipLimitsOn from 'ee_else_ce/boards/mixins/is_wip_limits';
|
||||
import { s__, __, sprintf } from '~/locale';
|
||||
import { n__, s__ } from '~/locale';
|
||||
import AccessorUtilities from '../../lib/utils/accessor';
|
||||
import BoardDelete from './board_delete';
|
||||
import IssueCount from './issue_count.vue';
|
||||
|
@ -25,6 +26,7 @@ export default {
|
|||
GlLabel,
|
||||
GlTooltip,
|
||||
GlIcon,
|
||||
GlSprintf,
|
||||
IssueCount,
|
||||
},
|
||||
directives: {
|
||||
|
@ -82,10 +84,20 @@ export default {
|
|||
this.listType !== ListType.promotion
|
||||
);
|
||||
},
|
||||
issuesTooltip() {
|
||||
showMilestoneListDetails() {
|
||||
return (
|
||||
this.list.type === 'milestone' &&
|
||||
this.list.milestone &&
|
||||
(this.list.isExpanded || !this.isSwimlanesHeader)
|
||||
);
|
||||
},
|
||||
showAssigneeListDetails() {
|
||||
return this.list.type === 'assignee' && (this.list.isExpanded || !this.isSwimlanesHeader);
|
||||
},
|
||||
issuesTooltipLabel() {
|
||||
const { issuesSize } = this.list;
|
||||
|
||||
return sprintf(__('%{issuesSize} issues'), { issuesSize });
|
||||
return n__(`%d issue`, `%d issues`, issuesSize);
|
||||
},
|
||||
chevronTooltip() {
|
||||
return this.list.isExpanded ? s__('Boards|Collapse') : s__('Boards|Expand');
|
||||
|
@ -111,6 +123,9 @@ export default {
|
|||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `boards.${this.boardId}.${this.listType}.${this.list.id}`;
|
||||
},
|
||||
collapsedTooltipTitle() {
|
||||
return this.listTitle || this.listAssignee;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
showScopedLabels(label) {
|
||||
|
@ -147,7 +162,7 @@ export default {
|
|||
'has-border': list.label && list.label.color,
|
||||
'gl-relative': list.isExpanded,
|
||||
'gl-h-full': !list.isExpanded,
|
||||
'board-inner gl-rounded-base gl-border-b-0': isSwimlanesHeader,
|
||||
'board-inner gl-rounded-top-left-base gl-rounded-top-right-base': isSwimlanesHeader,
|
||||
}"
|
||||
:style="{ borderTopColor: list.label && list.label.color ? list.label.color : null }"
|
||||
class="board-header gl-relative"
|
||||
|
@ -157,7 +172,9 @@ export default {
|
|||
<h3
|
||||
:class="{
|
||||
'user-can-drag': !disabled && !list.preset,
|
||||
'gl-border-b-0': !list.isExpanded,
|
||||
'gl-py-3': !list.isExpanded && !isSwimlanesHeader,
|
||||
'gl-border-b-0': !list.isExpanded || isSwimlanesHeader,
|
||||
'gl-py-2': !list.isExpanded && isSwimlanesHeader,
|
||||
}"
|
||||
class="board-title gl-m-0 gl-display-flex js-board-handle"
|
||||
>
|
||||
|
@ -167,21 +184,17 @@ export default {
|
|||
:aria-label="chevronTooltip"
|
||||
:title="chevronTooltip"
|
||||
:icon="chevronIcon"
|
||||
class="board-title-caret no-drag"
|
||||
class="board-title-caret no-drag gl-cursor-pointer"
|
||||
variant="link"
|
||||
@click="toggleExpanded"
|
||||
/>
|
||||
<!-- The following is only true in EE and if it is a milestone -->
|
||||
<span
|
||||
v-if="list.type === 'milestone' && list.milestone"
|
||||
aria-hidden="true"
|
||||
class="gl-mr-2 milestone-icon"
|
||||
>
|
||||
<span v-if="showMilestoneListDetails" aria-hidden="true" class="gl-mr-2 milestone-icon">
|
||||
<gl-icon name="timer" />
|
||||
</span>
|
||||
|
||||
<a
|
||||
v-if="list.type === 'assignee'"
|
||||
v-if="showAssigneeListDetails"
|
||||
:href="list.assignee.path"
|
||||
class="user-avatar-link js-no-trigger"
|
||||
>
|
||||
|
@ -195,7 +208,10 @@ export default {
|
|||
width="20"
|
||||
/>
|
||||
</a>
|
||||
<div class="board-title-text">
|
||||
<div
|
||||
class="board-title-text"
|
||||
:class="{ 'gl-display-none': !list.isExpanded && isSwimlanesHeader }"
|
||||
>
|
||||
<span
|
||||
v-if="list.type !== 'label'"
|
||||
v-gl-tooltip.hover
|
||||
|
@ -208,7 +224,7 @@ export default {
|
|||
{{ list.title }}
|
||||
</span>
|
||||
<span v-if="list.type === 'assignee'" class="board-title-sub-text gl-ml-2">
|
||||
@{{ list.assignee.username }}
|
||||
@{{ listAssignee }}
|
||||
</span>
|
||||
<gl-label
|
||||
v-if="list.type === 'label'"
|
||||
|
@ -220,6 +236,33 @@ export default {
|
|||
:title="list.label.title"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<span
|
||||
v-if="isSwimlanesHeader && !list.isExpanded"
|
||||
ref="collapsedInfo"
|
||||
aria-hidden="true"
|
||||
class="board-header-collapsed-info-icon gl-mt-2 gl-cursor-pointer gl-text-gray-700"
|
||||
>
|
||||
<gl-icon name="information" />
|
||||
</span>
|
||||
<gl-tooltip v-if="isSwimlanesHeader && !list.isExpanded" :target="() => $refs.collapsedInfo">
|
||||
<div class="gl-font-weight-bold gl-pb-2">{{ collapsedTooltipTitle }}</div>
|
||||
<div v-if="list.maxIssueCount !== 0">
|
||||
•
|
||||
<gl-sprintf :message="__('%{issuesSize} with a limit of %{maxIssueCount}')">
|
||||
<template #issuesSize>{{ issuesTooltipLabel }}</template>
|
||||
<template #maxIssueCount>{{ list.maxIssueCount }}</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
<div v-else>• {{ issuesTooltipLabel }}</div>
|
||||
<div v-if="weightFeatureAvailable">
|
||||
•
|
||||
<gl-sprintf :message="__('%{totalWeight} total weight')">
|
||||
<template #totalWeight>{{ list.totalWeight }}</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</gl-tooltip>
|
||||
|
||||
<board-delete
|
||||
v-if="canAdminList && !list.preset && list.id"
|
||||
:list="list"
|
||||
|
@ -229,7 +272,7 @@ export default {
|
|||
v-gl-tooltip.hover.bottom
|
||||
:class="{ 'gl-display-none': !list.isExpanded }"
|
||||
:aria-label="__('Delete list')"
|
||||
class="board-delete no-drag gl-pr-0 gl-shadow-none gl-mr-3"
|
||||
class="board-delete no-drag gl-pr-0 gl-shadow-none! gl-mr-3"
|
||||
:title="__('Delete list')"
|
||||
icon="remove"
|
||||
size="small"
|
||||
|
@ -238,10 +281,11 @@ export default {
|
|||
</board-delete>
|
||||
<div
|
||||
v-if="showBoardListAndBoardInfo"
|
||||
class="issue-count-badge gl-pr-0 no-drag text-secondary"
|
||||
class="issue-count-badge gl-display-inline-flex gl-pr-0 no-drag text-secondary"
|
||||
:class="{ 'gl-display-none': !list.isExpanded && isSwimlanesHeader }"
|
||||
>
|
||||
<span class="gl-display-inline-flex">
|
||||
<gl-tooltip :target="() => $refs.issueCount" :title="issuesTooltip" />
|
||||
<gl-tooltip :target="() => $refs.issueCount" :title="issuesTooltipLabel" />
|
||||
<span ref="issueCount" class="issue-count-badge-count">
|
||||
<gl-icon class="gl-mr-2" name="issues" />
|
||||
<issue-count :issues-size="list.issuesSize" :max-issue-count="list.maxIssueCount" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import { GlDeprecatedButton } from '@gitlab/ui';
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import { getMilestone } from 'ee_else_ce/boards/boards_util';
|
||||
import ListIssue from 'ee_else_ce/boards/models/issue';
|
||||
import eventHub from '../eventhub';
|
||||
|
@ -11,7 +11,7 @@ export default {
|
|||
name: 'BoardNewIssue',
|
||||
components: {
|
||||
ProjectSelect,
|
||||
GlDeprecatedButton,
|
||||
GlButton,
|
||||
},
|
||||
props: {
|
||||
groupId: {
|
||||
|
@ -120,21 +120,18 @@ export default {
|
|||
/>
|
||||
<project-select v-if="groupId" :group-id="groupId" :list="list" />
|
||||
<div class="clearfix prepend-top-10">
|
||||
<gl-deprecated-button
|
||||
<gl-button
|
||||
ref="submit-button"
|
||||
:disabled="disabled"
|
||||
class="float-left"
|
||||
variant="success"
|
||||
category="primary"
|
||||
type="submit"
|
||||
>{{ __('Submit issue') }}</gl-deprecated-button
|
||||
>
|
||||
<gl-deprecated-button
|
||||
class="float-right"
|
||||
type="button"
|
||||
variant="default"
|
||||
@click="cancel"
|
||||
>{{ __('Cancel') }}</gl-deprecated-button
|
||||
>{{ __('Submit issue') }}</gl-button
|
||||
>
|
||||
<gl-button class="float-right" type="button" variant="default" @click="cancel">{{
|
||||
__('Cancel')
|
||||
}}</gl-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -233,7 +233,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="boards-switcher js-boards-selector append-right-10">
|
||||
<div class="boards-switcher js-boards-selector gl-mr-3">
|
||||
<span class="boards-selector-wrapper js-boards-selector-wrapper">
|
||||
<gl-dropdown
|
||||
data-qa-selector="boards_dropdown"
|
||||
|
|
|
@ -153,7 +153,7 @@ export default {
|
|||
v-gl-tooltip
|
||||
name="issue-block"
|
||||
:title="__('Blocked issue')"
|
||||
class="issue-blocked-icon append-right-4"
|
||||
class="issue-blocked-icon gl-mr-2"
|
||||
:aria-label="__('Blocked issue')"
|
||||
/>
|
||||
<icon
|
||||
|
@ -161,7 +161,7 @@ export default {
|
|||
v-gl-tooltip
|
||||
name="eye-slash"
|
||||
:title="__('Confidential')"
|
||||
class="confidential-icon append-right-4"
|
||||
class="confidential-icon gl-mr-2"
|
||||
:aria-label="__('Confidential')"
|
||||
/>
|
||||
<a :href="issue.path" :title="issue.title" class="js-no-trigger" @mousemove.stop>{{
|
||||
|
|
|
@ -72,7 +72,7 @@ export default {
|
|||
<button
|
||||
ref="selectAllBtn"
|
||||
type="button"
|
||||
class="btn btn-success btn-inverted prepend-left-10"
|
||||
class="btn btn-success btn-inverted gl-ml-3"
|
||||
@click="toggleAll"
|
||||
>
|
||||
{{ selectAllText }}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue