New upstream version 11.11.7+dfsg

This commit is contained in:
Pirate Praveen 2019-07-31 17:26:46 +00:00
parent 45981217aa
commit 0ed0e4d656
2803 changed files with 53501 additions and 15217 deletions

2
.gitignore vendored
View file

@ -59,8 +59,6 @@ eslint-report.html
/public/uploads.* /public/uploads.*
/public/uploads/ /public/uploads/
/shared/artifacts/ /shared/artifacts/
/spec/javascripts/fixtures/blob/pdf/
/spec/javascripts/fixtures/blob/balsamiq/
/rails_best_practices_output.html /rails_best_practices_output.html
/tags /tags
/tmp/* /tmp/*

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
# Backend Maintainers are the default for all ruby files # Backend Maintainers are the default for all ruby files
*.rb @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern *.rb @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera
*.rake @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern *.rake @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera
# Technical writing team are the default reviewers for everything in `doc/` # Technical writing team are the default reviewers for everything in `doc/`
/doc/ @axil @marcia /doc/ @axil @marcia

View file

@ -0,0 +1,16 @@
cloud-native-image:
image: ruby:2.5-alpine
before_script: []
dependencies: []
stage: post-test
allow_failure: true
variables:
GIT_DEPTH: "1"
cache: {}
when: manual
script:
- install_gitlab_gem
- CNG_PROJECT_PATH="gitlab-org/build/CNG" BUILD_TRIGGER_TOKEN=$CI_JOB_TOKEN ./scripts/trigger-build cng
only:
- tags@gitlab-org/gitlab-ce
- tags@gitlab-org/gitlab-ee

View file

@ -0,0 +1,76 @@
.review-docs: &review-docs
extends: .single-script-job-dedicated-runner
variables:
SCRIPT_NAME: trigger-build-docs
environment:
name: review-docs/$CI_COMMIT_REF_SLUG
# DOCS_REVIEW_APPS_DOMAIN and DOCS_GITLAB_REPO_SUFFIX are CI variables
# Discussion: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14236/diffs#note_40140693
url: http://$CI_ENVIRONMENT_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
on_stop: review-docs-cleanup
# Trigger a manual docs build in gitlab-docs only on non docs-only branches.
# Useful to preview the docs changes live.
review-docs-deploy-manual:
<<: *review-docs
stage: build
script:
- gem install gitlab --no-document
- ./$SCRIPT_NAME deploy
when: manual
only:
- branches@gitlab-org/gitlab-ce
- branches@gitlab-org/gitlab-ee
except:
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/
# Always trigger a docs build in gitlab-docs only on docs-only branches.
# Useful to preview the docs changes live.
review-docs-deploy:
<<: *review-docs
stage: post-test
script:
- gem install gitlab --no-document
- ./$SCRIPT_NAME deploy
only:
- /(^docs[\/-].*|.*-docs$)/@gitlab-org/gitlab-ce
- /(^docs[\/-].*|.*-docs$)/@gitlab-org/gitlab-ee
except:
- /(^qa[\/-].*|.*-qa$)/
# Cleanup remote environment of gitlab-docs
review-docs-cleanup:
<<: *review-docs
stage: post-cleanup
environment:
name: review-docs/$CI_COMMIT_REF_SLUG
action: stop
script:
- gem install gitlab --no-document
- ./$SCRIPT_NAME cleanup
when: manual
only:
- branches@gitlab-org/gitlab-ce
- branches@gitlab-org/gitlab-ee
docs lint:
extends: .dedicated-runner
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-docs-lint"
stage: test
cache: {}
dependencies: []
before_script: []
script:
- scripts/lint-doc.sh
- scripts/lint-changelog-yaml
- mv doc/ /tmp/gitlab-docs/content/$DOCS_GITLAB_REPO_SUFFIX
- cd /tmp/gitlab-docs
# Build HTML from Markdown
- bundle exec nanoc
# Check the internal links
- bundle exec nanoc check internal_links
# Check the internal anchor links
- bundle exec nanoc check internal_anchors
except:
- /(^qa[\/-].*|.*-qa$)/

View file

@ -0,0 +1,242 @@
.assets-compile-cache: &assets-compile-cache
cache:
key: "assets-compile:vendor_ruby:.yarn-cache:tmp_cache_assets_sprockets:v5"
paths:
- vendor/ruby/
- .yarn-cache/
- tmp/cache/assets/sprockets
policy: pull-push
.use-pg: &use-pg
services:
- name: postgres:9.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine
gitlab:assets:compile:
<<: *assets-compile-cache
extends: .dedicated-no-docs-pull-cache-job
image: dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.5.3-git-2.21-chrome-73.0-node-8.x-yarn-1.12-graphicsmagick-1.3.29-docker-18.06.1
dependencies:
- setup-test-env
services:
- docker:stable-dind
variables:
NODE_ENV: "production"
RAILS_ENV: "production"
SETUP_DB: "false"
SKIP_STORAGE_VALIDATION: "true"
WEBPACK_REPORT: "true"
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375
script:
- node --version
- yarn install --frozen-lockfile --production --cache-folder .yarn-cache
- free -m
- bundle exec rake gitlab:assets:compile
- time scripts/build_assets_image
- scripts/clean-old-cached-assets
# Play dependent manual jobs
- install_api_client_dependencies_with_apt
- play_job "review-build-cng" || true # this job might not exist so ignore the failure if it cannot be played
- play_job "schedule:review-build-cng" || true # this job might not exist so ignore the failure if it cannot be played
artifacts:
name: webpack-report
expire_in: 31d
paths:
- webpack-report/
- public/assets/
only:
- /.+/@gitlab-org/gitlab-ce
- /.+/@gitlab-org/gitlab-ee
- /.+/@gitlab/gitlabhq
- /.+/@gitlab/gitlab-ee
tags:
- docker
- gitlab-org
compile-assets:
extends: .dedicated-runner
<<: *use-pg
<<: *assets-compile-cache
stage: prepare
script:
- node --version
- yarn install --frozen-lockfile --cache-folder .yarn-cache
- free -m
- bundle exec rake gitlab:assets:compile
- scripts/clean-old-cached-assets
variables:
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
artifacts:
expire_in: 7d
paths:
- node_modules
- public/assets
except:
refs:
- /(^docs[\/-].*|.*-docs$)/
gitlab:ui:visual:
extends: .dedicated-runner
before_script: []
allow_failure: true
dependencies:
- compile-assets
script:
# Remove node modules from GitLab that may conflict with gitlab-ui
- rm -r node_modules
- git clone https://gitlab.com/gitlab-org/gitlab-ui.git
- cp public/assets/application-*.css gitlab-ui/styles/application.css
- cd gitlab-ui
- yarn install
- CSS_URL=./application.css yarn test
only:
changes:
- app/assets/stylesheets/*.scss
- app/assets/stylesheets/**/*.scss
- app/assets/stylesheets/**/**/*.scss
except:
refs:
- /(^docs[\/-].*|.*-docs$)/
- master
variables:
- $CI_COMMIT_MESSAGE =~ /\[skip visual\]/i
artifacts:
paths:
- gitlab-ui/tests/__image_snapshots__/
when: always
karma:
extends: .dedicated-no-docs-pull-cache-job
<<: *use-pg
dependencies:
- compile-assets
- setup-test-env
variables:
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
script:
- export BABEL_ENV=coverage CHROME_LOG_FILE=chrome_debug.log
- date
- scripts/gitaly-test-spawn
- date
- bundle exec rake karma
coverage: '/^Statements *: (\d+\.\d+%)/'
artifacts:
name: coverage-javascript
expire_in: 31d
when: always
paths:
- chrome_debug.log
- coverage-javascript/
reports:
junit: junit_karma.xml
jest:
extends: .dedicated-no-docs-and-no-qa-pull-cache-job
<<: *use-pg
dependencies:
- compile-assets
- setup-test-env
script:
- scripts/gitaly-test-spawn
- date
- bundle exec rake karma:fixtures
- date
- yarn jest --ci --coverage
artifacts:
name: coverage-frontend
expire_in: 31d
when: always
paths:
- coverage-frontend/
- junit_jest.xml
reports:
junit: junit_jest.xml
cache:
key: jest
paths:
- tmp/jest/jest/
policy: pull-push
qa:internal:
extends: .dedicated-no-docs-no-db-pull-cache-job
services: []
script:
- cd qa/
- bundle install
- bundle exec rspec
dependencies:
- setup-test-env
qa:selectors:
extends: .dedicated-no-docs-no-db-pull-cache-job
services: []
script:
- cd qa/
- bundle install
- bundle exec bin/qa Test::Sanity::Selectors
dependencies:
- setup-test-env
.qa-frontend-node: &qa-frontend-node
extends: .dedicated-no-docs-no-db-pull-cache-job
stage: test
cache:
key: "$CI_JOB_NAME"
paths:
- .yarn-cache/
policy: pull-push
dependencies: []
before_script: []
script:
- date
- yarn install --frozen-lockfile --cache-folder .yarn-cache
- date
- yarn run webpack-prod
qa-frontend-node:8:
<<: *qa-frontend-node
image: node:8-alpine
qa-frontend-node:10:
<<: *qa-frontend-node
image: node:10-alpine
qa-frontend-node:latest:
<<: *qa-frontend-node
image: node:alpine
allow_failure: true
lint:javascript:report:
extends: .dedicated-no-docs-no-db-pull-cache-job
stage: post-test
dependencies: []
before_script: []
script:
- date
- yarn run eslint-report || true # ignore exit code
artifacts:
name: eslint-report
expire_in: 31d
paths:
- eslint-report.html
jsdoc:
extends: .dedicated-no-docs-no-db-pull-cache-job
stage: post-test
dependencies:
- compile-assets
before_script: []
script:
- date
- yarn run jsdoc || true # ignore exit code
artifacts:
name: jsdoc
expire_in: 31d
paths:
- jsdoc/

View file

@ -0,0 +1,62 @@
.dedicated-runner:
retry:
max: 2 # This is confusing but this means "3 runs at max".
when:
- unknown_failure
- api_failure
- runner_system_failure
tags:
- gitlab-org
.default-cache: &default-cache
key: "debian-stretch-ruby-2.5.3-node-10.x"
paths:
- vendor/ruby
- .yarn-cache/
- vendor/gitaly-ruby
.dedicated-runner-default-cache:
extends: .dedicated-runner
cache:
<<: *default-cache
# Jobs that only need to pull cache
.dedicated-pull-cache-job:
extends: .dedicated-runner
cache:
<<: *default-cache
policy: pull
stage: test
.dedicated-no-docs-pull-cache-job:
extends: .dedicated-pull-cache-job
except:
- /(^docs[\/-].*|.*-docs$)/
.dedicated-no-docs-and-no-qa-pull-cache-job:
extends: .dedicated-pull-cache-job
except:
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/
# Jobs that do not need a DB
.dedicated-no-docs-no-db-pull-cache-job:
extends: .dedicated-no-docs-pull-cache-job
variables:
SETUP_DB: "false"
.single-script-job-dedicated-runner:
extends: .dedicated-runner
image: ruby:2.5-alpine
stage: test
cache: {}
dependencies: []
variables:
GIT_STRATEGY: none
before_script:
# We don't clone the repo by using GIT_STRATEGY: none and only download the
# single script we need here so it's much faster than cloning.
- export SCRIPT_NAME="${SCRIPT_NAME:-$CI_JOB_NAME}"
- apk add --update openssl
- wget $CI_PROJECT_URL/raw/$CI_COMMIT_SHA/scripts/$SCRIPT_NAME
- chmod 755 $(basename $SCRIPT_NAME)

View file

@ -0,0 +1,27 @@
pages:
extends: .dedicated-no-docs-no-db-pull-cache-job
before_script: []
stage: pages
dependencies:
- coverage
- karma
- gitlab:assets:compile
- lint:javascript:report
- jsdoc
script:
- mv public/ .public/
- mkdir public/
- mv coverage/ public/coverage-ruby/ || true
- mv coverage-javascript/ public/coverage-javascript/ || true
- mv eslint-report.html public/ || true
- mv webpack-report/ public/webpack-report/ || true
- cp .public/assets/application-*.css public/application.css || true
- cp .public/assets/application-*.css.gz public/application.css.gz || true
- mv jsdoc/ public/jsdoc/ || true
artifacts:
paths:
- public
only:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee

View file

@ -0,0 +1,17 @@
package-and-qa:
image: ruby:2.5-alpine
stage: qa
when: manual
before_script: []
dependencies: []
cache: {}
variables:
GIT_DEPTH: "1"
retry: 0
script:
- source scripts/utils.sh
- install_gitlab_gem
- ./scripts/trigger-build omnibus
only:
- /.+/@gitlab-org/gitlab-ce
- /.+/@gitlab-org/gitlab-ee

View file

@ -0,0 +1,292 @@
.use-pg: &use-pg
services:
- name: postgres:9.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine
.use-pg-10: &use-pg-10
services:
- postgres:10.7
- redis:alpine
.use-mysql: &use-mysql
services:
- mysql:5.7
- redis:alpine
.only-schedules-master: &only-schedules-master
only:
- schedules@gitlab-org/gitlab-ce
- schedules@gitlab-org/gitlab-ee
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
.gitlab-setup: &gitlab-setup
extends: .dedicated-no-docs-and-no-qa-pull-cache-job
<<: *use-pg
variables:
SETUP_DB: "false"
script:
# Manually clone gitlab-test and only seed this project in
# db/fixtures/development/04_project.rb thanks to SIZE=1 below
- git clone https://gitlab.com/gitlab-org/gitlab-test.git
/home/git/repositories/gitlab-org/gitlab-test.git
- scripts/gitaly-test-spawn
- force=yes SIZE=1 FIXTURE_PATH="db/fixtures/development" bundle exec rake gitlab:setup
artifacts:
when: on_failure
expire_in: 1d
paths:
- log/development.log
.rake-exec: &rake-exec
extends: .dedicated-no-docs-no-db-pull-cache-job
script:
- bundle exec rake $CI_JOB_NAME
.rspec-metadata: &rspec-metadata
extends: .dedicated-pull-cache-job
stage: test
script:
- JOB_NAME=( $CI_JOB_NAME )
- TEST_TOOL=${JOB_NAME[0]}
- export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${TEST_TOOL}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export KNAPSACK_GENERATE_REPORT=true
- export SUITE_FLAKY_RSPEC_REPORT_PATH=${FLAKY_RSPEC_SUITE_REPORT_PATH}
- export FLAKY_RSPEC_REPORT_PATH=rspec_flaky/all_${TEST_TOOL}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export NEW_FLAKY_RSPEC_REPORT_PATH=rspec_flaky/new_${TEST_TOOL}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export FLAKY_RSPEC_GENERATE_REPORT=true
- export CACHE_CLASSES=true
- cp ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
- '[[ -f $FLAKY_RSPEC_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_REPORT_PATH}'
- '[[ -f $NEW_FLAKY_RSPEC_REPORT_PATH ]] || echo "{}" > ${NEW_FLAKY_RSPEC_REPORT_PATH}'
- scripts/gitaly-test-spawn
- knapsack rspec "--color --format documentation --format RspecJunitFormatter --out junit_rspec.xml"
artifacts:
expire_in: 31d
when: always
paths:
- coverage/
- knapsack/
- rspec_flaky/
- rspec_profiling/
- tmp/capybara/
reports:
junit: junit_rspec.xml
except:
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/
.rspec-metadata-pg: &rspec-metadata-pg
<<: *rspec-metadata
<<: *use-pg
.rspec-metadata-pg-10: &rspec-metadata-pg-10
<<: *rspec-metadata
<<: *use-pg-10
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.5.3-golang-1.11-git-2.21-chrome-73.0-node-10.x-yarn-1.12-postgresql-10-graphicsmagick-1.3.29"
.rspec-metadata-mysql: &rspec-metadata-mysql
<<: *rspec-metadata
<<: *use-mysql
# DB migration, rollback, and seed jobs
.db-migrate-reset: &db-migrate-reset
extends: .dedicated-no-docs-and-no-qa-pull-cache-job
script:
- bundle exec rake db:migrate:reset
dependencies:
- setup-test-env
.migration-paths: &migration-paths
extends: .dedicated-no-docs-and-no-qa-pull-cache-job
variables:
SETUP_DB: "false"
script:
- git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v9.3.0
- git checkout -f FETCH_HEAD
- sed -i "s/gem 'oj', '~> 2.17.4'//" Gemfile
- bundle update google-protobuf grpc
- bundle install $BUNDLE_INSTALL_FLAGS
- date
- cp config/gitlab.yml.example config/gitlab.yml
- bundle exec rake db:drop db:create db:schema:load db:seed_fu
- date
- git checkout -f $CI_COMMIT_SHA
- bundle install $BUNDLE_INSTALL_FLAGS
- date
- . scripts/prepare_build.sh
- date
- bundle exec rake db:migrate
dependencies:
- setup-test-env
setup-test-env:
extends: .dedicated-runner-default-cache
<<: *use-pg
stage: prepare
script:
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
- scripts/gitaly-test-build # Do not use 'bundle exec' here
artifacts:
expire_in: 7d
paths:
- tmp/tests
- config/secrets.yml
- vendor/gitaly-ruby
except:
- /(^docs[\/-].*|.*-docs$)/
rspec-pg:
<<: *rspec-metadata-pg
parallel: 50
rspec-pg-10:
<<: *rspec-metadata-pg-10
<<: *only-schedules-master
parallel: 50
rspec-mysql:
<<: *rspec-metadata-mysql
<<: *only-schedules-master
parallel: 50
rspec-fast-spec-helper:
<<: *rspec-metadata-pg
script:
- bundle exec rspec spec/fast_spec_helper.rb
.rspec-quarantine: &rspec-quarantine
<<: *only-schedules-master
script:
- export CACHE_CLASSES=true
- scripts/gitaly-test-spawn
- bin/rspec --color --format documentation --tag quarantine spec/
rspec-pg-quarantine:
<<: *rspec-metadata-pg
<<: *rspec-quarantine
allow_failure: true
rspec-mysql-quarantine:
<<: *rspec-metadata-mysql
<<: *rspec-quarantine
allow_failure: true
static-analysis:
extends: .dedicated-no-docs-no-db-pull-cache-job
dependencies:
- compile-assets
- setup-test-env
script:
- scripts/static-analysis
cache:
key: "debian-stretch-ruby-2.5.3-node-10.x-and-rubocop"
paths:
- vendor/ruby
- .yarn-cache/
- tmp/rubocop_cache
policy: pull-push
downtime_check:
<<: *rake-exec
except:
- master
- tags
- /^[\d-]+-stable(-ee)?$/
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/
dependencies:
- setup-test-env
ee_compat_check:
<<: *rake-exec
dependencies: []
except:
- master
- tags
- /[\d-]+-stable(-ee)?/
- /^security-/
- branches@gitlab-org/gitlab-ee
- branches@gitlab/gitlab-ee
retry: 0
artifacts:
name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}"
when: always
expire_in: 10d
paths:
- ee_compat_check/patches/*.patch
db:migrate:reset-pg:
<<: *db-migrate-reset
<<: *use-pg
db:migrate:reset-mysql:
<<: *db-migrate-reset
<<: *use-mysql
db:check-schema-pg:
<<: *db-migrate-reset
<<: *use-pg
script:
- source scripts/schema_changed.sh
migration:path-pg:
<<: *migration-paths
<<: *use-pg
migration:path-mysql:
<<: *migration-paths
<<: *use-mysql
.db-rollback: &db-rollback
extends: .dedicated-no-docs-and-no-qa-pull-cache-job
script:
- bundle exec rake db:migrate VERSION=20170523121229
- bundle exec rake db:migrate
dependencies:
- setup-test-env
db:rollback-pg:
<<: *db-rollback
<<: *use-pg
db:rollback-mysql:
<<: *db-rollback
<<: *use-mysql
gitlab:setup-pg:
<<: *gitlab-setup
<<: *use-pg
dependencies:
- setup-test-env
gitlab:setup-mysql:
<<: *gitlab-setup
<<: *use-mysql
dependencies:
- setup-test-env
coverage:
# Don't include dedicated-no-docs-no-db-pull-cache-job here since we need to
# download artifacts from all the rspec jobs instead of from setup-test-env only
extends: .dedicated-runner-default-cache
cache:
policy: pull
variables:
SETUP_DB: "false"
stage: post-test
script:
- bundle exec scripts/merge-simplecov
coverage: '/LOC \((\d+\.\d+%)\) covered.$/'
artifacts:
name: coverage
expire_in: 31d
paths:
- coverage/index.html
- coverage/assets/
except:
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/

View file

@ -0,0 +1,98 @@
include:
- template: Code-Quality.gitlab-ci.yml
code_quality:
extends: .dedicated-no-docs-no-db-pull-cache-job
# gitlab-org runners set `privileged: false` but we need to have it set to true
# since we're using Docker in Docker
tags: []
before_script: []
cache: {}
dependencies: []
variables:
SETUP_DB: "false"
sast:
extends: .dedicated-no-docs-no-db-pull-cache-job
image: docker:stable
variables:
SAST_CONFIDENCE_LEVEL: 2
DOCKER_DRIVER: overlay2
allow_failure: true
tags: []
before_script: []
cache: {}
dependencies: []
services:
- docker:stable-dind
script:
- | # this is required to avoid undesirable reset of Docker image ENV variables being set on build stage
function propagate_env_vars() {
CURRENT_ENV=$(printenv)
for VAR_NAME; do
echo $CURRENT_ENV | grep "${VAR_NAME}=" > /dev/null && echo "--env $VAR_NAME "
done
}
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- |
docker run \
$(propagate_env_vars \
SAST_ANALYZER_IMAGES \
SAST_ANALYZER_IMAGE_PREFIX \
SAST_ANALYZER_IMAGE_TAG \
SAST_DEFAULT_ANALYZERS \
SAST_BRAKEMAN_LEVEL \
SAST_GOSEC_LEVEL \
SAST_FLAWFINDER_LEVEL \
SAST_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
SAST_PULL_ANALYZER_IMAGE_TIMEOUT \
SAST_RUN_ANALYZER_TIMEOUT \
) \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
"registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code
artifacts:
reports:
sast: gl-sast-report.json
dependency_scanning:
extends: .dedicated-no-docs-no-db-pull-cache-job
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
allow_failure: true
tags: []
before_script: []
cache: {}
dependencies: []
services:
- docker:stable-dind
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- | # this is required to avoid undesirable reset of Docker image ENV variables being set on build stage
function propagate_env_vars() {
CURRENT_ENV=$(printenv)
for VAR_NAME; do
echo $CURRENT_ENV | grep "${VAR_NAME}=" > /dev/null && echo "--env $VAR_NAME "
done
}
- |
docker run \
$(propagate_env_vars \
DS_ANALYZER_IMAGES \
DS_ANALYZER_IMAGE_PREFIX \
DS_ANALYZER_IMAGE_TAG \
DS_DEFAULT_ANALYZERS \
DEP_SCAN_DISABLE_REMOTE_CHECKS \
DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
DS_PULL_ANALYZER_IMAGE_TIMEOUT \
DS_RUN_ANALYZER_TIMEOUT \
) \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
"registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code
artifacts:
reports:
dependency_scanning: gl-dependency-scanning-report.json

View file

@ -0,0 +1,233 @@
.review-only: &review-only
only:
refs:
- branches@gitlab-org/gitlab-ce
- branches@gitlab-org/gitlab-ee
kubernetes: active
except:
refs:
- master
- /(^docs[\/-].*|.*-docs$)/
.review-schedules-only: &review-schedules-only
only:
refs:
- schedules@gitlab-org/gitlab-ce
- schedules@gitlab-org/gitlab-ee
kubernetes: active
variables:
- $REVIEW_APP_CLEANUP
except:
refs:
- tags
- /(^docs[\/-].*|.*-docs$)/
.review-base: &review-base
extends: .dedicated-runner
<<: *review-only
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
cache: {}
dependencies: []
before_script:
- source scripts/utils.sh
.review-docker: &review-docker
<<: *review-base
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine
services:
- docker:stable-dind
tags:
- gitlab-org
- docker
variables: &review-docker-variables
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375
LATEST_QA_IMAGE: "gitlab/${CI_PROJECT_NAME}-qa:nightly"
QA_IMAGE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab/${CI_PROJECT_NAME}-qa:${CI_COMMIT_REF_SLUG}"
build-qa-image:
<<: *review-docker
stage: test
script:
- time docker build --cache-from ${LATEST_QA_IMAGE} --tag ${QA_IMAGE} ./qa/
- echo "${CI_JOB_TOKEN}" | docker login --username gitlab-ci-token --password-stdin ${CI_REGISTRY}
- time docker push ${QA_IMAGE}
.review-build-cng-base: &review-build-cng-base
image: ruby:2.5-alpine
stage: test
when: manual
before_script:
- source scripts/utils.sh
- install_api_client_dependencies_with_apk
- install_gitlab_gem
dependencies: []
cache: {}
script:
- BUILD_TRIGGER_TOKEN=$REVIEW_APPS_BUILD_TRIGGER_TOKEN ./scripts/trigger-build cng
review-build-cng:
<<: *review-only
<<: *review-build-cng-base
schedule:review-build-cng:
<<: *review-schedules-only
<<: *review-build-cng-base
.review-deploy-base: &review-deploy-base
<<: *review-base
stage: review
retry: 2
allow_failure: true
variables:
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
GITLAB_HELM_CHART_REF: "master"
environment: &review-environment
name: review/${CI_COMMIT_REF_NAME}
url: https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}
on_stop: review-stop
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}" > review_app_url.txt
- source scripts/utils.sh
- install_api_client_dependencies_with_apk
- source scripts/review_apps/review-apps.sh
script:
- perform_review_app_deployment
artifacts:
paths:
- review_app_url.txt
expire_in: 2 days
when: always
review-deploy:
<<: *review-deploy-base
schedule:review-deploy:
<<: *review-deploy-base
<<: *review-schedules-only
script:
- perform_review_app_deployment
review-stop:
<<: *review-base
stage: review
when: manual
allow_failure: true
variables:
GIT_DEPTH: "1"
environment:
<<: *review-environment
action: stop
script:
- source scripts/review_apps/review-apps.sh
- delete
- cleanup
.review-qa-base: &review-qa-base
<<: *review-docker
stage: qa
allow_failure: true
variables:
<<: *review-docker-variables
QA_ARTIFACTS_DIR: "${CI_PROJECT_DIR}/qa"
QA_CAN_TEST_GIT_PROTOCOL_V2: "false"
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}"
QA_DEBUG: "true"
dependencies:
- review-deploy
artifacts:
paths:
- ./qa/gitlab-qa-run-*
expire_in: 7 days
when: always
before_script:
- export CI_ENVIRONMENT_URL="$(cat review_app_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}}
review-qa-smoke:
<<: *review-qa-base
retry: 2
script:
- gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}"
review-qa-all:
<<: *review-qa-base
when: manual
script:
- gitlab-qa Test::Instance::Any "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}"
.review-performance-base: &review-performance-base
<<: *review-qa-base
stage: qa
before_script:
- export CI_ENVIRONMENT_URL="$(cat review_app_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:
- docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:6.3.1 --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
review-performance:
<<: *review-performance-base
schedule:review-performance:
<<: *review-performance-base
<<: *review-schedules-only
dependencies:
- schedule:review-deploy
schedule:review-cleanup:
<<: *review-base
<<: *review-schedules-only
stage: build
allow_failure: true
environment:
name: review/auto-cleanup
action: stop
before_script:
- source scripts/utils.sh
- install_gitlab_gem
script:
- ruby -rrubygems scripts/review_apps/automated_cleanup.rb
danger-review:
extends: .dedicated-pull-cache-job
image: registry.gitlab.com/gitlab-org/gitlab-build-images:danger
stage: test
dependencies: []
before_script: []
only:
variables:
- $DANGER_GITLAB_API_TOKEN
except:
refs:
- master
variables:
- $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/
- $CI_COMMIT_REF_NAME =~ /.*-stable(-ee)?-prepare-.*/
script:
- git version
- node --version
- yarn install --frozen-lockfile --cache-folder .yarn-cache
- danger --fail-on-errors=true

View file

@ -0,0 +1,43 @@
# Insurance in case a gem needed by one of our releases gets yanked from
# rubygems.org in the future.
cache gems:
extends: .dedicated-no-docs-no-db-pull-cache-job
script:
- bundle package --all --all-platforms
artifacts:
paths:
- vendor/cache
only:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- tags
dependencies:
- setup-test-env
gitlab_git_test:
extends: .dedicated-runner
variables:
SETUP_DB: "false"
before_script: []
dependencies: []
cache: {}
script:
- spec/support/prepare-gitlab-git-test-for-commit --check-for-changes
except:
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/
no_ee_check:
extends: .dedicated-runner
variables:
SETUP_DB: "false"
before_script: []
dependencies: []
cache: {}
script:
- scripts/no-ee-check
only:
- /.+/@gitlab-org/gitlab-ce
except:
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/

View file

@ -0,0 +1,82 @@
.tests-metadata-state: &tests-metadata-state
extends: .dedicated-runner
variables:
TESTS_METADATA_S3_BUCKET: "gitlab-ce-cache"
before_script:
- source scripts/utils.sh
artifacts:
expire_in: 31d
paths:
- knapsack/
- rspec_flaky/
- rspec_profiling/
retrieve-tests-metadata:
<<: *tests-metadata-state
stage: prepare
cache:
key: tests_metadata
policy: pull
script:
- mkdir -p knapsack/${CI_PROJECT_NAME}/
- wget -O $KNAPSACK_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || rm $KNAPSACK_RSPEC_SUITE_REPORT_PATH
- '[[ -f $KNAPSACK_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_RSPEC_SUITE_REPORT_PATH}'
- mkdir -p rspec_flaky/
- mkdir -p rspec_profiling/
- wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH
- '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}'
except:
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/
update-tests-metadata:
<<: *tests-metadata-state
stage: post-test
cache:
key: tests_metadata
paths:
- knapsack/
- rspec_flaky/
policy: push
script:
- retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json
- scripts/merge-reports ${FLAKY_RSPEC_SUITE_REPORT_PATH} rspec_flaky/all_*_*.json
- FLAKY_RSPEC_GENERATE_REPORT=1 scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH}
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH'
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $FLAKY_RSPEC_SUITE_REPORT_PATH'
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
- rm -f rspec_flaky/all_*.json rspec_flaky/new_*.json
- scripts/insert-rspec-profiling-data
only:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
flaky-examples-check:
extends: .dedicated-runner
image: ruby:2.5-alpine
services: []
before_script: []
variables:
SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false"
NEW_FLAKY_SPECS_REPORT: rspec_flaky/report-new.json
stage: post-test
allow_failure: true
retry: 0
only:
- branches
except:
- master
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/
artifacts:
expire_in: 30d
paths:
- rspec_flaky/
script:
- '[[ -f $NEW_FLAKY_SPECS_REPORT ]] || echo "{}" > ${NEW_FLAKY_SPECS_REPORT}'
- scripts/merge-reports ${NEW_FLAKY_SPECS_REPORT} rspec_flaky/new_*_*.json
- scripts/detect-new-flaky-examples $NEW_FLAKY_SPECS_REPORT

View file

@ -1,6 +1,8 @@
#### Database Reviewer Checklist #### Database Reviewer Checklist
Thank you for becoming a ~database reviewer! Please work on the list below to complete your setup. For any question, reach out to #database an mention @abrandl. Thank you for becoming a ~database reviewer! Please work on the list
below to complete your setup. For any question, reach out to #database
an mention `@abrandl`.
- [ ] Change issue title to include your name: `Database Reviewer Checklist: Your Name` - [ ] Change issue title to include your name: `Database Reviewer Checklist: Your Name`
- [ ] Review general [code review guide](https://docs.gitlab.com/ee/development/code_review.html) - [ ] Review general [code review guide](https://docs.gitlab.com/ee/development/code_review.html)
@ -12,7 +14,7 @@ Thank you for becoming a ~database reviewer! Please work on the list below to co
- [ ] Read [Understanding EXPLAIN plans](https://docs.gitlab.com/ee/development/understanding_explain_plans.html) - [ ] Read [Understanding EXPLAIN plans](https://docs.gitlab.com/ee/development/understanding_explain_plans.html)
- [ ] Review [database best practices](https://docs.gitlab.com/ee/development/#best-practices) - [ ] Review [database best practices](https://docs.gitlab.com/ee/development/#best-practices)
- [ ] Review how we use [database instances restored from a backup](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd) for testing and make sure you're set up to execute pipelines (check [README.md](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd/blob/master/README.md) and reach out to @abrandl since this is currently subject to being changed) - [ ] Review how we use [database instances restored from a backup](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd) for testing and make sure you're set up to execute pipelines (check [README.md](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd/blob/master/README.md) and reach out to @abrandl since this is currently subject to being changed)
- [ ] Get yourself added to [@gl-database](https://gitlab.com/groups/gl-database/-/group_members) group and respond to @-mentions to the group (reach out to any maintainer on the group to get added). You will get TODOs on gitlab.com for group mentions. - [ ] Get yourself added to [`@gl-database`](https://gitlab.com/groups/gl-database/-/group_members) group and respond to @-mentions to the group (reach out to any maintainer on the group to get added). You will get TODOs on gitlab.com for group mentions.
- [ ] Make sure you have proper access to at least a read-only replica in staging and production - [ ] Make sure you have proper access to at least a read-only replica in staging and production
- [ ] Indicate in `data/team.yml` your role as a database reviewer ([example MR](https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/19600/diffs)). Assign MR to your manager for merge. - [ ] Indicate in `data/team.yml` your role as a database reviewer ([example MR](https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/19600/diffs)). Assign MR to your manager for merge.
- [ ] Send one MR to improve the [review documentation](https://about.gitlab.com/handbook/engineering/workflow/code-review/database.html) or the [issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Database%20Reviewer.md) - [ ] Send one MR to improve the [review documentation](https://about.gitlab.com/handbook/engineering/workflow/code-review/database.html) or the [issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Database%20Reviewer.md)
@ -25,7 +27,7 @@ You're all set! Watch out for TODOs on GitLab.com.
###### Where to go for questions? ###### Where to go for questions?
Reach out to `#database` on Slack and mention @abrandl for any questions. Reach out to `#database` on Slack and mention `@abrandl` for any questions.
cc @abrandl cc @abrandl

View file

@ -0,0 +1,41 @@
## Summary
<!--
Please briefly describe what part of the code base needs to be refactored.
-->
## Improvements
<!--
Explain the benefits of refactoring this code.
See also https://about.gitlab.com/handbook/values/index.html#say-why-not-just-what
-->
## Risks
<!--
Please list features that can break because of this refactoring and how you intend to solve that.
-->
## Involved components
<!--
List files or directories that will be changed by the refactoring.
-->
## Optional: Intended side effects
<!--
If the refactoring involves changes apart from the main improvements (such as a better UI), list them here.
It may be a good idea to create separate issues and link them here.
-->
## Optional: Missing test coverage
<!--
If you are aware of tests that need to be written or adjusted apart from unit tests for the changed components,
please list them here.
-->
/label ~backstage

View file

@ -97,6 +97,7 @@ linters:
- Cop/LineBreakAroundConditionalBlock - Cop/LineBreakAroundConditionalBlock
- Cop/ProjectPathHelper - Cop/ProjectPathHelper
- GitlabSecurity/PublicSend - GitlabSecurity/PublicSend
- Layout/EmptyLineAfterGuardClause
- Layout/LeadingCommentSpace - Layout/LeadingCommentSpace
- Layout/SpaceAfterColon - Layout/SpaceAfterColon
- Layout/SpaceAfterComma - Layout/SpaceAfterComma
@ -112,11 +113,13 @@ linters:
- Lint/LiteralInInterpolation - Lint/LiteralInInterpolation
- Lint/ParenthesesAsGroupedExpression - Lint/ParenthesesAsGroupedExpression
- Lint/RedundantWithIndex - Lint/RedundantWithIndex
- Lint/SafeNavigationConsistency
- Lint/Syntax - Lint/Syntax
- Metrics/BlockNesting - Metrics/BlockNesting
- Naming/VariableName - Naming/VariableName
- Performance/RedundantMatch - Performance/RedundantMatch
- Performance/StringReplacement - Performance/StringReplacement
- Rails/LinkToBlank
- Rails/Presence - Rails/Presence
- Rails/RequestReferer - Rails/RequestReferer
- Style/AndOr - Style/AndOr
@ -134,6 +137,7 @@ linters:
- Style/TernaryParentheses - Style/TernaryParentheses
- Style/TrailingCommaInHashLiteral - Style/TrailingCommaInHashLiteral
- Style/UnlessElse - Style/UnlessElse
- Style/UnneededCondition
- Style/WordArray - Style/WordArray
- Style/ZeroLengthPredicate - Style/ZeroLengthPredicate

View file

@ -75,6 +75,7 @@ Naming/FileName:
- 'qa/spec/**/*' - 'qa/spec/**/*'
- 'qa/qa/specs/**/*' - 'qa/qa/specs/**/*'
- 'qa/bin/*' - 'qa/bin/*'
- 'ee/bin/*'
- 'config/**/*' - 'config/**/*'
- 'ee/config/**/*' - 'ee/config/**/*'
- 'lib/generators/**/*' - 'lib/generators/**/*'
@ -204,3 +205,9 @@ Style/ReturnNil:
# nil values on the left hand side # nil values on the left hand side
Performance/RegexpMatch: Performance/RegexpMatch:
Enabled: false Enabled: false
ActiveRecordAssociationReload:
Enabled: true
Exclude:
- 'spec/**/*'
- 'ee/spec/**/*'

View file

@ -1,42 +1,154 @@
# This configuration was generated by # This configuration was generated by
# `rubocop --auto-gen-config` # `rubocop --auto-gen-config`
# on 2018-01-18 18:23:26 +0100 using RuboCop version 0.52.1. # on 2019-05-04 16:01:00 +0000 using RuboCop version 0.68.1.
# The point is for the user to remove these configuration records # The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base. # one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new # Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again. # versions of RuboCop, may require this file to be generated again.
# Offense count: 181 # Offense count: 264
Capybara/CurrentPathExpectation: Capybara/CurrentPathExpectation:
Enabled: false Enabled: false
# Offense count: 167 # Offense count: 1097
# Cop supports --auto-correct. # Cop supports --auto-correct.
Layout/EmptyLinesAroundArguments: # Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: with_first_argument, with_fixed_indentation
Layout/AlignArguments:
Enabled: false Enabled: false
# Offense count: 83 # Offense count: 824
# Cop supports --auto-correct.
# Configuration parameters: EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
# SupportedHashRocketStyles: key, separator, table
# SupportedColonStyles: key, separator, table
# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
Layout/AlignHash:
Enabled: false
# Offense count: 13
# Cop supports --auto-correct.
Layout/ClosingHeredocIndentation:
Exclude:
- 'app/graphql/mutations/merge_requests/set_wip.rb'
- 'ee/db/geo/migrate/20180322062741_migrate_ci_job_artifacts_to_separate_registry.rb'
- 'ee/db/migrate/20160204190809_update_jenkins_service_category.rb'
- 'ee/lib/gitlab/background_migration/prune_orphaned_geo_events.rb'
- 'ee/lib/gitlab/geo/health_check.rb'
- 'lib/gitlab/background_migration/populate_untracked_uploads.rb'
- 'qa/qa/service/kubernetes_cluster.rb'
- 'spec/features/merge_request/user_sees_diff_spec.rb'
- 'spec/lib/gitlab/asciidoc_spec.rb'
- 'spec/lib/gitlab/checks/project_moved_spec.rb'
- 'spec/rubocop/cop/active_record_association_reload_spec.rb'
- 'spec/services/task_list_toggle_service_spec.rb'
# Offense count: 14
# Cop supports --auto-correct.
Layout/ClosingParenthesisIndentation:
Exclude:
- 'db/post_migrate/20180704145007_update_project_indexes.rb'
- 'ee/db/geo/migrate/20180405074130_add_partial_index_project_repository_verification.rb'
- 'ee/db/migrate/20180308234102_add_partial_index_to_project_repository_states_checksum_columns.rb'
- 'ee/db/post_migrate/20180605213516_fix_partial_index_to_project_repository_states_checksum_columns.rb'
- 'ee/lib/ee/gitlab/usage_data.rb'
- 'spec/services/issues/resolve_discussions_spec.rb'
- 'spec/services/projects/update_service_spec.rb'
- 'spec/support/helpers/stub_object_storage.rb'
- 'spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: leading, trailing
Layout/DotPosition:
Exclude:
- 'app/models/concerns/relative_positioning.rb'
- 'app/models/group.rb'
# Offense count: 69
# Cop supports --auto-correct.
Layout/EmptyLinesAroundArguments:
Exclude:
- 'app/models/concerns/discussion_on_diff.rb'
- 'app/models/concerns/resolvable_discussion.rb'
- 'app/models/diff_discussion.rb'
- 'app/models/discussion.rb'
- 'ee/app/helpers/license_helper.rb'
- 'ee/spec/models/geo/project_registry_spec.rb'
- 'lib/banzai/pipeline/broadcast_message_pipeline.rb'
- 'lib/banzai/pipeline/gfm_pipeline.rb'
- 'lib/banzai/pipeline/single_line_pipeline.rb'
- 'spec/features/markdown/copy_as_gfm_spec.rb'
# Offense count: 160
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth. # Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_brackets # SupportedStyles: special_inside_parentheses, consistent, align_brackets
Layout/IndentArray: Layout/IndentFirstArrayElement:
Enabled: false Enabled: false
# Offense count: 237 # Offense count: 631
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth. # Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces # SupportedStyles: special_inside_parentheses, consistent, align_braces
Layout/IndentHash: Layout/IndentFirstHashElement:
Enabled: false Enabled: false
# Offense count: 93 # Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: consistent, align_parentheses
Layout/IndentFirstParameter:
Exclude:
- 'app/models/ci/pipeline_schedule.rb'
- 'lib/gitlab/cross_project_access.rb'
- 'lib/gitlab/data_builder/push.rb'
- 'spec/support/helpers/repo_helpers.rb'
- 'spec/support/helpers/stub_object_storage.rb'
# Offense count: 5
# Cop supports --auto-correct.
Layout/LeadingBlankLines:
Exclude:
- 'app/workers/update_project_statistics_worker.rb'
- 'db/migrate/20161007073613_create_user_activities.rb'
- 'ee/spec/helpers/boards_helper_spec.rb'
- 'lib/tasks/yarn.rake'
- 'spec/javascripts/fixtures/merge_requests_diffs.rb'
# Offense count: 30
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: aligned, indented
Layout/MultilineOperationIndentation:
Enabled: false
# Offense count: 13
# Cop supports --auto-correct.
Layout/RescueEnsureAlignment:
Exclude:
- 'app/models/blob_viewer/dependency_manager.rb'
- 'app/models/ci/pipeline.rb'
- 'app/models/project.rb'
- 'app/services/prometheus/proxy_service.rb'
- 'app/workers/delete_stored_files_worker.rb'
- 'app/workers/reactive_caching_worker.rb'
- 'config/initializers/1_settings.rb'
- 'config/initializers/trusted_proxies.rb'
- 'ee/db/migrate/20151113115819_canonicalize_kerberos_identities.rb'
- 'lib/gitlab/background_migration/archive_legacy_traces.rb'
- 'lib/gitlab/highlight.rb'
- 'lib/tasks/gitlab/lfs/migrate.rake'
# Offense count: 344
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: require_no_space, require_space # SupportedStyles: require_no_space, require_space
Layout/SpaceInLambdaLiteral: Layout/SpaceInLambdaLiteral:
Enabled: false Enabled: false
# Offense count: 327 # Offense count: 583
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space # SupportedStyles: space, no_space
@ -44,20 +156,27 @@ Layout/SpaceInLambdaLiteral:
Layout/SpaceInsideBlockBraces: Layout/SpaceInsideBlockBraces:
Enabled: false Enabled: false
# Offense count: 156 # Offense count: 255
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: space, no_space
Layout/SpaceInsideParens: Layout/SpaceInsideParens:
Enabled: false Enabled: false
# Offense count: 26 # Offense count: 1
Lint/DisjunctiveAssignmentInConstructor:
Exclude:
- 'app/models/uploads/base.rb'
# Offense count: 19
Lint/DuplicateMethods: Lint/DuplicateMethods:
Exclude: Exclude:
- 'app/models/application_setting.rb'
- 'app/models/commit.rb' - 'app/models/commit.rb'
- 'app/models/note.rb' - 'app/models/note.rb'
- 'app/services/merge_requests/merge_service.rb'
- 'lib/bitbucket/representation/repo.rb' - 'lib/bitbucket/representation/repo.rb'
- 'lib/declarative_policy/base.rb' - 'lib/declarative_policy/base.rb'
- 'lib/gitlab/auth/ldap/person.rb'
- 'lib/gitlab/auth/o_auth/user.rb'
- 'lib/gitlab/ci/build/artifacts/metadata/entry.rb' - 'lib/gitlab/ci/build/artifacts/metadata/entry.rb'
- 'lib/gitlab/cycle_analytics/base_event_fetcher.rb' - 'lib/gitlab/cycle_analytics/base_event_fetcher.rb'
- 'lib/gitlab/diff/formatters/base_formatter.rb' - 'lib/gitlab/diff/formatters/base_formatter.rb'
@ -65,22 +184,34 @@ Lint/DuplicateMethods:
- 'lib/gitlab/git/repository.rb' - 'lib/gitlab/git/repository.rb'
- 'lib/gitlab/git/tree.rb' - 'lib/gitlab/git/tree.rb'
- 'lib/gitlab/git/wiki_page.rb' - 'lib/gitlab/git/wiki_page.rb'
- 'lib/gitlab/auth/ldap/person.rb'
- 'lib/gitlab/auth/o_auth/user.rb'
# Offense count: 4 # Offense count: 2
Lint/InterpolationCheck: Lint/InterpolationCheck:
Exclude: Exclude:
- 'spec/features/issues/filtered_search/filter_issues_spec.rb' - 'spec/features/issues/filtered_search/filter_issues_spec.rb'
- 'spec/features/users_spec.rb'
- 'spec/services/quick_actions/interpret_service_spec.rb' - 'spec/services/quick_actions/interpret_service_spec.rb'
# Offense count: 206 # Offense count: 326
# Configuration parameters: MaximumRangeSize. # Configuration parameters: MaximumRangeSize.
Lint/MissingCopEnableDirective: Lint/MissingCopEnableDirective:
Enabled: false Enabled: false
# Offense count: 9 # Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: Whitelist.
# Whitelist: present?, blank?, presence, try, try!
Lint/SafeNavigationConsistency:
Exclude:
- 'lib/gitlab/gpg/commit.rb'
# Offense count: 2
# Cop supports --auto-correct.
Lint/ToJSON:
Exclude:
- 'lib/gitlab/cycle_analytics/usage_data.rb'
- 'lib/gitlab/template/base_template.rb'
# Offense count: 7
Lint/UriEscapeUnescape: Lint/UriEscapeUnescape:
Exclude: Exclude:
- 'app/controllers/application_controller.rb' - 'app/controllers/application_controller.rb'
@ -88,13 +219,25 @@ Lint/UriEscapeUnescape:
- 'spec/lib/google_api/auth_spec.rb' - 'spec/lib/google_api/auth_spec.rb'
- 'spec/requests/api/files_spec.rb' - 'spec/requests/api/files_spec.rb'
- 'spec/requests/api/internal_spec.rb' - 'spec/requests/api/internal_spec.rb'
- 'spec/requests/api/issues_spec.rb'
# Offense count: 1 # Offense count: 1
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # Configuration parameters: CheckForMethodsWithNoSideEffects.
Lint/Void:
Exclude:
- 'lib/gitlab/git/diff_collection.rb'
# Offense count: 158
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https # URISchemes: http, https
Metrics/LineLength: Metrics/LineLength:
Max: 1310 Max: 176
# Offense count: 94
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
Naming/FileName:
Enabled: false
# Offense count: 11 # Offense count: 11
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
@ -107,61 +250,85 @@ Naming/HeredocDelimiterCase:
- 'spec/support/helpers/repo_helpers.rb' - 'spec/support/helpers/repo_helpers.rb'
- 'spec/support/helpers/seed_repo.rb' - 'spec/support/helpers/seed_repo.rb'
# Offense count: 112 # Offense count: 197
# Configuration parameters: Blacklist. # Configuration parameters: Blacklist.
# Blacklist: END, (?-mix:EO[A-Z]{1}) # Blacklist: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$))
Naming/HeredocDelimiterNaming: Naming/HeredocDelimiterNaming:
Enabled: false Enabled: false
# Offense count: 125
# Cop supports --auto-correct.
# Configuration parameters: PreferredName.
Naming/RescuedExceptionsVariableName:
Enabled: false
# Offense count: 3821 # Offense count: 6
# Cop supports --auto-correct.
Performance/InefficientHashSearch:
Exclude:
- 'app/controllers/concerns/sessionless_authentication.rb'
- 'app/models/note.rb'
- 'app/models/user_preference.rb'
- 'ee/app/models/ee/project.rb'
- 'lib/gitlab/import_export/members_mapper.rb'
- 'qa/spec/spec_helper.rb'
# Offense count: 3
# Cop supports --auto-correct.
Performance/ReverseEach:
Exclude:
- 'app/models/commit.rb'
- 'db/migrate/20190222051615_add_indexes_for_merge_request_diffs_query.rb'
- 'lib/gitlab/profiler.rb'
# Offense count: 7081
# Configuration parameters: Prefixes. # Configuration parameters: Prefixes.
# Prefixes: when, with, without # Prefixes: when, with, without
RSpec/ContextWording: RSpec/ContextWording:
Enabled: false Enabled: false
# Offense count: 293 # Offense count: 407
# Cop supports --auto-correct.
RSpec/EmptyLineAfterFinalLet: RSpec/EmptyLineAfterFinalLet:
Enabled: false Enabled: false
# Offense count: 188 # Offense count: 232
# Cop supports --auto-correct.
RSpec/EmptyLineAfterSubject: RSpec/EmptyLineAfterSubject:
Enabled: false Enabled: false
# Offense count: 258 # Offense count: 719
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: method_call, block # SupportedStyles: method_call, block
RSpec/ExpectChange: RSpec/ExpectChange:
Enabled: false Enabled: false
# Offense count: 221 # Offense count: 512
RSpec/ExpectInHook: RSpec/ExpectInHook:
Enabled: false Enabled: false
# Offense count: 19 # Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: it_behaves_like, it_should_behave_like # SupportedStyles: it_behaves_like, it_should_behave_like
RSpec/ItBehavesLike: RSpec/ItBehavesLike:
Exclude: Exclude:
- 'spec/lib/gitlab/git/commit_spec.rb' - 'spec/lib/gitlab/git/commit_spec.rb'
- 'spec/lib/gitlab/git/repository_spec.rb' - 'spec/lib/gitlab/git/repository_spec.rb'
- 'spec/lib/gitlab/shell_spec.rb'
- 'spec/services/notification_service_spec.rb' - 'spec/services/notification_service_spec.rb'
- 'spec/workers/git_garbage_collect_worker_spec.rb'
# Offense count: 5 # Offense count: 3
RSpec/IteratedExpectation: RSpec/IteratedExpectation:
Exclude: Exclude:
- 'spec/features/admin/admin_settings_spec.rb' - 'spec/features/admin/admin_settings_spec.rb'
- 'spec/features/merge_requests/diff_notes_resolve_spec.rb'
- 'spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb'
- 'spec/lib/gitlab/gitlab_import/client_spec.rb' - 'spec/lib/gitlab/gitlab_import/client_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/client_spec.rb' - 'spec/lib/gitlab/legacy_github_import/client_spec.rb'
# Offense count: 75 # Offense count: 68
# Cop supports --auto-correct.
RSpec/LetBeforeExamples: RSpec/LetBeforeExamples:
Exclude: Exclude:
- 'spec/controllers/projects/commit_controller_spec.rb'
- 'spec/lib/banzai/filter/issue_reference_filter_spec.rb' - 'spec/lib/banzai/filter/issue_reference_filter_spec.rb'
- 'spec/lib/banzai/filter/user_reference_filter_spec.rb' - 'spec/lib/banzai/filter/user_reference_filter_spec.rb'
- 'spec/lib/gitlab/email/handler/create_issue_handler_spec.rb' - 'spec/lib/gitlab/email/handler/create_issue_handler_spec.rb'
@ -170,12 +337,11 @@ RSpec/LetBeforeExamples:
- 'spec/models/commit_range_spec.rb' - 'spec/models/commit_range_spec.rb'
- 'spec/models/milestone_spec.rb' - 'spec/models/milestone_spec.rb'
- 'spec/models/project_services/packagist_service_spec.rb' - 'spec/models/project_services/packagist_service_spec.rb'
- 'spec/models/repository_spec.rb'
- 'spec/rubocop/cop/migration/update_column_in_batches_spec.rb' - 'spec/rubocop/cop/migration/update_column_in_batches_spec.rb'
- 'spec/serializers/pipeline_details_entity_spec.rb' - 'spec/serializers/pipeline_details_entity_spec.rb'
- 'spec/views/ci/lints/show.html.haml_spec.rb'
# Offense count: 1 # Offense count: 1
# Cop supports --auto-correct.
RSpec/MultipleSubjects: RSpec/MultipleSubjects:
Exclude: Exclude:
- 'spec/services/merge_requests/create_from_issue_service_spec.rb' - 'spec/services/merge_requests/create_from_issue_service_spec.rb'
@ -188,95 +354,136 @@ RSpec/OverwritingSetup:
- 'spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb' - 'spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb'
- 'spec/services/notes/quick_actions_service_spec.rb' - 'spec/services/notes/quick_actions_service_spec.rb'
# Offense count: 965 # Offense count: 1828
# Cop supports --auto-correct.
# Configuration parameters: Strict, EnforcedStyle. # Configuration parameters: Strict, EnforcedStyle.
# SupportedStyles: inflected, explicit # SupportedStyles: inflected, explicit
RSpec/PredicateMatcher: RSpec/PredicateMatcher:
Enabled: false Enabled: false
# Offense count: 35 # Offense count: 57
RSpec/RepeatedExample: RSpec/RepeatedExample:
Enabled: false Enabled: false
# Offense count: 140 # Offense count: 474
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: and_return, block # SupportedStyles: and_return, block
RSpec/ReturnFromStub: RSpec/ReturnFromStub:
Enabled: false Enabled: false
# Offense count: 112 # Offense count: 188
RSpec/ScatteredLet: RSpec/ScatteredLet:
Enabled: false Enabled: false
# Offense count: 22 # Offense count: 10
RSpec/ScatteredSetup: RSpec/ScatteredSetup:
Exclude: Exclude:
- 'spec/controllers/projects/templates_controller_spec.rb' - 'spec/controllers/projects/templates_controller_spec.rb'
- 'spec/lib/gitlab/bitbucket_import/importer_spec.rb' - 'spec/lib/gitlab/bitbucket_import/importer_spec.rb'
- 'spec/lib/gitlab/git/env_spec.rb'
- 'spec/requests/api/jobs_spec.rb' - 'spec/requests/api/jobs_spec.rb'
- 'spec/services/projects/create_service_spec.rb' - 'spec/services/projects/create_service_spec.rb'
# Offense count: 1 # Offense count: 1
# Cop supports --auto-correct.
RSpec/SharedContext: RSpec/SharedContext:
Exclude: Exclude:
- 'spec/features/admin/admin_groups_spec.rb' - 'spec/features/admin/admin_groups_spec.rb'
# Offense count: 5 # Offense count: 4
RSpec/VoidExpect: RSpec/VoidExpect:
Exclude: Exclude:
- 'spec/features/projects/artifacts/download_spec.rb'
- 'spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb' - 'spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb'
- 'spec/models/ci/group_spec.rb' - 'spec/models/ci/group_spec.rb'
- 'spec/models/ci/runner_spec.rb' - 'spec/models/ci/runner_spec.rb'
- 'spec/services/users/destroy_service_spec.rb' - 'spec/services/users/destroy_service_spec.rb'
# Offense count: 41 # Offense count: 8
# Cop supports --auto-correct.
Rails/BelongsTo:
Exclude:
- 'app/models/deployment.rb'
- 'app/models/environment.rb'
- 'ee/app/models/prometheus_alert.rb'
- 'ee/app/models/prometheus_alert_event.rb'
# Offense count: 80
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: db/migrate/*.rb # Include: db/migrate/*.rb
Rails/CreateTableWithTimestamps: Rails/CreateTableWithTimestamps:
Enabled: false Enabled: false
# Offense count: 155 # Offense count: 222
# Configuration parameters: EnforcedStyle.
# SupportedStyles: slashes, arguments
Rails/FilePath: Rails/FilePath:
Enabled: false Enabled: false
# Offense count: 121 # Offense count: 167
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/models/**/*.rb # Include: app/models/**/*.rb
Rails/HasManyOrHasOneDependent: Rails/HasManyOrHasOneDependent:
Enabled: false Enabled: false
# Offense count: 157 # Offense count: 40
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: numeric, symbolic
Rails/HttpStatus:
Enabled: false
# Offense count: 2
# Configuration parameters: Include.
# Include: app/controllers/**/*.rb
Rails/IgnoredSkipActionFilterOption:
Exclude:
- 'app/controllers/projects/snippets_controller.rb'
- 'app/controllers/snippets_controller.rb'
# Offense count: 87
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/models/**/*.rb # Include: app/models/**/*.rb
Rails/InverseOf: Rails/InverseOf:
Enabled: false Enabled: false
# Offense count: 48 # Offense count: 46
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/controllers/**/*.rb # Include: app/controllers/**/*.rb
Rails/LexicallyScopedActionFilter: Rails/LexicallyScopedActionFilter:
Enabled: false Enabled: false
# Offense count: 14 # Offense count: 4
# Cop supports --auto-correct.
Rails/LinkToBlank:
Exclude:
- 'app/helpers/projects_helper.rb'
- 'app/helpers/wiki_helper.rb'
- 'ee/app/helpers/ee/user_callouts_helper.rb'
- 'ee/app/helpers/license_helper.rb'
# Offense count: 11
# Cop supports --auto-correct. # Cop supports --auto-correct.
Rails/Presence: Rails/Presence:
Exclude: Exclude:
- 'app/controllers/projects/blob_controller.rb'
- 'app/models/ci/pipeline.rb' - 'app/models/ci/pipeline.rb'
- 'app/models/clusters/platforms/kubernetes.rb' - 'app/models/clusters/platforms/kubernetes.rb'
- 'app/models/concerns/mentionable.rb' - 'app/models/concerns/mentionable.rb'
- 'app/models/concerns/token_authenticatable.rb'
- 'app/models/project_services/hipchat_service.rb' - 'app/models/project_services/hipchat_service.rb'
- 'app/models/project_services/irker_service.rb' - 'app/models/project_services/irker_service.rb'
- 'app/models/project_services/jira_service.rb' - 'app/models/project_services/jira_service.rb'
- 'app/models/project_services/kubernetes_service.rb' - 'app/models/project_services/kubernetes_service.rb'
- 'app/models/project_services/packagist_service.rb' - 'app/models/project_services/packagist_service.rb'
- 'app/models/wiki_page.rb' - 'app/models/wiki_page.rb'
- 'lib/gitlab/git/hook.rb'
- 'lib/gitlab/github_import/importer/releases_importer.rb' - 'lib/gitlab/github_import/importer/releases_importer.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/RedundantAllowNil:
Exclude:
- 'app/models/application_setting.rb'
# Offense count: 2 # Offense count: 2
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: db/migrate/*.rb # Include: db/migrate/*.rb
@ -284,8 +491,8 @@ Rails/ReversibleMigration:
Exclude: Exclude:
- 'db/migrate/20160824103857_drop_unused_ci_tables.rb' - 'db/migrate/20160824103857_drop_unused_ci_tables.rb'
# Offense count: 446 # Offense count: 860
# Configuration parameters: Blacklist. # Configuration parameters: Blacklist, Whitelist.
# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters # Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
Rails/SkipsModelValidations: Rails/SkipsModelValidations:
Enabled: false Enabled: false
@ -297,21 +504,25 @@ Rails/UnknownEnv:
Exclude: Exclude:
- 'db/migrate/20171124125748_populate_missing_merge_request_statuses.rb' - 'db/migrate/20171124125748_populate_missing_merge_request_statuses.rb'
# Offense count: 13 # Offense count: 11
# Cop supports --auto-correct. # Cop supports --auto-correct.
Security/YAMLLoad: Security/YAMLLoad:
Exclude: Exclude:
- 'config/initializers/carrierwave.rb'
- 'lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb' - 'lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb'
- 'lib/gitlab/redis/wrapper.rb' - 'lib/gitlab/redis/wrapper.rb'
- 'lib/system_check/incoming_email/imap_authentication_check.rb' - 'lib/system_check/incoming_email/imap_authentication_check.rb'
- 'spec/config/mail_room_spec.rb' - 'spec/config/mail_room_spec.rb'
- 'spec/initializers/secret_token_spec.rb' - 'spec/initializers/secret_token_spec.rb'
- 'spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb' - 'spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb'
- 'spec/models/clusters/platforms/kubernetes_spec.rb'
- 'spec/models/project_services/kubernetes_service_spec.rb' - 'spec/models/project_services/kubernetes_service_spec.rb'
# Offense count: 64 # Offense count: 34
# Configuration parameters: EnforcedStyle.
# SupportedStyles: inline, group
Style/AccessModifierDeclarations:
Enabled: false
# Offense count: 121
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: percent_q, bare_percent # SupportedStyles: percent_q, bare_percent
@ -324,17 +535,13 @@ Style/CommentedKeyword:
- 'lib/tasks/gitlab/backup.rake' - 'lib/tasks/gitlab/backup.rake'
- 'spec/tasks/gitlab/backup_rake_spec.rb' - 'spec/tasks/gitlab/backup_rake_spec.rb'
# Offense count: 30
Style/DateTime:
Enabled: false
# Offense count: 1 # Offense count: 1
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/Dir: Style/Dir:
Exclude: Exclude:
- 'qa/qa.rb' - 'qa/qa.rb'
# Offense count: 9 # Offense count: 7
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/EachWithObject: Style/EachWithObject:
Exclude: Exclude:
@ -345,46 +552,42 @@ Style/EachWithObject:
- 'lib/gitlab/i18n/po_linter.rb' - 'lib/gitlab/i18n/po_linter.rb'
- 'lib/gitlab/import_export/members_mapper.rb' - 'lib/gitlab/import_export/members_mapper.rb'
- 'lib/gitlab/import_export/relation_factory.rb' - 'lib/gitlab/import_export/relation_factory.rb'
- 'scripts/static-analysis'
# Offense count: 24 # Offense count: 34
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: empty, nil, both # SupportedStyles: empty, nil, both
Style/EmptyElse: Style/EmptyElse:
Enabled: false Enabled: false
# Offense count: 14 # Offense count: 11
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/EmptyLambdaParameter: Style/EmptyLambdaParameter:
Exclude: Exclude:
- 'app/models/ci/build.rb' - 'app/models/ci/build.rb'
- 'app/models/ci/runner.rb' - 'app/models/ci/runner.rb'
# Offense count: 12 # Offense count: 9
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/EmptyLiteral: Style/EmptyLiteral:
Exclude: Exclude:
- 'features/steps/project/commits/commits.rb'
- 'lib/gitlab/fogbugz_import/importer.rb' - 'lib/gitlab/fogbugz_import/importer.rb'
- 'lib/gitlab/git/diff_collection.rb' - 'lib/gitlab/git/diff_collection.rb'
- 'lib/gitlab/gitaly_client.rb' - 'lib/gitlab/gitaly_client.rb'
- 'scripts/trigger-build'
- 'spec/features/merge_requests/versions_spec.rb'
- 'spec/helpers/merge_requests_helper_spec.rb' - 'spec/helpers/merge_requests_helper_spec.rb'
- 'spec/lib/gitlab/request_context_spec.rb' - 'spec/lib/gitlab/request_context_spec.rb'
- 'spec/lib/gitlab/workhorse_spec.rb' - 'spec/lib/gitlab/workhorse_spec.rb'
- 'spec/requests/api/jobs_spec.rb' - 'spec/requests/api/jobs_spec.rb'
- 'spec/support/shared_examples/chat_slash_commands_shared_examples.rb' - 'spec/support/shared_examples/chat_slash_commands_shared_examples.rb'
# Offense count: 102 # Offense count: 180
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: compact, expanded # SupportedStyles: compact, expanded
Style/EmptyMethod: Style/EmptyMethod:
Enabled: false Enabled: false
# Offense count: 23 # Offense count: 40
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/Encoding: Style/Encoding:
Enabled: false Enabled: false
@ -394,52 +597,52 @@ Style/EvalWithLocation:
Exclude: Exclude:
- 'app/models/service.rb' - 'app/models/service.rb'
# Offense count: 35 # Offense count: 203
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: format, sprintf, percent # SupportedStyles: format, sprintf, percent
Style/FormatString: Style/FormatString:
Enabled: false Enabled: false
# Offense count: 384 # Offense count: 669
# Configuration parameters: MinBodyLength. # Configuration parameters: MinBodyLength.
Style/GuardClause: Style/GuardClause:
Enabled: false Enabled: false
# Offense count: 22 # Offense count: 27
Style/IfInsideElse: Style/IfInsideElse:
Enabled: false Enabled: false
# Offense count: 809 # Offense count: 1346
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/IfUnlessModifier: Style/IfUnlessModifier:
Enabled: false Enabled: false
# Offense count: 75 # Offense count: 186
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: line_count_dependent, lambda, literal # SupportedStyles: line_count_dependent, lambda, literal
Style/Lambda: Style/Lambda:
Enabled: false Enabled: false
# Offense count: 11 # Offense count: 3
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/LineEndConcatenation: Style/LineEndConcatenation:
Exclude: Exclude:
- 'app/helpers/tree_helper.rb'
- 'spec/features/issuables/markdown_references_spec.rb'
- 'spec/lib/gitlab/checks/project_moved_spec.rb'
- 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb' - 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb'
- 'spec/lib/gitlab/incoming_email_spec.rb' - 'spec/lib/gitlab/incoming_email_spec.rb'
# Offense count: 18 # Offense count: 18
Style/MethodMissing: Style/MethodMissingSuper:
Enabled: false Enabled: false
# Offense count: 7 # Offense count: 18
Style/MissingRespondToMissing:
Enabled: false
# Offense count: 6
Style/MixinUsage: Style/MixinUsage:
Exclude: Exclude:
- 'features/support/env.rb'
- 'spec/factories/ci/builds.rb' - 'spec/factories/ci/builds.rb'
- 'spec/factories/ci/job_artifacts.rb' - 'spec/factories/ci/job_artifacts.rb'
- 'spec/factories/lfs_objects.rb' - 'spec/factories/lfs_objects.rb'
@ -447,59 +650,63 @@ Style/MixinUsage:
- 'spec/lib/gitlab/import_export/project_tree_restorer_spec.rb' - 'spec/lib/gitlab/import_export/project_tree_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/version_checker_spec.rb' - 'spec/lib/gitlab/import_export/version_checker_spec.rb'
# Offense count: 6 # Offense count: 4
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/MultilineIfModifier: Style/MultilineIfModifier:
Exclude: Exclude:
- 'app/helpers/snippets_helper.rb' - 'app/helpers/snippets_helper.rb'
- 'app/models/project_wiki.rb' - 'app/models/project_wiki.rb'
- 'app/services/ci/process_pipeline_service.rb' - 'app/services/ci/process_pipeline_service.rb'
- 'app/services/create_deployment_service.rb'
- 'lib/api/commit_statuses.rb' - 'lib/api/commit_statuses.rb'
- 'lib/gitlab/ci/trace.rb'
# Offense count: 25 # Offense count: 72
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: literals, strict
Style/MutableConstant:
Enabled: false
# Offense count: 28
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: Whitelist. # Configuration parameters: Whitelist.
# Whitelist: be, be_a, be_an, be_between, be_falsey, be_kind_of, be_instance_of, be_truthy, be_within, eq, eql, end_with, include, match, raise_error, respond_to, start_with # Whitelist: be, be_a, be_an, be_between, be_falsey, be_kind_of, be_instance_of, be_truthy, be_within, eq, eql, end_with, include, match, raise_error, respond_to, start_with
Style/NestedParenthesizedCalls: Style/NestedParenthesizedCalls:
Enabled: false Enabled: false
# Offense count: 19 # Offense count: 31
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength. # Configuration parameters: EnforcedStyle, MinBodyLength.
# SupportedStyles: skip_modifier_ifs, always # SupportedStyles: skip_modifier_ifs, always
Style/Next: Style/Next:
Enabled: false Enabled: false
# Offense count: 61 # Offense count: 67
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedOctalStyle. # Configuration parameters: EnforcedOctalStyle.
# SupportedOctalStyles: zero_with_o, zero_only # SupportedOctalStyles: zero_with_o, zero_only
Style/NumericLiteralPrefix: Style/NumericLiteralPrefix:
Enabled: false Enabled: false
# Offense count: 114 # Offense count: 186
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle. # Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods.
# SupportedStyles: predicate, comparison # SupportedStyles: predicate, comparison
Style/NumericPredicate: Style/NumericPredicate:
Enabled: false Enabled: false
# Offense count: 4 # Offense count: 2
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/OrAssignment: Style/OrAssignment:
Exclude: Exclude:
- 'app/models/concerns/token_authenticatable.rb'
- 'lib/api/commit_statuses.rb' - 'lib/api/commit_statuses.rb'
- 'lib/gitlab/project_transfer.rb' - 'lib/gitlab/project_transfer.rb'
# Offense count: 50 # Offense count: 79
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/ParallelAssignment: Style/ParallelAssignment:
Enabled: false Enabled: false
# Offense count: 917 # Offense count: 1390
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters. # Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters: Style/PercentLiteralDelimiters:
@ -521,25 +728,20 @@ Style/PerlBackrefs:
- 'lib/gitlab/search_results.rb' - 'lib/gitlab/search_results.rb'
- 'lib/gitlab/sherlock/query.rb' - 'lib/gitlab/sherlock/query.rb'
# Offense count: 87 # Offense count: 129
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: compact, exploded # SupportedStyles: compact, exploded
Style/RaiseArgs: Style/RaiseArgs:
Enabled: false Enabled: false
# Offense count: 9 # Offense count: 3
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantBegin: Style/RedundantBegin:
Exclude: Exclude:
- 'app/controllers/projects/clusters/gcp_controller.rb'
- 'app/models/merge_request.rb' - 'app/models/merge_request.rb'
- 'app/services/projects/import_service.rb' - 'app/services/projects/import_service.rb'
- 'lib/api/branches.rb'
- 'lib/gitlab/current_settings.rb'
- 'lib/gitlab/git/commit.rb'
- 'lib/gitlab/health_checks/base_abstract_check.rb' - 'lib/gitlab/health_checks/base_abstract_check.rb'
- 'lib/tasks/gitlab/task_helpers.rb'
# Offense count: 1 # Offense count: 1
# Cop supports --auto-correct. # Cop supports --auto-correct.
@ -547,7 +749,7 @@ Style/RedundantConditional:
Exclude: Exclude:
- 'lib/system_check/helpers.rb' - 'lib/system_check/helpers.rb'
# Offense count: 57 # Offense count: 360
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantFreeze: Style/RedundantFreeze:
Enabled: false Enabled: false
@ -567,41 +769,36 @@ Style/RedundantReturn:
- 'lib/gitlab/utils.rb' - 'lib/gitlab/utils.rb'
- 'lib/google_api/auth.rb' - 'lib/google_api/auth.rb'
# Offense count: 460 # Offense count: 700
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantSelf: Style/RedundantSelf:
Enabled: false Enabled: false
# Offense count: 142 # Offense count: 28
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, AllowInnerSlashes. # Configuration parameters: EnforcedStyle, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed # SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral: Style/RegexpLiteral:
Enabled: true Enabled: false
EnforcedStyle: mixed
AllowInnerSlashes: false
# Offense count: 36 # Offense count: 41
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RescueModifier: Style/RescueModifier:
Enabled: false Enabled: false
# Offense count: 107 # Offense count: 197
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: implicit, explicit # SupportedStyles: implicit, explicit
Style/RescueStandardError: Style/RescueStandardError:
Enabled: false Enabled: false
# Offense count: 8 # Offense count: 5
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/SelfAssignment: Style/SelfAssignment:
Exclude: Exclude:
- 'app/models/concerns/bulk_member_access_load.rb' - 'app/models/concerns/bulk_member_access_load.rb'
- 'app/serializers/base_serializer.rb' - 'app/serializers/base_serializer.rb'
- 'app/services/notification_service.rb'
- 'lib/api/runners.rb'
- 'spec/features/merge_requests/diff_notes_resolve_spec.rb'
- 'spec/features/projects/clusters/interchangeability_spec.rb' - 'spec/features/projects/clusters/interchangeability_spec.rb'
- 'spec/support/import_export/configuration_helper.rb' - 'spec/support/import_export/configuration_helper.rb'
@ -612,7 +809,7 @@ Style/SingleLineMethods:
Exclude: Exclude:
- 'lib/gitlab/ci/ansi2html.rb' - 'lib/gitlab/ci/ansi2html.rb'
# Offense count: 66 # Offense count: 91
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: . # Configuration parameters: .
# SupportedStyles: use_perl_names, use_english_names # SupportedStyles: use_perl_names, use_english_names
@ -625,21 +822,21 @@ Style/StderrPuts:
Exclude: Exclude:
- 'config/initializers/rspec_profiling.rb' - 'config/initializers/rspec_profiling.rb'
# Offense count: 45 # Offense count: 65
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: single_quotes, double_quotes # SupportedStyles: single_quotes, double_quotes
Style/StringLiteralsInInterpolation: Style/StringLiteralsInInterpolation:
Enabled: false Enabled: false
# Offense count: 106 # Offense count: 187
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods. # Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method # IgnoredMethods: respond_to, define_method
Style/SymbolProc: Style/SymbolProc:
Enabled: false Enabled: false
# Offense count: 9 # Offense count: 7
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, AllowSafeAssignment. # Configuration parameters: EnforcedStyle, AllowSafeAssignment.
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex # SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
@ -647,45 +844,65 @@ Style/TernaryParentheses:
Exclude: Exclude:
- 'app/finders/projects_finder.rb' - 'app/finders/projects_finder.rb'
- 'app/helpers/namespaces_helper.rb' - 'app/helpers/namespaces_helper.rb'
- 'features/support/capybara.rb'
- 'lib/gitlab/ci/build/artifacts/metadata/entry.rb' - 'lib/gitlab/ci/build/artifacts/metadata/entry.rb'
- 'spec/requests/api/pipeline_schedules_spec.rb' - 'spec/requests/api/pipeline_schedules_spec.rb'
- 'spec/support/capybara.rb' - 'spec/support/capybara.rb'
# Offense count: 17 # Offense count: 3
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowNamedUnderscoreVariables. # Configuration parameters: EnforcedStyleForMultiline.
Style/TrailingUnderscoreVariable: # SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInArguments:
Exclude: Exclude:
- 'app/controllers/admin/background_jobs_controller.rb' - 'spec/features/markdown/copy_as_gfm_spec.rb'
- 'app/controllers/invites_controller.rb'
- 'app/helpers/tab_helper.rb'
- 'lib/backup/manager.rb'
- 'lib/gitlab/logger.rb'
- 'lib/gitlab/upgrader.rb'
- 'lib/system_check/app/migrations_are_up_check.rb'
- 'lib/system_check/incoming_email/mail_room_running_check.rb'
- 'lib/tasks/gitlab/check.rake'
- 'lib/tasks/gitlab/task_helpers.rb'
- 'spec/lib/gitlab/etag_caching/middleware_spec.rb'
- 'spec/services/quick_actions/interpret_service_spec.rb'
# Offense count: 4 # Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInArrayLiteral:
Exclude:
- 'ee/spec/models/project_spec.rb'
- 'spec/lib/gitlab/diff/position_tracer_spec.rb'
- 'spec/lib/gitlab/metrics/dashboard/processor_spec.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInHashLiteral:
Exclude:
- 'lib/gitlab/ci/ansi2html.rb'
- 'lib/gitlab/kubernetes.rb'
# Offense count: 2
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/UnlessElse: Style/UnlessElse:
Exclude: Exclude:
- 'lib/backup/manager.rb' - 'lib/backup/manager.rb'
- 'lib/gitlab/project_search_results.rb' - 'lib/gitlab/project_search_results.rb'
- 'lib/tasks/gitlab/check.rake'
- 'spec/features/issues/award_emoji_spec.rb'
# Offense count: 31 # Offense count: 10
# Cop supports --auto-correct.
Style/UnneededCondition:
Exclude:
- 'app/helpers/button_helper.rb'
- 'app/helpers/environment_helper.rb'
- 'app/models/project.rb'
- 'app/services/issuable/clone/base_service.rb'
- 'app/services/prometheus/adapter_service.rb'
- 'lib/gitlab/email/message/repository_push.rb'
- 'lib/gitlab/prometheus_client.rb'
- 'spec/lib/rspec_flaky/flaky_example_spec.rb'
# Offense count: 73
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/UnneededInterpolation: Style/UnneededInterpolation:
Enabled: false Enabled: false
# Offense count: 22840 # Offense count: 2
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # Cop supports --auto-correct.
# URISchemes: http, https Style/UnneededSort:
Metrics/LineLength: Exclude:
Max: 1310 - 'app/models/concerns/resolvable_discussion.rb'
- 'lib/gitlab/highlight.rb'

View file

@ -2,7 +2,7 @@
"plugins":[ "plugins":[
"./scripts/frontend/stylelint/stylelint-duplicate-selectors.js", "./scripts/frontend/stylelint/stylelint-duplicate-selectors.js",
"./scripts/frontend/stylelint/stylelint-utility-classes.js", "./scripts/frontend/stylelint/stylelint-utility-classes.js",
"stylelint-scss", "stylelint-scss"
], ],
"rules":{ "rules":{
"at-rule-blacklist":[ "at-rule-blacklist":[
@ -94,7 +94,7 @@
{ {
"message":"Selector should be written in lowercase with hyphens (selector-class-pattern)", "message":"Selector should be written in lowercase with hyphens (selector-class-pattern)",
"severity": "warning" "severity": "warning"
}, }
], ],
"selector-list-comma-newline-after":"always", "selector-list-comma-newline-after":"always",
"selector-max-compound-selectors":[3, { "severity": "warning" }], "selector-max-compound-selectors":[3, { "severity": "warning" }],
@ -104,8 +104,8 @@
"selector-pseudo-element-no-unknown":true, "selector-pseudo-element-no-unknown":true,
"shorthand-property-no-redundant-values":true, "shorthand-property-no-redundant-values":true,
"string-quotes":"single", "string-quotes":"single",
"value-no-vendor-prefix":[true, { ignoreValues: ["sticky"] }], "value-no-vendor-prefix":[true, { "ignoreValues": ["sticky"] }],
"stylelint-gitlab/duplicate-selectors":[true,{ "severity": "warning" }], "stylelint-gitlab/duplicate-selectors":[true,{ "severity": "warning" }],
"stylelint-gitlab/utility-classes":[true,{ "severity": "warning" }], "stylelint-gitlab/utility-classes":[true,{ "severity": "warning" }]
} }
} }

View file

@ -2,60 +2,82 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 11.10.8 (2019-06-27) ## 11.11.7
### Security (9 changes)
- Restrict slash commands to users who can log in.
- Patch XSS issue in wiki links.
- Filter merge request params on the new merge request page.
- Fix Server Side Request Forgery mitigation bypass.
- Show badges if pipelines are public otherwise default to project permissions.
- Do not allow localhost url redirection in GitHub Integration.
- Do not show moved issue id for users that cannot read issue.
- Use source project as permissions reference for MergeRequestsController#pipelines.
- Drop feature to take ownership of trigger token.
## 11.11.6
- Unreleased due to QA failure.
## 11.11.5 (2019-06-27)
- No changes.
### Security (10 changes) ### Security (10 changes)
- Fix Denial of Service for comments when rendering issues/MR comments. - Disable Rails SQL query cache when applying service templates. !30060
- Gate MR head_pipeline behind read_pipeline ability. - Add missing authorizations in GraphQL.
- Fix DoS vulnerability in color validation regex. - Fix DoS vulnerability in color validation regex.
- Expose merge requests count based on user access. - Expose merge requests count based on user access.
- Persist tmp snippet uploads at users. - Fix Denial of Service for comments when rendering issues/MR comments.
- Add missing authorizations in GraphQL. - Gate MR head_pipeline behind read_pipeline ability.
- Disable Rails SQL query cache when applying service templates.
- Prevent Billion Laughs attack. - Prevent Billion Laughs attack.
- Correctly check permissions when creating snippet notes. - Correctly check permissions when creating snippet notes.
- Prevent the detection of merge request templates by unauthorized users. - Prevent the detection of merge request templates by unauthorized users.
- Persist tmp snippet uploads at users.
### Performance (1 change)
- Add improvements to global search of issues and merge requests. !27817
## 11.10.7 (2019-06-26) ## 11.11.4 (2019-06-26)
### Fixed (3 changes) ### Fixed (3 changes)
- Remove a default git depth in Pipelines for merge requests. !28926 - Fix Fogbugz Importer not working. !29383
- Fix label click scrolling to top. !29202
- Fix scrolling to top on assignee change. !29500 - Fix scrolling to top on assignee change. !29500
- Fix IDE commit using latest ref in branch and overriding contents. !29769
## 11.10.6 (2019-06-04) ## 11.11.3 (2019-06-10)
### Fixed (7 changes, 1 of them is from the community) ### Fixed (5 changes)
- Allow a member to have an access level equal to parent group. !27913 - Fix invalid visibility string comparison in project import. !28612
- Fix uploading of LFS tracked file through UI. !28052 - Remove a default git depth in Pipelines for merge requests. !28926
- Use 3-way merge for squashing commits. !28078 - Fix connection to Tiller error while uninstalling. !29131
- Use a path for the related merge requests endpoint. !28171 - Fix label click scrolling to top. !29202
- Fix project visibility level validation. !28305 (Peter Marko) - Make OpenID Connect work without requiring a name. !29312
- Fix Rugged get_tree_entries recursive flag not working. !28494
## 11.11.2 (2019-06-04)
### Fixed (7 changes)
- Update SAST.gitlab-ci.yml - Add SAST_GITLEAKS_ENTROPY_LEVEL. !28607
- Fix OmniAuth OAuth2Generic strategy not loading. !28680
- Use source ref in pipeline webhook. !28772 - Use source ref in pipeline webhook. !28772
- Fix migration failure when groups are missing route. !29022
- Stop two-step rebase from hanging when errors occur. !29068
- Fix project settings not being able to update. !29097
- Fix display of 'Promote to group label' button.
### Other (1 change) ### Other (1 change)
- Fix input group height. - Fix input group height.
## 11.10.5 (2019-05-30) ## 11.11.1 (2019-05-30)
### Security (12 changes, 1 of them is from the community) ### Security (12 changes)
- Protect Gitlab::HTTP against DNS rebinding attack.
- Fix project visibility level validation. (Peter Marko)
- Update Knative version.
- Add DNS rebinding protection settings. - Add DNS rebinding protection settings.
- Prevent XSS injection in note imports. - Prevent XSS injection in note imports.
- Prevent invalid branch for merge request. - Prevent invalid branch for merge request.
@ -63,10 +85,198 @@ entry.
- Fix confidential issue label disclosure on milestone view. - Fix confidential issue label disclosure on milestone view.
- Fix url redaction for issue links. - Fix url redaction for issue links.
- Resolve: Milestones leaked via search API. - Resolve: Milestones leaked via search API.
- Protect Gitlab::HTTP against DNS rebinding attack.
- Add extra fields for handling basic auth on import by url page.
- Prevent bypass of restriction disabling web password sign in. - Prevent bypass of restriction disabling web password sign in.
- Update Gitaly to fix GetArchive vulnerability.
- Hide confidential issue title on unsubscribe for anonymous users. - Hide confidential issue title on unsubscribe for anonymous users.
## 11.11.0 (2019-05-22)
### Security (1 change)
- Destroy project remote mirrors instead of disabling. !27087
### Fixed (74 changes, 19 of them are from the community)
- Don't create a temp reference for branch comparisons within project. !24038
- Fix some label links not appearing on group labels page and label title being a link on project labels page. !24060 (Tanya Pazitny)
- Fix extra emails for custom notifications. !25607
- Rewind IID on Ci::Pipelines. !26490
- Fix duplicate merge request pipelines created by Sidekiq worker retry. !26643
- Catch and report OpenSSL exceptions while fetching external configuration files in CI::Config. !26750 (Drew Cimino)
- stop rendering download links for expired artifacts on the project tags page. !26753 (Drew Cimino)
- Format extra help page text like wiki. !26782 (Bastian Blank)
- Always show instance configuration link. !26783 (Bastian Blank)
- Display maximum artifact size from runtime config. !26784 (Bastian Blank)
- Resolve issue where list labels did not have the correct text color on creation. !26794 (Tucker Chapman)
- Set release name when adding release notes to an existing tag. !26807
- Fix the bug that the project statistics is not updated. !26854 (Hiroyuki Sato)
- Client side changes for ListLastCommitsForTree response update. !26880
- Fix api group visibility. !26896
- Require all templates to use default stages. !26954
- Remove a "reopen merge request button" on a "merged" merge request. !26965 (Hiroyuki Sato)
- Fix misaligned image diff swipe view. !26969 (ftab)
- Add badge-pill class on group member count. !27019
- Remove leading / trailing spaces from heading when generating header ids. !27025 (Willian Balmant)
- Respect updated_at attribute in notes produced by API calls. !27124 (Ben Gamari)
- Fix GitHub project import visibility. !27133 (Daniel Wyatt)
- Fixes actions dropdowns in environments page. !27160
- Fixes create button background for Environments form. !27161
- Display scoped labels in Issue Boards. !27164
- Align UrlValidator to validate_url gem implementation. !27194 (Horatiu Eugen Vlad)
- Resolve Web IDE template dropdown showing duplicates. !27237
- Update GitLab Workhorse to v8.6.0. !27260
- Only show in autocomplete when author active. !27292
- Remove deadline for Git fsck. !27299
- Show prioritized labels to guests. !27307
- Properly expire all pipeline caches when pipeline is deleted. !27334
- Replaced icon for external URL with doc-text icon. !27365
- Add auto direction for issue title. !27378 (Ahmad Haghighi)
- fix wiki search result links in titles. !27400 (khm)
- Fix system notes timestamp when creating issue in the past. !27406
- Fix approvals sometimes being reset after a merge request is rebased. !27446
- Fix empty block in MR widget when user doesn't have permission. !27462
- Fix wrong use of ActiveRecord in PoolRepository. !27464
- Show proper preview for uploaded images in Web IDE. !27471
- Resolve Renaming an image via Web IDE corrupts it. !27486
- Clean up CarrierWave's import/export files. !27487
- Fix autocomplete dropdown for usernames starting with period. !27533 (Jan Beckmann)
- Disable password autocomplete in mirror repository form. !27542
- Always use internal ID tables in development and production. !27544
- Only show the "target branch has advanced" message when the merge request is open. !27588
- Resolve Misalignment on suggested changes diff table. !27612
- Update Workhorse to v8.7.0. !27630
- Fix FE API and IDE handling of '/' relative_url_root. !27635
- Hide ScopedBadge overflow notes. !27651
- Fix base domain help text update. !27746
- Upgrade letter_opener_web to support Rails 5.1. !27829
- Fix webpack assets handling when relative url root is '/'. !27909
- Fix IDE get file data with '/' as relative root. !27911
- Allow a member to have an access level equal to parent group. !27913
- Fix issuables state_id nil when importing projects from GitHub. !28027
- Fix uploading of LFS tracked file through UI. !28052
- Render Next badge only for gitlab.com. !28056
- Fix update head pipeline process of Pipelines for merge requests. !28057
- Fix visual issues in set status modal. !28147
- Use a path for the related merge requests endpoint. !28171
- disable SSH key validation in key details view. !28180 (Roger Meier)
- Fix MR discussion border missing in chrome sometimes. !28185
- Fix Error 500 when inviting user already present. !28198
- Remove non-semantic use of `.row` in member listing controls. !28204
- Properly handle LFS Batch API response in project import. !28223
- Fix project visibility level validation. !28305 (Peter Marko)
- Fix incorrect prefix used in new uploads for personal snippets. !28337
- Fix Rugged get_tree_entries recursive flag not working. !28494
- Fixes next badge being always visible.
- Next badge must visible when canary flag is true.
- Adds arrow icons to select option in CI/CD settings.
- Vertically aligns the play button for stages.
- Allow replying to individual notes from API.
### Changed (19 changes, 3 of them are from the community)
- Sort by due date and popularity in both directions for Issues and Merge requests. !25502 (Nermin Vehabovic)
- Improve pipelines table spacing, add triggerer column. !26136
- Allow extra arguments in helm commands when deploying the application in Auto-DevOps.gitlab-ci.yml. !26171 (tortuetorche)
- Switch to sassc-rails for faster stylesheet compilation. !26224
- Reorganize project merge request settings. !26834
- Display a toast message when the Kubernetes runner has successfully upgraded. !27206
- Allow guests users to access project releases. !27247
- Add help texts to K8 form fields. !27274
- Support prometheus for group level clusters. !27280
- Include link to raw job log in plain-text emails. !27409
- Only escape Markdown emphasis characters in autocomplete when necessary. !27457
- Move location of charts/auto-deploy-app -> gitlab-org/charts/auto-deploy-app. !27477
- Make canceled jobs not retryable. !27503
- Upgrade to Gitaly v1.36.0. !27831
- Update deployment event chat notification message. !27972
- Upgrade to Gitaly v1.42.0. !28135
- Resolve discussion when apply suggestion. !28160
- Improve expanding diff to full file performance.
- Knative version bump 0.3 -> 0.5. (Chris Baumbauer <cab@cabnetworks.net>)
### Performance (5 changes)
- Added list_pages method to avoid loading all wiki pages content. !22801
- Add gitaly session id & catfile-cache feature flag. !27472
- Add improvements to global search of issues and merge requests. !27817
- Disable method replacement in avatar loading. !27866
- Fix Blob.lazy always loading all previously-requested blobs when a new request is made.
### Added (36 changes, 10 of them are from the community)
- Add time preferences for user. !25381
- Added write_repository scope for personal access token. !26021 (Horatiu Eugen Vlad)
- Mark disabled pages domains for removal, but don't remove them yet. !26212
- Remove pages domains if they weren't verified for 1 week. !26227
- Expose pipeline variables via API. !26501 (Agustin Henze <tin@redhat.com>)
- Download a folder from repository. !26532 (kiameisomabes)
- Remove cleaned up OIDs from database and cache. !26555
- Disables kubernetes resources creation if a cluster is not managed. !26565
- Add CI_COMMIT_REF_PROTECTED CI variable. !26716 (Jason van den Hurk)
- Add new API endpoint to expose a single environment. !26887
- Allow Sentry configuration to be passed on gitlab.yml. !27091 (Roger Meier)
- CI variables of type file. !27112
- Allow linking to a private helm repository by providing credentials, and customisation of repository name. !27123 (Stuart Moore @stjm-cc)
- Add time tracking information to Issue Boards sidebar. !27166
- Play all manual jobs in a stage. !27188
- Instance level kubernetes clusters. !27196
- Adds if InfluxDB and Prometheus metrics are enabled to usage ping data. !27238
- Autosave description in epics. !27296
- Add deployment events to chat notification services. !27338
- Add packages_size to ProjectStatistics. !27373
- Added OmniAuth OpenID Connect strategy. !27383 (Horatiu Eugen Vlad)
- Test using Git 2.21. !27418
- Use official Gitea logo in importer. !27424 (Matti Ranta (@techknowlogick))
- Add option to set access_level of runners upon registration. !27490 (Zelin L)
- Add initial GraphQL query for Groups. !27492
- Enable Sidekiq Reliable Fetcher for background jobs by default. !27530
- Add backend support for a External Dashboard URL setting. !27550
- Implement UI for uninstalling Clusters managed apps. !27559
- Resolve Salesforce.com omniauth support. !27834
- Leave project/group from access granted email. !27892
- Allow Sentry client-side DSN to be passed on gitlab.yml. !27967
- GraphQL: improve evaluation of query complexity based on arguments and query limits. !28017
- Adds badge for Canary environment and help link.
- Support negative matches.
- Show category icons in user popover.
- Added Omniauth UltraAuth strategy to GitLab. (Kartikey Tanna)
### Other (29 changes, 8 of them are from the community)
- Validate refs used in controllers don't have spaces. !24037
- Migrate correlation and tracing code to LabKit. !25379
- Update node.js to 10.15.3 in CI template for Hexo. !25943 (Takuya Noguchi)
- Improve icons and button order in project overview. !26796
- Add instructions on how to contribute a Built-In template for project. !26976
- Extract DiscussionNotes component from NoteableDiscussion. !27066
- Bump gRPC to 1.19.0 and protobuf to 3.7.1. !27086
- Extract DiscussionActions component from NoteableDiscussion. !27227
- Show disabled project repo mirrors in settings. !27326
- Add backtrace to Gitaly performance bar. !27345
- Moved EE/CE differences for dropdown_value_collapsed into CE. !27367
- Remove "You are already signed in" banner. !27377
- Move ee-specific code from boards/components/issue_card_inner.vue. !27394 (Roman Rodionov)
- Upgrade to Rails 5.1. !27480 (Jasper Maes)
- Update GitLab Runner Helm Chart to 0.4.0. !27508
- Update GitLab Runner Helm Chart to 0.4.1. !27627
- Refactored notes tests from Karma to Jest. !27648 (Martin Hobert)
- refactor(issue): Refactored issue tests from Karma to Jest. !27673 (Martin Hobert)
- Refactored Karma spec files to Jest. !27688 (Martin Hobert)
- Add CSS fix for <wbr> elements on IE11. !27846
- Update clair-local-scan to v2.0.8 for container scanning. !27977
- Use PostgreSQL 10.7 in tests. !28020
- Document EE License Auto Import During Install. !28106
- Remove the note in the docs that multi-line suggestions are not yet available. !28119 (hardysim)
- Update gitlab-shell to v9.1.0. !28184
- Add EE fixtures to SeedFu list. !28241
- Replaces CSS with BS4 utility class for pipeline schedules.
- Creates a vendors folder for external CSS.
- Add some frozen string to spec/**/*.rb. (gfyoung)
## 11.10.4 (2019-05-01) ## 11.10.4 (2019-05-01)
### Fixed (12 changes) ### Fixed (12 changes)
@ -358,6 +568,44 @@ entry.
- Removes EE differences for environment_item.vue. - Removes EE differences for environment_item.vue.
## 11.9.10 (2019-04-26)
### Security (5 changes)
- Loosen regex for exception sanitization. !3077
- Resolve: moving an issue to private repo leaks namespace and project name.
- Escape path in new merge request mail.
- Stop sending emails to users who can't read commit.
- Upgrade Rails to 5.0.7.2.
## 11.9.9 (2019-04-23)
### Performance (1 change)
- Bring back Rugged implementation of ListCommitsByOid. !27441
## 11.9.8 (2019-04-11)
### Deprecated (1 change)
- Allow to use untrusted Regexp via feature flag. !26905
### Performance (2 changes)
- Improve performance of PR import. !27121
- Disable method instrumentation for diffs. !27235
### Other (1 change)
- Restore HipChat project service. !27172
## 11.9.7 (2019-04-09)
- No changes.
## 11.9.6 (2019-04-04) ## 11.9.6 (2019-04-04)
### Fixed (3 changes) ### Fixed (3 changes)
@ -689,6 +937,35 @@ entry.
- Removes EE differences for jobs/getters.js. - Removes EE differences for jobs/getters.js.
## 11.8.10 (2019-04-30)
### Security (1 change)
- Allow to see project events only with api scope token.
## 11.8.8 (2019-04-23)
### Fixed (5 changes)
- Bring back Rugged implementation of find_commit. !25477
- Fix bug in BitBucket imports with SHA shorter than 40 chars. !26050
- Fix health checks not working behind load balancers. !26055
- Fix error creating a merge request when diff includes a null byte. !26190
- Avoid excessive recursive calls with Rugged TreeEntries. !26813
### Performance (1 change)
- Bring back Rugged implementation of ListCommitsByOid. !27441
### Other (4 changes)
- Bring back Rugged implementation of GetTreeEntries. !25674
- Bring back Rugged implementation of CommitIsAncestor. !25702
- Bring back Rugged implementation of TreeEntry. !25706
- Bring back Rugged implementation of commit_tree_entry. !25896
## 11.8.3 (2019-03-19) ## 11.8.3 (2019-03-19)
### Security (1 change) ### Security (1 change)
@ -958,6 +1235,29 @@ entry.
- Creates mixin to reduce code duplication between CE and EE in graph component. - Creates mixin to reduce code duplication between CE and EE in graph component.
## 11.7.12 (2019-04-23)
### Fixed (2 changes)
- Bring back Rugged implementation of find_commit. !25477
- Avoid excessive recursive calls with Rugged TreeEntries. !26813
### Performance (1 change)
- Bring back Rugged implementation of ListCommitsByOid. !27441
### Other (4 changes)
- Bring back Rugged implementation of GetTreeEntries. !25674
- Bring back Rugged implementation of CommitIsAncestor. !25702
- Bring back Rugged implementation of TreeEntry. !25706
- Bring back Rugged implementation of commit_tree_entry. !25896
## 11.7.11 (2019-04-09)
- No changes.
## 11.7.10 (2019-03-28) ## 11.7.10 (2019-03-28)
### Security (7 changes) ### Security (7 changes)
@ -1229,6 +1529,30 @@ entry.
- Update url placeholder for the sentry configuration page. !24338 - Update url placeholder for the sentry configuration page. !24338
## 11.6.11 (2019-04-23)
### Security (2 changes)
- Fixed ability to see private groups by users not belonging to given group.
- Fix XSS in resolve conflicts form.
### Fixed (2 changes)
- Bring back Rugged implementation of find_commit. !25477
- Avoid excessive recursive calls with Rugged TreeEntries. !26813
### Performance (1 change)
- Bring back Rugged implementation of ListCommitsByOid. !27441
### Other (4 changes)
- Bring back Rugged implementation of GetTreeEntries. !25674
- Bring back Rugged implementation of CommitIsAncestor. !25702
- Bring back Rugged implementation of TreeEntry. !25706
- Bring back Rugged implementation of commit_tree_entry. !25896
## 11.6.10 (2019-02-28) ## 11.6.10 (2019-02-28)
### Security (21 changes) ### Security (21 changes)
@ -1600,6 +1924,25 @@ entry.
- Enable Rubocop on lib/gitlab. (gfyoung) - Enable Rubocop on lib/gitlab. (gfyoung)
## 11.5.11 (2019-04-23)
### Fixed (2 changes)
- Bring back Rugged implementation of find_commit. !25477
- Avoid excessive recursive calls with Rugged TreeEntries. !26813
### Performance (1 change)
- Bring back Rugged implementation of ListCommitsByOid. !27441
### Other (4 changes)
- Bring back Rugged implementation of GetTreeEntries. !25674
- Bring back Rugged implementation of CommitIsAncestor. !25702
- Bring back Rugged implementation of TreeEntry. !25706
- Bring back Rugged implementation of commit_tree_entry. !25896
## 11.5.8 (2019-01-28) ## 11.5.8 (2019-01-28)
### Security (21 changes) ### Security (21 changes)

View file

@ -1,3 +1,4 @@
# frozen_string_literal: true
danger.import_plugin('danger/plugins/helper.rb') danger.import_plugin('danger/plugins/helper.rb')
unless helper.release_automation? unless helper.release_automation?
@ -16,4 +17,5 @@ unless helper.release_automation?
danger.import_dangerfile(path: 'danger/roulette') danger.import_dangerfile(path: 'danger/roulette')
danger.import_dangerfile(path: 'danger/single_codebase') danger.import_dangerfile(path: 'danger/single_codebase')
danger.import_dangerfile(path: 'danger/gitlab_ui_wg') danger.import_dangerfile(path: 'danger/gitlab_ui_wg')
danger.import_dangerfile(path: 'danger/ce_ee_vue_templates')
end end

View file

@ -1 +1 @@
1.34.3 1.42.5

View file

@ -1 +1 @@
9.0.0 9.1.0

View file

@ -1 +1 @@
8.5.2 8.7.0

50
Gemfile
View file

@ -1,7 +1,6 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'rails', '5.0.7.2' gem 'rails', '5.1.7'
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Improves copy-on-write performance for MRI # Improves copy-on-write performance for MRI
gem 'nakayoshi_fork', '~> 0.0.4' gem 'nakayoshi_fork', '~> 0.0.4'
@ -19,7 +18,7 @@ gem 'mysql2', '~> 0.4.10', group: :mysql
gem 'pg', '~> 1.1', group: :postgres gem 'pg', '~> 1.1', group: :postgres
gem 'rugged', '~> 0.28' gem 'rugged', '~> 0.28'
gem 'grape-path-helpers', '~> 1.0' gem 'grape-path-helpers', '~> 1.1'
gem 'faraday', '~> 0.12' gem 'faraday', '~> 0.12'
@ -42,6 +41,9 @@ gem 'omniauth-shibboleth', '~> 1.3.0'
gem 'omniauth-twitter', '~> 1.4' gem 'omniauth-twitter', '~> 1.4'
gem 'omniauth_crowd', '~> 2.2.0' gem 'omniauth_crowd', '~> 2.2.0'
gem 'omniauth-authentiq', '~> 0.3.3' gem 'omniauth-authentiq', '~> 0.3.3'
gem 'omniauth_openid_connect', '~> 0.3.0'
gem "omniauth-ultraauth", '~> 0.0.2'
gem 'omniauth-salesforce', '~> 1.0.5'
gem 'rack-oauth2', '~> 1.9.3' gem 'rack-oauth2', '~> 1.9.3'
gem 'jwt', '~> 2.1.0' gem 'jwt', '~> 2.1.0'
@ -79,6 +81,7 @@ gem 'rack-cors', '~> 1.0.0', require: 'rack/cors'
# GraphQL API # GraphQL API
gem 'graphql', '~> 1.8.0' gem 'graphql', '~> 1.8.0'
gem 'graphiql-rails', '~> 1.4.10' gem 'graphiql-rails', '~> 1.4.10'
gem 'apollo_upload_server', '~> 2.0.0.beta3'
# Disable strong_params so that Mash does not respond to :permitted? # Disable strong_params so that Mash does not respond to :permitted?
gem 'hashie-forbidden_attributes' gem 'hashie-forbidden_attributes'
@ -129,7 +132,7 @@ gem 'asciidoctor-plantuml', '0.0.8'
gem 'rouge', '~> 3.1' gem 'rouge', '~> 3.1'
gem 'truncato', '~> 0.7.11' gem 'truncato', '~> 0.7.11'
gem 'bootstrap_form', '~> 4.2.0' gem 'bootstrap_form', '~> 4.2.0'
gem 'nokogiri', '~> 1.10.1' gem 'nokogiri', '~> 1.10.3'
gem 'escape_utils', '~> 1.1' gem 'escape_utils', '~> 1.1'
# Calendar rendering # Calendar rendering
@ -158,7 +161,7 @@ gem 'state_machines-activerecord', '~> 0.5.1'
gem 'acts-as-taggable-on', '~> 6.0' gem 'acts-as-taggable-on', '~> 6.0'
# Background jobs # Background jobs
gem 'sidekiq', '~> 5.2.1' gem 'sidekiq', '~> 5.2.7'
gem 'sidekiq-cron', '~> 1.0' gem 'sidekiq-cron', '~> 1.0'
gem 'redis-namespace', '~> 1.6.0' gem 'redis-namespace', '~> 1.6.0'
gem 'gitlab-sidekiq-fetcher', '~> 0.4.0', require: 'sidekiq-reliable-fetch' gem 'gitlab-sidekiq-fetcher', '~> 0.4.0', require: 'sidekiq-reliable-fetch'
@ -257,8 +260,7 @@ gem 'chronic_duration', '~> 0.10.6'
gem 'webpack-rails', '~> 0.9.10' gem 'webpack-rails', '~> 0.9.10'
gem 'rack-proxy', '~> 0.6.0' gem 'rack-proxy', '~> 0.6.0'
gem 'sass-rails', '~> 5.0.6' gem 'sassc-rails', '~> 2.1.0'
gem 'sass', '~> 3.5'
gem 'uglifier', '~> 2.7.2' gem 'uglifier', '~> 2.7.2'
gem 'addressable', '~> 2.5.2' gem 'addressable', '~> 2.5.2'
@ -274,6 +276,9 @@ gem 'sentry-raven', '~> 2.7'
gem 'premailer-rails', '~> 1.9.7' gem 'premailer-rails', '~> 1.9.7'
# LabKit: Tracing and Correlation
gem 'gitlab-labkit', '~> 0.2.0'
# I18n # I18n
gem 'ruby_parser', '~> 3.8', require: false gem 'ruby_parser', '~> 3.8', require: false
gem 'rails-i18n', '~> 5.1' gem 'rails-i18n', '~> 5.1'
@ -281,7 +286,7 @@ gem 'gettext_i18n_rails', '~> 1.8.0'
gem 'gettext_i18n_rails_js', '~> 1.3' gem 'gettext_i18n_rails_js', '~> 1.3'
gem 'gettext', '~> 3.2.2', require: false, group: :development gem 'gettext', '~> 3.2.2', require: false, group: :development
gem 'batch-loader', '~> 1.2.2' gem 'batch-loader', '~> 1.4.0'
# Perf bar # Perf bar
gem 'peek', '~> 1.0.1' gem 'peek', '~> 1.0.1'
@ -301,17 +306,11 @@ group :metrics do
gem 'raindrops', '~> 0.18' gem 'raindrops', '~> 0.18'
end end
group :tracing do
# OpenTracing
gem 'opentracing', '~> 0.4.3'
gem 'jaeger-client', '~> 0.10.0'
end
group :development do group :development do
gem 'foreman', '~> 0.84.0' gem 'foreman', '~> 0.84.0'
gem 'brakeman', '~> 4.2', require: false gem 'brakeman', '~> 4.2', require: false
gem 'letter_opener_web', '~> 1.3.0' gem 'letter_opener_web', '~> 1.3.4'
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
# Better errors handler # Better errors handler
@ -334,7 +333,7 @@ group :development, :test do
gem 'database_cleaner', '~> 1.7.0' gem 'database_cleaner', '~> 1.7.0'
gem 'factory_bot_rails', '~> 4.8.2' gem 'factory_bot_rails', '~> 4.8.2'
gem 'rspec-rails', '~> 3.7.0' gem 'rspec-rails', '~> 3.7.0'
gem 'rspec-retry', '~> 0.4.5' gem 'rspec-retry', '~> 0.6.1'
gem 'rspec_profiling', '~> 0.0.5' gem 'rspec_profiling', '~> 0.0.5'
gem 'rspec-set', '~> 0.1.3' gem 'rspec-set', '~> 0.1.3'
gem 'rspec-parameterized', require: false gem 'rspec-parameterized', require: false
@ -345,20 +344,21 @@ group :development, :test do
# Generate Fake data # Generate Fake data
gem 'ffaker', '~> 2.10' gem 'ffaker', '~> 2.10'
gem 'capybara', '~> 2.16.1' gem 'capybara', '~> 2.18.0'
gem 'capybara-screenshot', '~> 1.0.18' gem 'capybara-screenshot', '~> 1.0.22'
gem 'selenium-webdriver', '~> 3.12' gem 'selenium-webdriver', '~> 3.141'
gem 'spring', '~> 2.0.0' gem 'spring', '~> 2.0.0'
gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-rspec', '~> 1.0.4'
gem 'gitlab-styles', '~> 2.4', require: false gem 'gitlab-styles', '~> 2.6', require: false
# Pin these dependencies, otherwise a new rule could break the CI pipelines # Pin these dependencies, otherwise a new rule could break the CI pipelines
gem 'rubocop', '~> 0.54.0' gem 'rubocop', '~> 0.68.1'
gem 'rubocop-performance', '~> 1.1.0'
gem 'rubocop-rspec', '~> 1.22.1' gem 'rubocop-rspec', '~> 1.22.1'
gem 'scss_lint', '~> 0.56.0', require: false gem 'scss_lint', '~> 0.56.0', require: false
gem 'haml_lint', '~> 0.28.0', require: false gem 'haml_lint', '~> 0.30.0', require: false
gem 'simplecov', '~> 0.14.0', require: false gem 'simplecov', '~> 0.14.0', require: false
gem 'bundler-audit', '~> 0.5.0', require: false gem 'bundler-audit', '~> 0.5.0', require: false
@ -419,11 +419,11 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 1.22.1', require: 'gitaly' gem 'gitaly-proto', '~> 1.27.2', require: 'gitaly'
gem 'grpc', '~> 1.15.0' gem 'grpc', '~> 1.19.0'
gem 'google-protobuf', '~> 3.6' gem 'google-protobuf', '~> 3.7.1'
gem 'toml-rb', '~> 1.0.0', require: false gem 'toml-rb', '~> 1.0.0', require: false

View file

@ -4,41 +4,41 @@ GEM
RedCloth (4.3.2) RedCloth (4.3.2)
abstract_type (0.0.7) abstract_type (0.0.7)
ace-rails-ap (4.1.2) ace-rails-ap (4.1.2)
actioncable (5.0.7.2) actioncable (5.1.7)
actionpack (= 5.0.7.2) actionpack (= 5.1.7)
nio4r (>= 1.2, < 3.0) nio4r (~> 2.0)
websocket-driver (~> 0.6.1) websocket-driver (~> 0.6.1)
actionmailer (5.0.7.2) actionmailer (5.1.7)
actionpack (= 5.0.7.2) actionpack (= 5.1.7)
actionview (= 5.0.7.2) actionview (= 5.1.7)
activejob (= 5.0.7.2) activejob (= 5.1.7)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
actionpack (5.0.7.2) actionpack (5.1.7)
actionview (= 5.0.7.2) actionview (= 5.1.7)
activesupport (= 5.0.7.2) activesupport (= 5.1.7)
rack (~> 2.0) rack (~> 2.0)
rack-test (~> 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.0.7.2) actionview (5.1.7)
activesupport (= 5.0.7.2) activesupport (= 5.1.7)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3) rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.0.7.2) activejob (5.1.7)
activesupport (= 5.0.7.2) activesupport (= 5.1.7)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (5.0.7.2) activemodel (5.1.7)
activesupport (= 5.0.7.2) activesupport (= 5.1.7)
activerecord (5.0.7.2) activerecord (5.1.7)
activemodel (= 5.0.7.2) activemodel (= 5.1.7)
activesupport (= 5.0.7.2) activesupport (= 5.1.7)
arel (~> 7.0) arel (~> 8.0)
activerecord_sane_schema_dumper (1.0) activerecord_sane_schema_dumper (1.0)
rails (>= 5, < 6) rails (>= 5, < 6)
activesupport (5.0.7.2) activesupport (5.1.7)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
minitest (~> 5.1) minitest (~> 5.1)
@ -52,7 +52,10 @@ GEM
public_suffix (>= 2.0.2, < 4.0) public_suffix (>= 2.0.2, < 4.0)
aes_key_wrap (1.0.1) aes_key_wrap (1.0.1)
akismet (2.0.0) akismet (2.0.0)
arel (7.1.4) apollo_upload_server (2.0.0.beta.3)
graphql (>= 1.8)
rails (>= 4.2)
arel (8.0.0)
asana (0.8.1) asana (0.8.1)
faraday (~> 0.9) faraday (~> 0.9)
faraday_middleware (~> 0.9) faraday_middleware (~> 0.9)
@ -73,7 +76,7 @@ GEM
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
babosa (1.0.2) babosa (1.0.2)
base32 (0.3.2) base32 (0.3.2)
batch-loader (1.2.2) batch-loader (1.4.0)
bcrypt (3.1.12) bcrypt (3.1.12)
bcrypt_pbkdf (1.0.0) bcrypt_pbkdf (1.0.0)
benchmark-ips (2.3.0) benchmark-ips (2.3.0)
@ -100,13 +103,13 @@ GEM
bundler (~> 1.2) bundler (~> 1.2)
thor (~> 0.18) thor (~> 0.18)
byebug (9.1.0) byebug (9.1.0)
capybara (2.16.1) capybara (2.18.0)
addressable addressable
mini_mime (>= 0.1.3) mini_mime (>= 0.1.3)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-test (>= 0.5.4) rack-test (>= 0.5.4)
xpath (~> 2.0) xpath (>= 2.0, < 4.0)
capybara-screenshot (1.0.22) capybara-screenshot (1.0.22)
capybara (>= 1.0, < 4) capybara (>= 1.0, < 4)
launchy launchy
@ -185,8 +188,7 @@ GEM
mail (~> 2.7) mail (~> 2.7)
encryptor (3.0.0) encryptor (3.0.0)
equalizer (0.0.11) equalizer (0.0.11)
erubi (1.7.1) erubi (1.8.0)
erubis (2.7.0)
escape_utils (1.2.1) escape_utils (1.2.1)
et-orbi (1.1.7) et-orbi (1.1.7)
tzinfo tzinfo
@ -257,8 +259,8 @@ GEM
fog-xml (0.1.3) fog-xml (0.1.3)
fog-core fog-core
nokogiri (>= 1.5.11, < 2.0.0) nokogiri (>= 1.5.11, < 2.0.0)
font-awesome-rails (4.7.0.1) font-awesome-rails (4.7.0.4)
railties (>= 3.2, < 5.1) railties (>= 3.2, < 6.0)
foreman (0.84.0) foreman (0.84.0)
thor (~> 0.19.1) thor (~> 0.19.1)
formatador (0.2.5) formatador (0.2.5)
@ -281,17 +283,24 @@ GEM
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gitaly-proto (1.22.1) gitaly-proto (1.27.2)
grpc (~> 1.0) grpc (~> 1.0)
github-markup (1.7.0) github-markup (1.7.0)
gitlab-default_value_for (3.1.1) gitlab-default_value_for (3.1.1)
activerecord (>= 3.2.0, < 6.0) activerecord (>= 3.2.0, < 6.0)
gitlab-labkit (0.2.0)
actionpack (~> 5)
activesupport (~> 5)
grpc (~> 1.15)
jaeger-client (~> 0.10)
opentracing (~> 0.4)
gitlab-markup (1.7.0) gitlab-markup (1.7.0)
gitlab-sidekiq-fetcher (0.4.0) gitlab-sidekiq-fetcher (0.4.0)
sidekiq (~> 5) sidekiq (~> 5)
gitlab-styles (2.5.1) gitlab-styles (2.6.2)
rubocop (~> 0.54.0) rubocop (~> 0.68.1)
rubocop-gitlab-security (~> 0.1.0) rubocop-gitlab-security (~> 0.1.0)
rubocop-performance (~> 1.1.0)
rubocop-rspec (~> 1.19) rubocop-rspec (~> 1.19)
gitlab_omniauth-ldap (2.1.1) gitlab_omniauth-ldap (2.1.1)
net-ldap (~> 0.16) net-ldap (~> 0.16)
@ -311,8 +320,8 @@ GEM
mime-types (~> 3.0) mime-types (~> 3.0)
representable (~> 3.0) representable (~> 3.0)
retriable (>= 2.0, < 4.0) retriable (>= 2.0, < 4.0)
google-protobuf (3.6.1) google-protobuf (3.7.1)
googleapis-common-protos-types (1.0.3) googleapis-common-protos-types (1.0.4)
google-protobuf (~> 3.0) google-protobuf (~> 3.0)
googleauth (0.6.6) googleauth (0.6.6)
faraday (~> 0.12) faraday (~> 0.12)
@ -333,8 +342,8 @@ GEM
grape-entity (0.7.1) grape-entity (0.7.1)
activesupport (>= 4.0) activesupport (>= 4.0)
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
grape-path-helpers (1.0.6) grape-path-helpers (1.1.0)
activesupport (>= 4, < 5.1) activesupport
grape (~> 1.0) grape (~> 1.0)
rake (~> 12) rake (~> 12)
grape_logging (1.7.0) grape_logging (1.7.0)
@ -343,13 +352,13 @@ GEM
railties railties
sprockets-rails sprockets-rails
graphql (1.8.1) graphql (1.8.1)
grpc (1.15.0) grpc (1.19.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
googleapis-common-protos-types (~> 1.0.0) googleapis-common-protos-types (~> 1.0.0)
haml (5.0.4) haml (5.0.4)
temple (>= 0.8.0) temple (>= 0.8.0)
tilt tilt
haml_lint (0.28.0) haml_lint (0.30.0)
haml (>= 4.0, < 5.1) haml (>= 4.0, < 5.1)
rainbow rainbow
rake (>= 10, < 13) rake (>= 10, < 13)
@ -399,6 +408,7 @@ GEM
jaeger-client (0.10.0) jaeger-client (0.10.0)
opentracing (~> 0.3) opentracing (~> 0.3)
thrift thrift
jaro_winkler (1.5.2)
jira-ruby (1.4.1) jira-ruby (1.4.1)
activesupport activesupport
multipart-post multipart-post
@ -436,9 +446,9 @@ GEM
rest-client (~> 2.0) rest-client (~> 2.0)
launchy (2.4.3) launchy (2.4.3)
addressable (~> 2.3) addressable (~> 2.3)
letter_opener (1.4.1) letter_opener (1.7.0)
launchy (~> 2.2) launchy (~> 2.2)
letter_opener_web (1.3.0) letter_opener_web (1.3.4)
actionmailer (>= 3.2) actionmailer (>= 3.2)
letter_opener (~> 1.0) letter_opener (~> 1.0)
railties (>= 3.2) railties (>= 3.2)
@ -488,7 +498,7 @@ GEM
net-ssh (5.0.1) net-ssh (5.0.1)
netrc (0.11.0) netrc (0.11.0)
nio4r (2.3.1) nio4r (2.3.1)
nokogiri (1.10.1) nokogiri (1.10.3)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
nokogumbo (1.5.0) nokogumbo (1.5.0)
nokogiri nokogiri
@ -543,6 +553,9 @@ GEM
omniauth (~> 1.9) omniauth (~> 1.9)
omniauth-oauth2-generic (0.2.2) omniauth-oauth2-generic (0.2.2)
omniauth-oauth2 (~> 1.0) omniauth-oauth2 (~> 1.0)
omniauth-salesforce (1.0.5)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.0)
omniauth-saml (1.10.0) omniauth-saml (1.10.0)
omniauth (~> 1.3, >= 1.3.2) omniauth (~> 1.3, >= 1.3.2)
ruby-saml (~> 1.7) ruby-saml (~> 1.7)
@ -551,17 +564,33 @@ GEM
omniauth-twitter (1.4.0) omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1) omniauth-oauth (~> 1.1)
rack rack
omniauth-ultraauth (0.0.2)
omniauth_openid_connect (~> 0.3.0)
omniauth_crowd (2.2.3) omniauth_crowd (2.2.3)
activesupport activesupport
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
omniauth (~> 1.0) omniauth (~> 1.0)
opentracing (0.4.3) omniauth_openid_connect (0.3.0)
addressable (~> 2.5)
omniauth (~> 1.3)
openid_connect (~> 1.1)
openid_connect (1.1.6)
activemodel
attr_required (>= 1.0.0)
json-jwt (>= 1.5.0)
rack-oauth2 (>= 1.6.1)
swd (>= 1.0.0)
tzinfo
validate_email
validate_url
webfinger (>= 1.0.1)
opentracing (0.5.0)
optimist (3.0.0) optimist (3.0.0)
org-ruby (0.9.12) org-ruby (0.9.12)
rubypants (~> 0.2) rubypants (~> 0.2)
orm_adapter (0.5.0) orm_adapter (0.5.0)
os (1.0.0) os (1.0.0)
parallel (1.12.1) parallel (1.17.0)
parser (2.5.3.0) parser (2.5.3.0)
ast (~> 2.4.0) ast (~> 2.4.0)
parslet (1.8.2) parslet (1.8.2)
@ -591,7 +620,6 @@ GEM
pg (1.1.4) pg (1.1.4)
po_to_json (1.0.1) po_to_json (1.0.1)
json (>= 1.6.0) json (>= 1.6.0)
powerpack (0.1.1)
premailer (1.10.4) premailer (1.10.4)
addressable addressable
css_parser (>= 1.4.10) css_parser (>= 1.4.10)
@ -636,26 +664,24 @@ GEM
rack rack
rack-proxy (0.6.0) rack-proxy (0.6.0)
rack rack
rack-test (0.6.3) rack-test (1.1.0)
rack (>= 1.0) rack (>= 1.0, < 3)
rails (5.0.7.2) rails (5.1.7)
actioncable (= 5.0.7.2) actioncable (= 5.1.7)
actionmailer (= 5.0.7.2) actionmailer (= 5.1.7)
actionpack (= 5.0.7.2) actionpack (= 5.1.7)
actionview (= 5.0.7.2) actionview (= 5.1.7)
activejob (= 5.0.7.2) activejob (= 5.1.7)
activemodel (= 5.0.7.2) activemodel (= 5.1.7)
activerecord (= 5.0.7.2) activerecord (= 5.1.7)
activesupport (= 5.0.7.2) activesupport (= 5.1.7)
bundler (>= 1.3.0) bundler (>= 1.3.0)
railties (= 5.0.7.2) railties (= 5.1.7)
sprockets-rails (>= 2.0.0) sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.2) rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1) actionpack (~> 5.x, >= 5.0.1)
actionview (~> 5.x, >= 5.0.1) actionview (~> 5.x, >= 5.0.1)
activesupport (~> 5.x) activesupport (~> 5.x)
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
rails-dom-testing (2.0.3) rails-dom-testing (2.0.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
nokogiri (>= 1.6) nokogiri (>= 1.6)
@ -664,9 +690,9 @@ GEM
rails-i18n (5.1.1) rails-i18n (5.1.1)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
railties (>= 5.0, < 6) railties (>= 5.0, < 6)
railties (5.0.7.2) railties (5.1.7)
actionpack (= 5.0.7.2) actionpack (= 5.1.7)
activesupport (= 5.0.7.2) activesupport (= 5.1.7)
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
@ -706,7 +732,7 @@ GEM
redis-store (>= 1.2, < 2) redis-store (>= 1.2, < 2)
redis-store (1.6.0) redis-store (1.6.0)
redis (>= 2.2, < 5) redis (>= 2.2, < 5)
regexp_parser (1.3.0) regexp_parser (1.4.0)
regexp_property_values (0.3.4) regexp_property_values (0.3.4)
representable (3.0.4) representable (3.0.4)
declarative (< 0.1.0) declarative (< 0.1.0)
@ -754,8 +780,8 @@ GEM
rspec-expectations (~> 3.7.0) rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0) rspec-mocks (~> 3.7.0)
rspec-support (~> 3.7.0) rspec-support (~> 3.7.0)
rspec-retry (0.4.5) rspec-retry (0.6.1)
rspec-core rspec-core (> 3.3)
rspec-set (0.1.3) rspec-set (0.1.3)
rspec-support (3.7.1) rspec-support (3.7.1)
rspec_junit_formatter (0.4.1) rspec_junit_formatter (0.4.1)
@ -765,15 +791,17 @@ GEM
pg pg
rails rails
sqlite3 sqlite3
rubocop (0.54.0) rubocop (0.68.1)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 2.5) parser (>= 2.5, != 2.5.1.1)
powerpack (~> 0.1)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1) unicode-display_width (>= 1.4.0, < 1.6)
rubocop-gitlab-security (0.1.1) rubocop-gitlab-security (0.1.1)
rubocop (>= 0.51) rubocop (>= 0.51)
rubocop-performance (1.1.0)
rubocop (>= 0.67.0)
rubocop-rspec (1.22.2) rubocop-rspec (1.22.2)
rubocop (>= 0.52.1) rubocop (>= 0.52.1)
ruby-enum (0.7.2) ruby-enum (0.7.2)
@ -781,7 +809,7 @@ GEM
ruby-fogbugz (0.2.1) ruby-fogbugz (0.2.1)
crack (~> 0.4) crack (~> 0.4)
ruby-prof (0.17.0) ruby-prof (0.17.0)
ruby-progressbar (1.9.0) ruby-progressbar (1.10.0)
ruby-saml (1.7.2) ruby-saml (1.7.2)
nokogiri (>= 1.5.10) nokogiri (>= 1.5.10)
ruby_parser (3.11.0) ruby_parser (3.11.0)
@ -800,12 +828,15 @@ GEM
sass-listen (4.0.0) sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4) rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7) rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.0.6) sassc (2.0.1)
railties (>= 4.0.0, < 6) ffi (~> 1.9)
sass (~> 3.1) rake
sprockets (>= 2.8, < 4.0) sassc-rails (2.1.0)
sprockets-rails (>= 2.0, < 4.0) railties (>= 4.0.0)
tilt (>= 1.1, < 3) sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
sawyer (0.8.1) sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6) addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0) faraday (~> 0.8, < 1.0)
@ -815,9 +846,9 @@ GEM
seed-fu (2.3.7) seed-fu (2.3.7)
activerecord (>= 3.1) activerecord (>= 3.1)
activesupport (>= 3.1) activesupport (>= 3.1)
selenium-webdriver (3.12.0) selenium-webdriver (3.141.0)
childprocess (~> 0.5) childprocess (~> 0.5)
rubyzip (~> 1.2) rubyzip (~> 1.2, >= 1.2.2)
sentry-raven (2.9.0) sentry-raven (2.9.0)
faraday (>= 0.7.6, < 1.0) faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9) settingslogic (2.0.9)
@ -826,7 +857,7 @@ GEM
rack rack
shoulda-matchers (3.1.2) shoulda-matchers (3.1.2)
activesupport (>= 4.0.0) activesupport (>= 4.0.0)
sidekiq (5.2.5) sidekiq (5.2.7)
connection_pool (~> 2.2, >= 2.2.2) connection_pool (~> 2.2, >= 2.2.2)
rack (>= 1.5.0) rack (>= 1.5.0)
rack-protection (>= 1.5.0) rack-protection (>= 1.5.0)
@ -867,6 +898,10 @@ GEM
state_machines-activerecord (0.5.1) state_machines-activerecord (0.5.1)
activerecord (>= 4.1, < 6.0) activerecord (>= 4.1, < 6.0)
state_machines-activemodel (>= 0.5.0) state_machines-activemodel (>= 0.5.0)
swd (1.1.2)
activesupport (>= 3)
attr_required (>= 0.0.5)
httpclient (>= 2.4)
sys-filesystem (1.1.6) sys-filesystem (1.1.6)
ffi ffi
sysexits (1.2.0) sysexits (1.2.0)
@ -900,7 +935,7 @@ GEM
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.5) unf_ext (0.0.7.5)
unicode-display_width (1.3.2) unicode-display_width (1.5.0)
unicorn (5.4.1) unicorn (5.4.1)
kgio (~> 2.6) kgio (~> 2.6)
raindrops (~> 0.7) raindrops (~> 0.7)
@ -916,6 +951,12 @@ GEM
equalizer (~> 0.0.9) equalizer (~> 0.0.9)
parser (>= 2.3.1.2, < 2.6) parser (>= 2.3.1.2, < 2.6)
procto (~> 0.0.2) procto (~> 0.0.2)
validate_email (0.1.6)
activemodel (>= 3.0)
mail (>= 2.2.5)
validate_url (1.0.8)
activemodel (>= 3.0.0)
public_suffix
validates_hostname (1.0.6) validates_hostname (1.0.6)
activerecord (>= 3.0) activerecord (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
@ -928,6 +969,9 @@ GEM
vmstat (2.3.0) vmstat (2.3.0)
warden (1.2.7) warden (1.2.7)
rack (>= 1.0) rack (>= 1.0)
webfinger (1.1.0)
activesupport
httpclient (>= 2.4)
webmock (3.5.1) webmock (3.5.1)
addressable (>= 2.3.6) addressable (>= 2.3.6)
crack (>= 0.3.2) crack (>= 0.3.2)
@ -943,8 +987,8 @@ GEM
rinku rinku
with_env (1.1.0) with_env (1.1.0)
xml-simple (1.1.5) xml-simple (1.1.5)
xpath (2.1.0) xpath (3.2.0)
nokogiri (~> 1.3) nokogiri (~> 1.8)
PLATFORMS PLATFORMS
ruby ruby
@ -956,6 +1000,7 @@ DEPENDENCIES
acts-as-taggable-on (~> 6.0) acts-as-taggable-on (~> 6.0)
addressable (~> 2.5.2) addressable (~> 2.5.2)
akismet (~> 2.0) akismet (~> 2.0)
apollo_upload_server (~> 2.0.0.beta3)
asana (~> 0.8.1) asana (~> 0.8.1)
asciidoctor (~> 1.5.8) asciidoctor (~> 1.5.8)
asciidoctor-plantuml (= 0.0.8) asciidoctor-plantuml (= 0.0.8)
@ -963,7 +1008,7 @@ DEPENDENCIES
awesome_print awesome_print
babosa (~> 1.0.2) babosa (~> 1.0.2)
base32 (~> 0.3.0) base32 (~> 0.3.0)
batch-loader (~> 1.2.2) batch-loader (~> 1.4.0)
bcrypt_pbkdf (~> 1.0) bcrypt_pbkdf (~> 1.0)
benchmark-ips (~> 2.3.0) benchmark-ips (~> 2.3.0)
better_errors (~> 2.5.0) better_errors (~> 2.5.0)
@ -974,8 +1019,8 @@ DEPENDENCIES
browser (~> 2.5) browser (~> 2.5)
bullet (~> 5.5.0) bullet (~> 5.5.0)
bundler-audit (~> 0.5.0) bundler-audit (~> 0.5.0)
capybara (~> 2.16.1) capybara (~> 2.18.0)
capybara-screenshot (~> 1.0.18) capybara-screenshot (~> 1.0.22)
carrierwave (~> 1.3) carrierwave (~> 1.3)
charlock_holmes (~> 0.7.5) charlock_holmes (~> 0.7.5)
chronic (~> 0.10.2) chronic (~> 0.10.2)
@ -1020,25 +1065,26 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3) gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 1.22.1) gitaly-proto (~> 1.27.2)
github-markup (~> 1.7.0) github-markup (~> 1.7.0)
gitlab-default_value_for (~> 3.1.1) gitlab-default_value_for (~> 3.1.1)
gitlab-labkit (~> 0.2.0)
gitlab-markup (~> 1.7.0) gitlab-markup (~> 1.7.0)
gitlab-sidekiq-fetcher (~> 0.4.0) gitlab-sidekiq-fetcher (~> 0.4.0)
gitlab-styles (~> 2.4) gitlab-styles (~> 2.6)
gitlab_omniauth-ldap (~> 2.1.1) gitlab_omniauth-ldap (~> 2.1.1)
gon (~> 6.2) gon (~> 6.2)
google-api-client (~> 0.23) google-api-client (~> 0.23)
google-protobuf (~> 3.6) google-protobuf (~> 3.7.1)
gpgme (~> 2.0.18) gpgme (~> 2.0.18)
grape (~> 1.1.0) grape (~> 1.1.0)
grape-entity (~> 0.7.1) grape-entity (~> 0.7.1)
grape-path-helpers (~> 1.0) grape-path-helpers (~> 1.1)
grape_logging (~> 1.7) grape_logging (~> 1.7)
graphiql-rails (~> 1.4.10) graphiql-rails (~> 1.4.10)
graphql (~> 1.8.0) graphql (~> 1.8.0)
grpc (~> 1.15.0) grpc (~> 1.19.0)
haml_lint (~> 0.28.0) haml_lint (~> 0.30.0)
hamlit (~> 2.8.8) hamlit (~> 2.8.8)
hangouts-chat (~> 0.0.5) hangouts-chat (~> 0.0.5)
hashie-forbidden_attributes hashie-forbidden_attributes
@ -1049,7 +1095,6 @@ DEPENDENCIES
httparty (~> 0.16.4) httparty (~> 0.16.4)
icalendar icalendar
influxdb (~> 0.2) influxdb (~> 0.2)
jaeger-client (~> 0.10.0)
jira-ruby (~> 1.4) jira-ruby (~> 1.4)
js_regex (~> 3.1) js_regex (~> 3.1)
json-schema (~> 2.8.0) json-schema (~> 2.8.0)
@ -1057,7 +1102,7 @@ DEPENDENCIES
kaminari (~> 1.0) kaminari (~> 1.0)
knapsack (~> 1.17) knapsack (~> 1.17)
kubeclient (~> 4.2.2) kubeclient (~> 4.2.2)
letter_opener_web (~> 1.3.0) letter_opener_web (~> 1.3.4)
license_finder (~> 5.4) license_finder (~> 5.4)
licensee (~> 8.9) licensee (~> 8.9)
lograge (~> 0.5) lograge (~> 0.5)
@ -1071,7 +1116,7 @@ DEPENDENCIES
nakayoshi_fork (~> 0.0.4) nakayoshi_fork (~> 0.0.4)
net-ldap net-ldap
net-ssh (~> 5.0) net-ssh (~> 5.0)
nokogiri (~> 1.10.1) nokogiri (~> 1.10.3)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.9) octokit (~> 4.9)
omniauth (~> 1.8) omniauth (~> 1.8)
@ -1085,11 +1130,13 @@ DEPENDENCIES
omniauth-google-oauth2 (~> 0.6.0) omniauth-google-oauth2 (~> 0.6.0)
omniauth-kerberos (~> 0.3.0) omniauth-kerberos (~> 0.3.0)
omniauth-oauth2-generic (~> 0.2.2) omniauth-oauth2-generic (~> 0.2.2)
omniauth-salesforce (~> 1.0.5)
omniauth-saml (~> 1.10) omniauth-saml (~> 1.10)
omniauth-shibboleth (~> 1.3.0) omniauth-shibboleth (~> 1.3.0)
omniauth-twitter (~> 1.4) omniauth-twitter (~> 1.4)
omniauth-ultraauth (~> 0.0.2)
omniauth_crowd (~> 2.2.0) omniauth_crowd (~> 2.2.0)
opentracing (~> 0.4.3) omniauth_openid_connect (~> 0.3.0)
org-ruby (~> 0.9.12) org-ruby (~> 0.9.12)
peek (~> 1.0.1) peek (~> 1.0.1)
peek-gc (~> 0.0.2) peek-gc (~> 0.0.2)
@ -1109,9 +1156,8 @@ DEPENDENCIES
rack-cors (~> 1.0.0) rack-cors (~> 1.0.0)
rack-oauth2 (~> 1.9.3) rack-oauth2 (~> 1.9.3)
rack-proxy (~> 0.6.0) rack-proxy (~> 0.6.0)
rails (= 5.0.7.2) rails (= 5.1.7)
rails-controller-testing rails-controller-testing
rails-deprecated_sanitizer (~> 1.0.3)
rails-i18n (~> 5.1) rails-i18n (~> 5.1)
rainbow (~> 3.0) rainbow (~> 3.0)
raindrops (~> 0.18) raindrops (~> 0.18)
@ -1129,11 +1175,12 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-parameterized rspec-parameterized
rspec-rails (~> 3.7.0) rspec-rails (~> 3.7.0)
rspec-retry (~> 0.4.5) rspec-retry (~> 0.6.1)
rspec-set (~> 0.1.3) rspec-set (~> 0.1.3)
rspec_junit_formatter rspec_junit_formatter
rspec_profiling (~> 0.0.5) rspec_profiling (~> 0.0.5)
rubocop (~> 0.54.0) rubocop (~> 0.68.1)
rubocop-performance (~> 1.1.0)
rubocop-rspec (~> 1.22.1) rubocop-rspec (~> 1.22.1)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.17.0) ruby-prof (~> 0.17.0)
@ -1142,16 +1189,15 @@ DEPENDENCIES
rubyzip (~> 1.2.2) rubyzip (~> 1.2.2)
rugged (~> 0.28) rugged (~> 0.28)
sanitize (~> 4.6) sanitize (~> 4.6)
sass (~> 3.5) sassc-rails (~> 2.1.0)
sass-rails (~> 5.0.6)
scss_lint (~> 0.56.0) scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7) seed-fu (~> 2.3.7)
selenium-webdriver (~> 3.12) selenium-webdriver (~> 3.141)
sentry-raven (~> 2.7) sentry-raven (~> 2.7)
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6) sham_rack (~> 1.3.6)
shoulda-matchers (~> 3.1.2) shoulda-matchers (~> 3.1.2)
sidekiq (~> 5.2.1) sidekiq (~> 5.2.7)
sidekiq-cron (~> 1.0) sidekiq-cron (~> 1.0)
simple_po_parser (~> 1.1.2) simple_po_parser (~> 1.1.2)
simplecov (~> 0.14.0) simplecov (~> 0.14.0)

View file

@ -1 +1 @@
11.10.8 11.11.7

View file

@ -1,6 +1,7 @@
import $ from 'jquery'; import $ from 'jquery';
import _ from 'underscore'; import _ from 'underscore';
import axios from './lib/utils/axios_utils'; import axios from './lib/utils/axios_utils';
import { joinPaths } from './lib/utils/url_utility';
const Api = { const Api = {
groupsPath: '/api/:version/groups.json', groupsPath: '/api/:version/groups.json',
@ -339,11 +340,7 @@ const Api = {
}, },
buildUrl(url) { buildUrl(url) {
let urlRoot = ''; return joinPaths(gon.relative_url_root || '', url.replace(':version', gon.api_version));
if (gon.relative_url_root != null) {
urlRoot = gon.relative_url_root;
}
return urlRoot + url.replace(':version', gon.api_version);
}, },
}; };

View file

@ -0,0 +1,13 @@
export default {
computed: {
resolveButtonTitle() {
let title = 'Mark as resolved';
if (this.resolvedBy) {
title = `Resolved by ${this.resolvedBy.name}`;
}
return title;
},
},
};

View file

@ -1,5 +1,6 @@
import $ from 'jquery'; import $ from 'jquery';
import Clipboard from 'clipboard'; import Clipboard from 'clipboard';
import { sprintf, __ } from '~/locale';
function showTooltip(target, title) { function showTooltip(target, title) {
const $target = $(target); const $target = $(target);
@ -16,7 +17,7 @@ function showTooltip(target, title) {
} }
function genericSuccess(e) { function genericSuccess(e) {
showTooltip(e.trigger, 'Copied'); showTooltip(e.trigger, __('Copied'));
// Clear the selection and blur the trigger so it loses its border // Clear the selection and blur the trigger so it loses its border
e.clearSelection(); e.clearSelection();
$(e.trigger).blur(); $(e.trigger).blur();
@ -33,7 +34,7 @@ function genericError(e) {
} else { } else {
key = 'Ctrl'; key = 'Ctrl';
} }
showTooltip(e.trigger, `Press ${key}-C to copy`); showTooltip(e.trigger, sprintf(__(`Press %{key}-C to copy`), { key }));
} }
export default function initCopyToClipboard() { export default function initCopyToClipboard() {

View file

@ -1,6 +1,6 @@
import $ from 'jquery'; import $ from 'jquery';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import GfmAutoComplete from '~/gfm_auto_complete'; import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete';
export default function initGFMInput() { export default function initGFMInput() {
$('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => { $('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {

View file

@ -1,6 +1,7 @@
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
import { Node } from 'tiptap'; import { Node } from 'tiptap';
import { __ } from '~/locale';
// Transforms generated HTML back to GFM for Banzai::Filter::TableOfContentsFilter // Transforms generated HTML back to GFM for Banzai::Filter::TableOfContentsFilter
export default class TableOfContents extends Node { export default class TableOfContents extends Node {
@ -22,7 +23,7 @@ export default class TableOfContents extends Node {
priority: 51, priority: 51,
}, },
], ],
toDOM: () => ['p', { class: 'table-of-contents' }, 'Table of Contents'], toDOM: () => ['p', { class: 'table-of-contents' }, __('Table of Contents')],
}; };
} }

View file

@ -22,7 +22,7 @@ function MarkdownPreview() {}
// Minimum number of users referenced before triggering a warning // Minimum number of users referenced before triggering a warning
MarkdownPreview.prototype.referenceThreshold = 10; MarkdownPreview.prototype.referenceThreshold = 10;
MarkdownPreview.prototype.emptyMessage = 'Nothing to preview.'; MarkdownPreview.prototype.emptyMessage = __('Nothing to preview.');
MarkdownPreview.prototype.ajaxCache = {}; MarkdownPreview.prototype.ajaxCache = {};
@ -40,7 +40,7 @@ MarkdownPreview.prototype.showPreview = function($form) {
preview.text(this.emptyMessage); preview.text(this.emptyMessage);
this.hideReferencedUsers($form); this.hideReferencedUsers($form);
} else { } else {
preview.addClass('md-preview-loading').text('Loading...'); preview.addClass('md-preview-loading').text(__('Loading...'));
this.fetchMarkdownPreview( this.fetchMarkdownPreview(
mdText, mdText,
url, url,

View file

@ -1,6 +1,7 @@
import $ from 'jquery'; import $ from 'jquery';
import '../commons/bootstrap'; import '../commons/bootstrap';
import { isInIssuePage } from '../lib/utils/common_utils'; import { isInIssuePage } from '../lib/utils/common_utils';
import { __ } from '~/locale';
// Quick Submit behavior // Quick Submit behavior
// //
@ -65,7 +66,9 @@ $(document).on(
} }
const $this = $(this); const $this = $(this);
const title = isMac() ? 'You can also press &#8984;-Enter' : 'You can also press Ctrl-Enter'; const title = isMac()
? __('You can also press &#8984;-Enter')
: __('You can also press Ctrl-Enter');
$this.tooltip({ $this.tooltip({
container: 'body', container: 'body',

View file

@ -1,8 +1,9 @@
import Flash from '../flash'; import Flash from '../flash';
import BalsamiqViewer from './balsamiq/balsamiq_viewer'; import BalsamiqViewer from './balsamiq/balsamiq_viewer';
import { __ } from '~/locale';
function onError() { function onError() {
const flash = new Flash('Balsamiq file could not be loaded.'); const flash = new Flash(__('Balsamiq file could not be loaded.'));
return flash; return flash;
} }

View file

@ -5,6 +5,7 @@ import Dropzone from 'dropzone';
import { visitUrl } from '../lib/utils/url_utility'; import { visitUrl } from '../lib/utils/url_utility';
import { HIDDEN_CLASS } from '../lib/utils/constants'; import { HIDDEN_CLASS } from '../lib/utils/constants';
import csrf from '../lib/utils/csrf'; import csrf from '../lib/utils/csrf';
import { sprintf, __ } from '~/locale';
Dropzone.autoDiscover = false; Dropzone.autoDiscover = false;
@ -73,7 +74,7 @@ export default class BlobFileDropzone {
.html(errorMessage) .html(errorMessage)
.text(); .text();
$('.dropzone-alerts') $('.dropzone-alerts')
.html(`Error uploading file: "${stripped}"`) .html(sprintf(__('Error uploading file: %{stripped}'), { stripped }))
.show(); .show();
this.removeFile(file); this.removeFile(file);
}, },
@ -84,7 +85,7 @@ export default class BlobFileDropzone {
e.stopPropagation(); e.stopPropagation();
if (dropzone[0].dropzone.getQueuedFiles().length === 0) { if (dropzone[0].dropzone.getQueuedFiles().length === 0) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
alert('Please select a file'); alert(__('Please select a file'));
return false; return false;
} }
toggleLoading(submitButton, submitButtonLoadingIcon, true); toggleLoading(submitButton, submitButtonLoadingIcon, true);

View file

@ -1,5 +1,6 @@
import JSZip from 'jszip'; import JSZip from 'jszip';
import JSZipUtils from 'jszip-utils'; import JSZipUtils from 'jszip-utils';
import { __ } from '~/locale';
export default class SketchLoader { export default class SketchLoader {
constructor(container) { constructor(container) {
@ -56,10 +57,10 @@ export default class SketchLoader {
const errorMsg = document.createElement('p'); const errorMsg = document.createElement('p');
errorMsg.className = 'prepend-top-default append-bottom-default text-center'; errorMsg.className = 'prepend-top-default append-bottom-default text-center';
errorMsg.textContent = ` errorMsg.textContent = __(`
Cannot show preview. For previews on sketch files, they must have the file format Cannot show preview. For previews on sketch files, they must have the file format
introduced by Sketch version 43 and above. introduced by Sketch version 43 and above.
`; `);
this.container.appendChild(errorMsg); this.container.appendChild(errorMsg);
this.removeLoadingIcon(); this.removeLoadingIcon();

View file

@ -1,11 +1,12 @@
import FileTemplateSelector from '../file_template_selector'; import FileTemplateSelector from '../file_template_selector';
import { __ } from '~/locale';
export default class DockerfileSelector extends FileTemplateSelector { export default class DockerfileSelector extends FileTemplateSelector {
constructor({ mediator }) { constructor({ mediator }) {
super(mediator); super(mediator);
this.config = { this.config = {
key: 'dockerfile', key: 'dockerfile',
name: 'Dockerfile', name: __('Dockerfile'),
pattern: /(Dockerfile)/, pattern: /(Dockerfile)/,
type: 'dockerfiles', type: 'dockerfiles',
dropdown: '.js-dockerfile-selector', dropdown: '.js-dockerfile-selector',

View file

@ -2,6 +2,7 @@ import $ from 'jquery';
import Flash from '../../flash'; import Flash from '../../flash';
import { handleLocationHash } from '../../lib/utils/common_utils'; import { handleLocationHash } from '../../lib/utils/common_utils';
import axios from '../../lib/utils/axios_utils'; import axios from '../../lib/utils/axios_utils';
import { __ } from '~/locale';
export default class BlobViewer { export default class BlobViewer {
constructor() { constructor() {
@ -26,7 +27,7 @@ export default class BlobViewer {
promise promise
.then(module => module.default(viewer)) .then(module => module.default(viewer))
.catch(error => { .catch(error => {
Flash('Error loading file viewer.'); Flash(__('Error loading file viewer.'));
throw error; throw error;
}); });
@ -106,16 +107,19 @@ export default class BlobViewer {
if (!this.copySourceBtn) return; if (!this.copySourceBtn) return;
if (this.simpleViewer.getAttribute('data-loaded')) { if (this.simpleViewer.getAttribute('data-loaded')) {
this.copySourceBtn.setAttribute('title', 'Copy source to clipboard'); this.copySourceBtn.setAttribute('title', __('Copy source to clipboard'));
this.copySourceBtn.classList.remove('disabled'); this.copySourceBtn.classList.remove('disabled');
} else if (this.activeViewer === this.simpleViewer) { } else if (this.activeViewer === this.simpleViewer) {
this.copySourceBtn.setAttribute( this.copySourceBtn.setAttribute(
'title', 'title',
'Wait for the source to load to copy it to the clipboard', __('Wait for the source to load to copy it to the clipboard'),
); );
this.copySourceBtn.classList.add('disabled'); this.copySourceBtn.classList.add('disabled');
} else { } else {
this.copySourceBtn.setAttribute('title', 'Switch to the source to copy it to the clipboard'); this.copySourceBtn.setAttribute(
'title',
__('Switch to the source to copy it to the clipboard'),
);
this.copySourceBtn.classList.add('disabled'); this.copySourceBtn.classList.add('disabled');
} }
@ -158,7 +162,7 @@ export default class BlobViewer {
this.toggleCopyButtonState(); this.toggleCopyButtonState();
}) })
.catch(() => new Flash('Error loading viewer')); .catch(() => new Flash(__('Error loading viewer')));
} }
static loadViewer(viewerParam) { static loadViewer(viewerParam) {

View file

@ -0,0 +1,7 @@
export function getMilestone() {
return null;
}
export default {
getMilestone,
};

View file

@ -60,11 +60,15 @@ export default {
</script> </script>
<template> <template>
<div class="board-blank-state"> <div class="board-blank-state p-3">
<p>Add the following default lists to your Issue Board with one click:</p> <p>Add the following default lists to your Issue Board with one click:</p>
<ul class="board-blank-state-list"> <ul class="list-unstyled board-blank-state-list">
<li v-for="(label, index) in predefinedLabels" :key="index"> <li v-for="(label, index) in predefinedLabels" :key="index">
<span :style="{ backgroundColor: label.color }" class="label-color"> </span> <span
:style="{ backgroundColor: label.color }"
class="label-color position-relative d-inline-block rounded"
>
</span>
{{ label.title }} {{ label.title }}
</li> </li>
</ul> </ul>

View file

@ -83,7 +83,7 @@ export default {
}" }"
:index="index" :index="index"
:data-issue-id="issue.id" :data-issue-id="issue.id"
class="board-card" class="board-card p-3 rounded"
@mousedown="mouseDown" @mousedown="mouseDown"
@mousemove="mouseMove" @mousemove="mouseMove"
@mouseup="showIssue($event)" @mouseup="showIssue($event)"

View file

@ -1,5 +1,6 @@
import $ from 'jquery'; import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import { __ } from '~/locale';
export default Vue.extend({ export default Vue.extend({
props: { props: {
@ -13,7 +14,7 @@ export default Vue.extend({
$(this.$el).tooltip('hide'); $(this.$el).tooltip('hide');
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (window.confirm('Are you sure you want to delete this list?')) { if (window.confirm(__('Are you sure you want to delete this list?'))) {
this.list.destroy(); this.list.destroy();
} }
}, },

View file

@ -221,7 +221,10 @@ export default {
</script> </script>
<template> <template>
<div class="board-list-component"> <div
:class="{ 'd-none': !list.isExpanded, 'd-flex flex-column': list.isExpanded }"
class="board-list-component position-relative h-100"
>
<div v-if="loading" class="board-list-loading text-center" aria-label="Loading issues"> <div v-if="loading" class="board-list-loading text-center" aria-label="Loading issues">
<gl-loading-icon /> <gl-loading-icon />
</div> </div>
@ -236,7 +239,7 @@ export default {
:data-board="list.id" :data-board="list.id"
:data-board-type="list.type" :data-board-type="list.type"
:class="{ 'is-smaller': showIssueForm }" :class="{ 'is-smaller': showIssueForm }"
class="board-list js-board-list" class="board-list w-100 h-100 list-unstyled mb-0 p-1 js-board-list"
> >
<board-card <board-card
v-for="(issue, index) in issues" v-for="(issue, index) in issues"

View file

@ -1,6 +1,7 @@
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import { getMilestone } from 'ee_else_ce/boards/boards_util';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import ProjectSelect from './project_select.vue'; import ProjectSelect from './project_select.vue';
import ListIssue from '../models/issue'; import ListIssue from '../models/issue';
@ -51,11 +52,14 @@ export default {
const labels = this.list.label ? [this.list.label] : []; const labels = this.list.label ? [this.list.label] : [];
const assignees = this.list.assignee ? [this.list.assignee] : []; const assignees = this.list.assignee ? [this.list.assignee] : [];
const milestone = getMilestone(this.list);
const issue = new ListIssue({ const issue = new ListIssue({
title: this.title, title: this.title,
labels, labels,
subscribed: true, subscribed: true,
assignees, assignees,
milestone,
project_id: this.selectedProject.id, project_id: this.selectedProject.id,
}); });
@ -95,7 +99,7 @@ export default {
<template> <template>
<div class="board-new-issue-form"> <div class="board-new-issue-form">
<div class="board-card"> <div class="board-card position-relative p-3 rounded">
<form @submit="submit($event)"> <form @submit="submit($event)">
<div v-if="error" class="flash-container"> <div v-if="error" class="flash-container">
<div class="flash-alert">An error occurred. Please try again.</div> <div class="flash-alert">An error occurred. Please try again.</div>

View file

@ -2,19 +2,21 @@
import $ from 'jquery'; import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import Flash from '../../flash'; import Flash from '~/flash';
import { sprintf, __ } from '../../locale'; import { sprintf, __ } from '~/locale';
import Sidebar from '../../right_sidebar'; import Sidebar from '~/right_sidebar';
import eventHub from '../../sidebar/event_hub'; import eventHub from '~/sidebar/event_hub';
import AssigneeTitle from '../../sidebar/components/assignees/assignee_title.vue'; import DueDateSelectors from '~/due_date_select';
import Assignees from '../../sidebar/components/assignees/assignees.vue'; import IssuableContext from '~/issuable_context';
import DueDateSelectors from '../../due_date_select'; import LabelsSelect from '~/labels_select';
import AssigneeTitle from '~/sidebar/components/assignees/assignee_title.vue';
import Assignees from '~/sidebar/components/assignees/assignees.vue';
import Subscriptions from '~/sidebar/components/subscriptions/subscriptions.vue';
import TimeTracker from '~/sidebar/components/time_tracking/time_tracker.vue';
import MilestoneSelect from '~/milestone_select';
import RemoveBtn from './sidebar/remove_issue.vue'; import RemoveBtn from './sidebar/remove_issue.vue';
import IssuableContext from '../../issuable_context';
import LabelsSelect from '../../labels_select';
import Subscriptions from '../../sidebar/components/subscriptions/subscriptions.vue';
import MilestoneSelect from '../../milestone_select';
import boardsStore from '../stores/boards_store'; import boardsStore from '../stores/boards_store';
import { isScopedLabel } from '~/lib/utils/common_utils';
export default Vue.extend({ export default Vue.extend({
components: { components: {
@ -22,6 +24,7 @@ export default Vue.extend({
Assignees, Assignees,
RemoveBtn, RemoveBtn,
Subscriptions, Subscriptions,
TimeTracker,
}, },
props: { props: {
currentUser: { currentUser: {
@ -42,7 +45,7 @@ export default Vue.extend({
return Object.keys(this.issue).length; return Object.keys(this.issue).length;
}, },
milestoneTitle() { milestoneTitle() {
return this.issue.milestone ? this.issue.milestone.title : 'No Milestone'; return this.issue.milestone ? this.issue.milestone.title : __('No Milestone');
}, },
canRemove() { canRemove() {
return !this.list.preset; return !this.list.preset;
@ -138,5 +141,11 @@ export default Vue.extend({
Flash(__('An error occurred while saving assignees')); Flash(__('An error occurred while saving assignees'));
}); });
}, },
showScopedLabels(label) {
return boardsStore.scopedLabels.enabled && isScopedLabel(label);
},
helpLink() {
return boardsStore.scopedLabels.helpLink;
},
}, },
}); });

View file

@ -4,11 +4,14 @@ import { GlTooltipDirective } from '@gitlab/ui';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
import issueCardInner from 'ee_else_ce/boards/mixins/issue_card_inner';
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import IssueDueDate from './issue_due_date.vue'; import IssueDueDate from './issue_due_date.vue';
import IssueTimeEstimate from './issue_time_estimate.vue'; import IssueTimeEstimate from './issue_time_estimate.vue';
import boardsStore from '../stores/boards_store'; import boardsStore from '../stores/boards_store';
import IssueCardInnerScopedLabel from './issue_card_inner_scoped_label.vue';
import { isScopedLabel } from '~/lib/utils/common_utils';
export default { export default {
components: { components: {
@ -17,10 +20,13 @@ export default {
TooltipOnTruncate, TooltipOnTruncate,
IssueDueDate, IssueDueDate,
IssueTimeEstimate, IssueTimeEstimate,
IssueCardWeight: () => import('ee_component/boards/components/issue_card_weight.vue'),
IssueCardInnerScopedLabel,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
mixins: [issueCardInner],
props: { props: {
issue: { issue: {
type: Object, type: Object,
@ -96,6 +102,9 @@ export default {
orderedLabels() { orderedLabels() {
return _.sortBy(this.issue.labels, 'title'); return _.sortBy(this.issue.labels, 'title');
}, },
helpLink() {
return boardsStore.scopedLabels.helpLink;
},
}, },
methods: { methods: {
isIndexLessThanlimit(index) { isIndexLessThanlimit(index) {
@ -129,14 +138,6 @@ export default {
this.applyFilter(filter); this.applyFilter(filter);
}, },
filterByWeight(weight) {
if (!this.updateFilters) return;
const issueWeight = encodeURIComponent(weight);
const filter = `weight=${issueWeight}`;
this.applyFilter(filter);
},
applyFilter(filter) { applyFilter(filter) {
const filterPath = boardsStore.filter.path.split('&'); const filterPath = boardsStore.filter.path.split('&');
const filterIndex = filterPath.indexOf(filter); const filterIndex = filterPath.indexOf(filter);
@ -159,12 +160,15 @@ export default {
color: label.textColor, color: label.textColor,
}; };
}, },
showScopedLabel(label) {
return boardsStore.scopedLabels.enabled && isScopedLabel(label);
},
}, },
}; };
</script> </script>
<template> <template>
<div> <div>
<div class="board-card-header"> <div class="d-flex board-card-header" dir="auto">
<h4 class="board-card-title append-bottom-0 prepend-top-0"> <h4 class="board-card-title append-bottom-0 prepend-top-0">
<icon <icon
v-if="issue.confidential" v-if="issue.confidential"
@ -179,27 +183,37 @@ export default {
</h4> </h4>
</div> </div>
<div v-if="showLabelFooter" class="board-card-labels prepend-top-4 d-flex flex-wrap"> <div v-if="showLabelFooter" class="board-card-labels prepend-top-4 d-flex flex-wrap">
<button <template v-for="label in orderedLabels" v-if="showLabel(label)">
v-for="label in orderedLabels" <issue-card-inner-scoped-label
v-if="showLabel(label)" v-if="showScopedLabel(label)"
:key="label.id" :key="label.id"
v-gl-tooltip :label="label"
:style="labelStyle(label)" :label-style="labelStyle(label)"
:title="label.description" :scoped-labels-documentation-link="helpLink"
class="badge color-label append-right-4 prepend-top-4" @scoped-label-click="filterByLabel($event)"
type="button" />
@click="filterByLabel(label)"
> <button
{{ label.title }} v-else
</button> :key="label.id"
v-gl-tooltip
:style="labelStyle(label)"
:title="label.description"
class="badge color-label append-right-4 prepend-top-4"
type="button"
@click="filterByLabel(label)"
>
{{ label.title }}
</button>
</template>
</div> </div>
<div class="board-card-footer d-flex justify-content-between align-items-end"> <div class="board-card-footer d-flex justify-content-between align-items-end">
<div <div
class="d-flex align-items-start flex-wrap-reverse board-card-number-container js-board-card-number-container" class="d-flex align-items-start flex-wrap-reverse board-card-number-container overflow-hidden js-board-card-number-container"
> >
<span <span
v-if="issue.referencePath" v-if="issue.referencePath"
class="board-card-number d-flex append-right-8 prepend-top-8" class="board-card-number overflow-hidden d-flex append-right-8 prepend-top-8"
> >
<tooltip-on-truncate <tooltip-on-truncate
v-if="issueReferencePath" v-if="issueReferencePath"
@ -213,10 +227,14 @@ export default {
<issue-due-date v-if="issue.dueDate" :date="issue.dueDate" /><issue-time-estimate <issue-due-date v-if="issue.dueDate" :date="issue.dueDate" /><issue-time-estimate
v-if="issue.timeEstimate" v-if="issue.timeEstimate"
:estimate="issue.timeEstimate" :estimate="issue.timeEstimate"
/><issue-card-weight
v-if="issue.weight"
:weight="issue.weight"
@click="filterByWeight(issue.weight)"
/> />
</span> </span>
</div> </div>
<div class="board-card-assignee"> <div class="board-card-assignee d-flex">
<user-avatar-link <user-avatar-link
v-for="(assignee, index) in issue.assignees" v-for="(assignee, index) in issue.assignees"
v-if="shouldRenderAssignee(index)" v-if="shouldRenderAssignee(index)"

View file

@ -0,0 +1,45 @@
<script>
import { GlLink, GlTooltip } from '@gitlab/ui';
export default {
components: {
GlTooltip,
GlLink,
},
props: {
label: {
type: Object,
required: true,
},
labelStyle: {
type: Object,
required: true,
},
scopedLabelsDocumentationLink: {
type: String,
required: true,
},
},
};
</script>
<template>
<span
class="d-inline-block position-relative scoped-label-wrapper append-right-4 prepend-top-4 board-label"
>
<a @click="$emit('scoped-label-click', label)">
<span :ref="'labelTitleRef'" :style="labelStyle" class="badge label color-label">
{{ label.title }}
</span>
<gl-tooltip :target="() => $refs.labelTitleRef" placement="top" boundary="viewport">
<span class="font-weight-bold scoped-label-tooltip-title">{{ __('Scoped label') }}</span
><br />
{{ label.description }}
</gl-tooltip>
</a>
<gl-link :href="scopedLabelsDocumentationLink" target="_blank" class="label scoped-label"
><i class="fa fa-question-circle" :style="labelStyle"></i
></gl-link>
</span>
</template>

View file

@ -82,7 +82,11 @@ export default {
<template> <template>
<span> <span>
<span ref="issueDueDate" :class="cssClass" class="board-card-info card-number"> <span ref="issueDueDate" :class="cssClass" class="board-card-info card-number">
<icon :class="{ 'text-danger': isPastDue, 'board-card-info-icon': true }" name="calendar" /> <icon
:class="{ 'text-danger': isPastDue }"
class="board-card-info-icon align-top"
name="calendar"
/>
<time :class="{ 'text-danger': isPastDue }" datetime="date" class="board-card-info-text">{{ <time :class="{ 'text-danger': isPastDue }" datetime="date" class="board-card-info-text">{{
body body
}}</time> }}</time>

View file

@ -28,7 +28,7 @@ export default {
<template> <template>
<span> <span>
<span ref="issueTimeEstimate" class="board-card-info card-number"> <span ref="issueTimeEstimate" class="board-card-info card-number">
<icon name="hourglass" css-classes="board-card-info-icon" /><time <icon name="hourglass" css-classes="board-card-info-icon align-top" /><time
class="board-card-info-text" class="board-card-info-text"
>{{ timeEstimate }}</time >{{ timeEstimate }}</time
> >

View file

@ -42,8 +42,8 @@ export default {
</script> </script>
<template> <template>
<section class="empty-state"> <section class="empty-state d-flex mt-0 h-100">
<div class="row"> <div class="row w-100 my-auto mx-0">
<div class="col-12 col-md-6 order-md-last"> <div class="col-12 col-md-6 order-md-last">
<aside class="svg-content d-none d-md-block"><img :src="emptyStateSvg" /></aside> <aside class="svg-content d-none d-md-block"><img :src="emptyStateSvg" /></aside>
</div> </div>

View file

@ -50,8 +50,8 @@ export default {
</script> </script>
<template> <template>
<div> <div>
<header class="add-issues-header form-actions"> <header class="add-issues-header border-top-0 form-actions">
<h2> <h2 class="m-0">
Add issues Add issues
<button <button
type="button" type="button"
@ -65,7 +65,7 @@ export default {
</h2> </h2>
</header> </header>
<modal-tabs v-if="!loading && issuesCount > 0" /> <modal-tabs v-if="!loading && issuesCount > 0" />
<div v-if="showSearch" class="add-issues-search append-bottom-10"> <div v-if="showSearch" class="d-flex append-bottom-10">
<modal-filters :store="filter" /> <modal-filters :store="filter" />
<button <button
ref="selectAllBtn" ref="selectAllBtn"

View file

@ -143,8 +143,11 @@ export default {
}; };
</script> </script>
<template> <template>
<div v-if="showAddIssuesModal" class="add-issues-modal"> <div
<div class="add-issues-container"> v-if="showAddIssuesModal"
class="add-issues-modal d-flex position-fixed position-top-0 position-bottom-0 position-left-0 position-right-0 h-100"
>
<div class="add-issues-container d-flex flex-column m-auto rounded">
<modal-header <modal-header
:project-id="projectId" :project-id="projectId"
:milestone-path="milestonePath" :milestone-path="milestonePath"
@ -161,8 +164,10 @@ export default {
:new-issue-path="newIssuePath" :new-issue-path="newIssuePath"
:empty-state-svg="emptyStateSvg" :empty-state-svg="emptyStateSvg"
/> />
<section v-if="loading || filterLoading" class="add-issues-list text-center"> <section v-if="loading || filterLoading" class="add-issues-list d-flex h-100 text-center">
<div class="add-issues-list-loading"><gl-loading-icon /></div> <div class="add-issues-list-loading w-100 align-self-center">
<gl-loading-icon size="md" />
</div>
</section> </section>
<modal-footer /> <modal-footer />
</div> </div>

View file

@ -117,7 +117,7 @@ export default {
}; };
</script> </script>
<template> <template>
<section ref="list" class="add-issues-list add-issues-list-columns"> <section ref="list" class="add-issues-list add-issues-list-columns d-flex h-100">
<div <div
v-if="issuesCount > 0 && issues.length === 0" v-if="issuesCount > 0 && issues.length === 0"
class="empty-state add-issues-empty-state-filter text-center" class="empty-state add-issues-empty-state-filter text-center"
@ -129,7 +129,7 @@ export default {
<div v-for="issue in group" v-if="showIssue(issue)" :key="issue.id" class="board-card-parent"> <div v-for="issue in group" v-if="showIssue(issue)" :key="issue.id" class="board-card-parent">
<div <div
:class="{ 'is-active': issue.selected }" :class="{ 'is-active': issue.selected }"
class="board-card" class="board-card position-relative p-3 rounded"
@click="toggleIssue($event, issue)" @click="toggleIssue($event, issue)"
> >
<issue-card-inner :issue="issue" :issue-link-base="issueLinkBase" :root-path="rootPath" /> <issue-card-inner :issue="issue" :issue-link-base="issueLinkBase" :root-path="rootPath" />

View file

@ -1,6 +1,8 @@
import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable_filtered_search_token_keys';
import FilteredSearchContainer from '../filtered_search/container'; import FilteredSearchContainer from '../filtered_search/container';
import FilteredSearchManager from '../filtered_search/filtered_search_manager'; import FilteredSearchManager from '../filtered_search/filtered_search_manager';
import boardsStore from './stores/boards_store'; import boardsStore from './stores/boards_store';
import { isEE } from '~/lib/utils/common_utils';
export default class FilteredSearchBoards extends FilteredSearchManager { export default class FilteredSearchBoards extends FilteredSearchManager {
constructor(store, updateUrl = false, cantEdit = []) { constructor(store, updateUrl = false, cantEdit = []) {
@ -8,6 +10,8 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
page: 'boards', page: 'boards',
isGroupDecendent: true, isGroupDecendent: true,
stateFiltersSelector: '.issues-state-filters', stateFiltersSelector: '.issues-state-filters',
isGroup: isEE(),
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
}); });
this.store = store; this.store = store;

View file

@ -24,7 +24,11 @@ import BoardSidebar from './components/board_sidebar';
import initNewListDropdown from './components/new_list_dropdown'; import initNewListDropdown from './components/new_list_dropdown';
import BoardAddIssuesModal from './components/modal/index.vue'; import BoardAddIssuesModal from './components/modal/index.vue';
import '~/vue_shared/vue_resource_interceptor'; import '~/vue_shared/vue_resource_interceptor';
import { NavigationType, parseBoolean } from '~/lib/utils/common_utils'; import {
NavigationType,
convertObjectPropsToCamelCase,
parseBoolean,
} from '~/lib/utils/common_utils';
let issueBoardsApp; let issueBoardsApp;
@ -119,7 +123,7 @@ export default () => {
this.loading = false; this.loading = false;
}) })
.catch(() => { .catch(() => {
Flash('An error occurred while fetching the board lists. Please try again.'); Flash(__('An error occurred while fetching the board lists. Please try again.'));
}); });
}, },
methods: { methods: {
@ -133,9 +137,25 @@ export default () => {
BoardService.getIssueInfo(sidebarInfoEndpoint) BoardService.getIssueInfo(sidebarInfoEndpoint)
.then(res => res.data) .then(res => res.data)
.then(data => { .then(data => {
const {
subscribed,
totalTimeSpent,
timeEstimate,
humanTimeEstimate,
humanTotalTimeSpent,
weight,
epic,
} = convertObjectPropsToCamelCase(data);
newIssue.setFetchingState('subscriptions', false); newIssue.setFetchingState('subscriptions', false);
newIssue.updateData({ newIssue.updateData({
subscribed: data.subscribed, humanTimeSpent: humanTotalTimeSpent,
timeSpent: totalTimeSpent,
humanTimeEstimate,
timeEstimate,
subscribed,
weight,
epic,
}); });
}) })
.catch(() => { .catch(() => {
@ -203,7 +223,7 @@ export default () => {
}, },
tooltipTitle() { tooltipTitle() {
if (this.disabled) { if (this.disabled) {
return 'Please add a list to your board first'; return __('Please add a list to your board first');
} }
return ''; return '';

View file

@ -0,0 +1,5 @@
export default {
methods: {
filterByWeight() {},
},
};

View file

@ -5,6 +5,7 @@
import Vue from 'vue'; import Vue from 'vue';
import '~/vue_shared/models/label'; import '~/vue_shared/models/label';
import { isEE, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import IssueProject from './project'; import IssueProject from './project';
import boardsStore from '../stores/boards_store'; import boardsStore from '../stores/boards_store';
@ -28,7 +29,6 @@ class ListIssue {
this.referencePath = obj.reference_path; this.referencePath = obj.reference_path;
this.path = obj.real_path; this.path = obj.real_path;
this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint; this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint;
this.milestone_id = obj.milestone_id;
this.project_id = obj.project_id; this.project_id = obj.project_id;
this.timeEstimate = obj.time_estimate; this.timeEstimate = obj.time_estimate;
this.assignableLabelsEndpoint = obj.assignable_labels_endpoint; this.assignableLabelsEndpoint = obj.assignable_labels_endpoint;
@ -39,6 +39,7 @@ class ListIssue {
if (obj.milestone) { if (obj.milestone) {
this.milestone = new ListMilestone(obj.milestone); this.milestone = new ListMilestone(obj.milestone);
this.milestone_id = obj.milestone.id;
} }
obj.labels.forEach(label => { obj.labels.forEach(label => {
@ -88,6 +89,19 @@ class ListIssue {
this.assignees = []; this.assignees = [];
} }
addMilestone(milestone) {
const miletoneId = this.milestone ? this.milestone.id : null;
if (isEE && milestone.id !== miletoneId) {
this.milestone = new ListMilestone(milestone);
}
}
removeMilestone(removeMilestone) {
if (isEE && removeMilestone && removeMilestone.id === this.milestone.id) {
this.milestone = {};
}
}
getLists() { getLists() {
return boardsStore.state.lists.filter(list => list.findIssue(this.id)); return boardsStore.state.lists.filter(list => list.findIssue(this.id));
} }
@ -127,7 +141,7 @@ class ListIssue {
* PATCH the said object. * PATCH the said object.
*/ */
if (body) { if (body) {
this.labels = body.labels; this.labels = convertObjectPropsToCamelCase(body.labels, { deep: true });
} }
}); });
} }

View file

@ -4,8 +4,9 @@
import { __ } from '~/locale'; import { __ } from '~/locale';
import ListLabel from '~/vue_shared/models/label'; import ListLabel from '~/vue_shared/models/label';
import ListAssignee from '~/vue_shared/models/assignee'; import ListAssignee from '~/vue_shared/models/assignee';
import { urlParamsToObject } from '~/lib/utils/common_utils'; import { isEE, urlParamsToObject } from '~/lib/utils/common_utils';
import boardsStore from '../stores/boards_store'; import boardsStore from '../stores/boards_store';
import ListMilestone from './milestone';
const PER_PAGE = 20; const PER_PAGE = 20;
@ -51,6 +52,9 @@ class List {
} else if (obj.user) { } else if (obj.user) {
this.assignee = new ListAssignee(obj.user); this.assignee = new ListAssignee(obj.user);
this.title = this.assignee.name; this.title = this.assignee.name;
} else if (isEE && obj.milestone) {
this.milestone = new ListMilestone(obj.milestone);
this.title = this.milestone.title;
} }
if (!typeInfo.isBlank && this.id) { if (!typeInfo.isBlank && this.id) {
@ -69,12 +73,14 @@ class List {
} }
save() { save() {
const entity = this.label || this.assignee; const entity = this.label || this.assignee || this.milestone;
let entityType = ''; let entityType = '';
if (this.label) { if (this.label) {
entityType = 'label_id'; entityType = 'label_id';
} else { } else if (this.assignee) {
entityType = 'assignee_id'; entityType = 'assignee_id';
} else if (isEE && this.milestone) {
entityType = 'milestone_id';
} }
return gl.boardService return gl.boardService
@ -84,6 +90,7 @@ class List {
this.id = data.id; this.id = data.id;
this.type = data.list_type; this.type = data.list_type;
this.position = data.position; this.position = data.position;
this.label = data.label;
return this.getIssues(); return this.getIssues();
}); });
@ -192,6 +199,13 @@ class List {
issue.addAssignee(this.assignee); issue.addAssignee(this.assignee);
} }
if (isEE && this.milestone) {
if (listFrom && listFrom.type === 'milestone') {
issue.removeMilestone(listFrom.milestone);
}
issue.addMilestone(this.milestone);
}
if (listFrom) { if (listFrom) {
this.issuesSize += 1; this.issuesSize += 1;

View file

@ -1,7 +1,16 @@
class ListMilestone { import { isEE } from '~/lib/utils/common_utils';
export default class ListMilestone {
constructor(obj) { constructor(obj) {
this.id = obj.id; this.id = obj.id;
this.title = obj.title; this.title = obj.title;
if (isEE) {
this.path = obj.path;
this.state = obj.state;
this.webUrl = obj.web_url || obj.webUrl;
this.description = obj.description;
}
} }
} }

View file

@ -5,14 +5,26 @@ import $ from 'jquery';
import _ from 'underscore'; import _ from 'underscore';
import Vue from 'vue'; import Vue from 'vue';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import BoardsStoreEE from 'ee_else_ce/boards/stores/boards_store_ee';
import { getUrlParamsArray, parseBoolean } from '~/lib/utils/common_utils'; import { getUrlParamsArray, parseBoolean } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
const boardsStore = { const boardsStore = {
disabled: false, disabled: false,
scopedLabels: {
helpLink: '',
enabled: false,
},
filter: { filter: {
path: '', path: '',
}, },
state: {}, state: {
currentBoard: {
labels: [],
},
currentPage: '',
reload: false,
},
detail: { detail: {
issue: {}, issue: {},
}, },
@ -27,6 +39,10 @@ const boardsStore = {
issue: {}, issue: {},
}; };
}, },
showPage(page) {
this.state.reload = false;
this.state.currentPage = page;
},
addList(listObj, defaultAvatar) { addList(listObj, defaultAvatar) {
const list = new List(listObj, defaultAvatar); const list = new List(listObj, defaultAvatar);
this.state.lists.push(list); this.state.lists.push(list);
@ -63,7 +79,7 @@ const boardsStore = {
this.addList({ this.addList({
id: 'blank', id: 'blank',
list_type: 'blank', list_type: 'blank',
title: 'Welcome to your Issue Board!', title: __('Welcome to your Issue Board!'),
position: 0, position: 0,
}); });
@ -174,6 +190,8 @@ const boardsStore = {
}, },
}; };
BoardsStoreEE.initEESpecific(boardsStore);
// hacks added in order to allow milestone_select to function properly // hacks added in order to allow milestone_select to function properly
// TODO: remove these // TODO: remove these

View file

@ -0,0 +1,5 @@
// this is just to make ee_else_ce happy and will be cleaned up in https://gitlab.com/gitlab-org/gitlab-ce/issues/59807
export default {
initEESpecific() {},
};

View file

@ -26,6 +26,10 @@ export default class VariableList {
selector: '.js-ci-variable-input-id', selector: '.js-ci-variable-input-id',
default: '', default: '',
}, },
variable_type: {
selector: '.js-ci-variable-input-variable-type',
default: 'env_var',
},
key: { key: {
selector: '.js-ci-variable-input-key', selector: '.js-ci-variable-input-key',
default: '', default: '',

View file

@ -19,6 +19,7 @@ export default function setupNativeFormVariableList({ container, formField = 'va
const isTouched = variableList.checkIfRowTouched($lastRow); const isTouched = variableList.checkIfRowTouched($lastRow);
if (!isTouched) { if (!isTouched) {
$lastRow.find('input, textarea').attr('name', ''); $lastRow.find('input, textarea').attr('name', '');
$lastRow.find('select').attr('name', '');
} }
}); });
} }

View file

@ -1,25 +1,20 @@
import Visibility from 'visibilityjs'; import Visibility from 'visibilityjs';
import Vue from 'vue'; import Vue from 'vue';
import { GlToast } from '@gitlab/ui';
import PersistentUserCallout from '../persistent_user_callout'; import PersistentUserCallout from '../persistent_user_callout';
import { s__, sprintf } from '../locale'; import { s__, sprintf } from '../locale';
import Flash from '../flash'; import Flash from '../flash';
import Poll from '../lib/utils/poll'; import Poll from '../lib/utils/poll';
import initSettingsPanels from '../settings_panels'; import initSettingsPanels from '../settings_panels';
import eventHub from './event_hub'; import eventHub from './event_hub';
import { import { APPLICATION_STATUS, INGRESS, INGRESS_DOMAIN_SUFFIX } from './constants';
APPLICATION_STATUS,
REQUEST_SUBMITTED,
REQUEST_FAILURE,
UPGRADE_REQUESTED,
UPGRADE_REQUEST_FAILURE,
INGRESS,
INGRESS_DOMAIN_SUFFIX,
} from './constants';
import ClustersService from './services/clusters_service'; import ClustersService from './services/clusters_service';
import ClustersStore from './stores/clusters_store'; import ClustersStore from './stores/clusters_store';
import Applications from './components/applications.vue'; import Applications from './components/applications.vue';
import setupToggleButtons from '../toggle_buttons'; import setupToggleButtons from '../toggle_buttons';
Vue.use(GlToast);
/** /**
* Cluster page has 2 separate parts: * Cluster page has 2 separate parts:
* Toggle button and applications section * Toggle button and applications section
@ -134,20 +129,20 @@ export default class Clusters {
if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken); if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken);
eventHub.$on('installApplication', this.installApplication); eventHub.$on('installApplication', this.installApplication);
eventHub.$on('upgradeApplication', data => this.upgradeApplication(data)); eventHub.$on('upgradeApplication', data => this.upgradeApplication(data));
eventHub.$on('upgradeFailed', appId => this.upgradeFailed(appId));
eventHub.$on('dismissUpgradeSuccess', appId => this.dismissUpgradeSuccess(appId)); eventHub.$on('dismissUpgradeSuccess', appId => this.dismissUpgradeSuccess(appId));
eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data)); eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data));
eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data)); eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data));
eventHub.$on('uninstallApplication', data => this.uninstallApplication(data));
} }
removeListeners() { removeListeners() {
if (this.showTokenButton) this.showTokenButton.removeEventListener('click', this.showToken); if (this.showTokenButton) this.showTokenButton.removeEventListener('click', this.showToken);
eventHub.$off('installApplication', this.installApplication); eventHub.$off('installApplication', this.installApplication);
eventHub.$off('upgradeApplication', this.upgradeApplication); eventHub.$off('upgradeApplication', this.upgradeApplication);
eventHub.$off('upgradeFailed', this.upgradeFailed);
eventHub.$off('dismissUpgradeSuccess', this.dismissUpgradeSuccess); eventHub.$off('dismissUpgradeSuccess', this.dismissUpgradeSuccess);
eventHub.$off('saveKnativeDomain'); eventHub.$off('saveKnativeDomain');
eventHub.$off('setKnativeHostname'); eventHub.$off('setKnativeHostname');
eventHub.$off('uninstallApplication');
} }
initPolling() { initPolling() {
@ -256,14 +251,14 @@ export default class Clusters {
} }
} }
installApplication(data) { installApplication({ id: appId, params }) {
const appId = data.id;
this.store.updateAppProperty(appId, 'requestStatus', REQUEST_SUBMITTED);
this.store.updateAppProperty(appId, 'requestReason', null); this.store.updateAppProperty(appId, 'requestReason', null);
this.store.updateAppProperty(appId, 'statusReason', null); this.store.updateAppProperty(appId, 'statusReason', null);
return this.service.installApplication(appId, data.params).catch(() => { this.store.installApplication(appId);
this.store.updateAppProperty(appId, 'requestStatus', REQUEST_FAILURE);
return this.service.installApplication(appId, params).catch(() => {
this.store.notifyInstallFailure(appId);
this.store.updateAppProperty( this.store.updateAppProperty(
appId, appId,
'requestReason', 'requestReason',
@ -272,29 +267,39 @@ export default class Clusters {
}); });
} }
upgradeApplication(data) { uninstallApplication({ id: appId }) {
const appId = data.id; this.store.updateAppProperty(appId, 'requestReason', null);
this.store.updateAppProperty(appId, 'requestStatus', UPGRADE_REQUESTED); this.store.updateAppProperty(appId, 'statusReason', null);
this.store.updateAppProperty(appId, 'status', APPLICATION_STATUS.UPDATING);
this.service.installApplication(appId, data.params).catch(() => this.upgradeFailed(appId)); this.store.uninstallApplication(appId);
return this.service.uninstallApplication(appId).catch(() => {
this.store.notifyUninstallFailure(appId);
this.store.updateAppProperty(
appId,
'requestReason',
s__('ClusterIntegration|Request to begin uninstalling failed'),
);
});
} }
upgradeFailed(appId) { upgradeApplication(data) {
this.store.updateAppProperty(appId, 'requestStatus', UPGRADE_REQUEST_FAILURE); const appId = data.id;
this.store.updateApplication(appId);
this.service.installApplication(appId, data.params).catch(() => {
this.store.notifyUpdateFailure(appId);
});
} }
dismissUpgradeSuccess(appId) { dismissUpgradeSuccess(appId) {
this.store.updateAppProperty(appId, 'requestStatus', null); this.store.acknowledgeSuccessfulUpdate(appId);
} }
toggleIngressDomainHelpText(ingressPreviousState, ingressNewState) { toggleIngressDomainHelpText({ externalIp }, { externalIp: newExternalIp }) {
const { externalIp, status } = ingressNewState; if (externalIp !== newExternalIp) {
const helpTextHidden = status !== APPLICATION_STATUS.INSTALLED || !externalIp; this.ingressDomainHelpText.classList.toggle('hide', !newExternalIp);
const domainSnippetText = `${externalIp}${INGRESS_DOMAIN_SUFFIX}`; this.ingressDomainSnippet.textContent = `${newExternalIp}${INGRESS_DOMAIN_SUFFIX}`;
if (ingressPreviousState.status !== status) {
this.ingressDomainHelpText.classList.toggle('hide', helpTextHidden);
this.ingressDomainSnippet.textContent = domainSnippetText;
} }
} }

View file

@ -1,17 +1,15 @@
<script> <script>
/* eslint-disable vue/require-default-prop */ /* eslint-disable vue/require-default-prop */
import { GlLink } from '@gitlab/ui'; import { GlLink, GlModalDirective } from '@gitlab/ui';
import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
import { s__, sprintf } from '../../locale'; import { s__, sprintf } from '../../locale';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import identicon from '../../vue_shared/components/identicon.vue'; import identicon from '../../vue_shared/components/identicon.vue';
import loadingButton from '../../vue_shared/components/loading_button.vue'; import loadingButton from '../../vue_shared/components/loading_button.vue';
import { import UninstallApplicationButton from './uninstall_application_button.vue';
APPLICATION_STATUS, import UninstallApplicationConfirmationModal from './uninstall_application_confirmation_modal.vue';
REQUEST_SUBMITTED,
REQUEST_FAILURE, import { APPLICATION_STATUS } from '../constants';
UPGRADE_REQUESTED,
} from '../constants';
export default { export default {
components: { components: {
@ -19,6 +17,11 @@ export default {
identicon, identicon,
TimeagoTooltip, TimeagoTooltip,
GlLink, GlLink,
UninstallApplicationButton,
UninstallApplicationConfirmationModal,
},
directives: {
GlModalDirective,
}, },
props: { props: {
id: { id: {
@ -47,6 +50,11 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
uninstallable: {
type: Boolean,
required: false,
default: false,
},
status: { status: {
type: String, type: String,
required: false, required: false,
@ -55,14 +63,20 @@ export default {
type: String, type: String,
required: false, required: false,
}, },
requestStatus: {
type: String,
required: false,
},
requestReason: { requestReason: {
type: String, type: String,
required: false, required: false,
}, },
installed: {
type: Boolean,
required: false,
default: false,
},
installFailed: {
type: Boolean,
required: false,
default: false,
},
version: { version: {
type: String, type: String,
required: false, required: false,
@ -75,6 +89,31 @@ export default {
type: Boolean, type: Boolean,
required: false, required: false,
}, },
updateSuccessful: {
type: Boolean,
required: false,
default: false,
},
updateFailed: {
type: Boolean,
required: false,
default: false,
},
uninstallFailed: {
type: Boolean,
required: false,
default: false,
},
uninstallSuccessful: {
type: Boolean,
required: false,
default: false,
},
updateAcknowledged: {
type: Boolean,
required: false,
default: true,
},
installApplicationRequestParams: { installApplicationRequestParams: {
type: Object, type: Object,
required: false, required: false,
@ -89,29 +128,12 @@ export default {
return Object.values(APPLICATION_STATUS).includes(this.status); return Object.values(APPLICATION_STATUS).includes(this.status);
}, },
isInstalling() { isInstalling() {
return ( return this.status === APPLICATION_STATUS.INSTALLING;
this.status === APPLICATION_STATUS.SCHEDULED ||
this.status === APPLICATION_STATUS.INSTALLING ||
(this.requestStatus === REQUEST_SUBMITTED && !this.statusReason && !this.isInstalled)
);
},
isInstalled() {
return (
this.status === APPLICATION_STATUS.INSTALLED ||
this.status === APPLICATION_STATUS.UPDATED ||
this.status === APPLICATION_STATUS.UPDATING ||
this.status === APPLICATION_STATUS.UPDATE_ERRORED
);
}, },
canInstall() { canInstall() {
if (this.isInstalling) {
return false;
}
return ( return (
this.status === APPLICATION_STATUS.NOT_INSTALLABLE || this.status === APPLICATION_STATUS.NOT_INSTALLABLE ||
this.status === APPLICATION_STATUS.INSTALLABLE || this.status === APPLICATION_STATUS.INSTALLABLE ||
this.status === APPLICATION_STATUS.ERROR ||
this.isUnknownStatus this.isUnknownStatus
); );
}, },
@ -125,8 +147,14 @@ export default {
rowJsClass() { rowJsClass() {
return `js-cluster-application-row-${this.id}`; return `js-cluster-application-row-${this.id}`;
}, },
displayUninstallButton() {
return this.installed && this.uninstallable;
},
displayInstallButton() {
return !this.installed || !this.uninstallable;
},
installButtonLoading() { installButtonLoading() {
return !this.status || this.status === APPLICATION_STATUS.SCHEDULED || this.isInstalling; return !this.status || this.isInstalling;
}, },
installButtonDisabled() { installButtonDisabled() {
// Avoid the potential for the real-time data to say APPLICATION_STATUS.INSTALLABLE but // Avoid the potential for the real-time data to say APPLICATION_STATUS.INSTALLABLE but
@ -145,7 +173,7 @@ export default {
label = s__('ClusterIntegration|Install'); label = s__('ClusterIntegration|Install');
} else if (this.isInstalling) { } else if (this.isInstalling) {
label = s__('ClusterIntegration|Installing'); label = s__('ClusterIntegration|Installing');
} else if (this.isInstalled) { } else if (this.installed) {
label = s__('ClusterIntegration|Installed'); label = s__('ClusterIntegration|Installed');
} }
@ -158,18 +186,23 @@ export default {
return s__('ClusterIntegration|Manage'); return s__('ClusterIntegration|Manage');
}, },
hasError() { hasError() {
return ( return this.installFailed || this.uninstallFailed;
!this.isInstalling &&
(this.status === APPLICATION_STATUS.ERROR || this.requestStatus === REQUEST_FAILURE)
);
}, },
generalErrorDescription() { generalErrorDescription() {
return sprintf(s__('ClusterIntegration|Something went wrong while installing %{title}'), { let errorDescription;
title: this.title,
}); if (this.installFailed) {
errorDescription = s__('ClusterIntegration|Something went wrong while installing %{title}');
} else if (this.uninstallFailed) {
errorDescription = s__(
'ClusterIntegration|Something went wrong while uninstalling %{title}',
);
}
return sprintf(errorDescription, { title: this.title });
}, },
versionLabel() { versionLabel() {
if (this.upgradeFailed) { if (this.updateFailed) {
return s__('ClusterIntegration|Upgrade failed'); return s__('ClusterIntegration|Upgrade failed');
} else if (this.isUpgrading) { } else if (this.isUpgrading) {
return s__('ClusterIntegration|Upgrading'); return s__('ClusterIntegration|Upgrading');
@ -177,19 +210,6 @@ export default {
return s__('ClusterIntegration|Upgraded'); return s__('ClusterIntegration|Upgraded');
}, },
upgradeRequested() {
return this.requestStatus === UPGRADE_REQUESTED;
},
upgradeSuccessful() {
return this.status === APPLICATION_STATUS.UPDATED;
},
upgradeFailed() {
if (this.isUpgrading) {
return false;
}
return this.status === APPLICATION_STATUS.UPDATE_ERRORED;
},
upgradeFailureDescription() { upgradeFailureDescription() {
return s__('ClusterIntegration|Update failed. Please check the logs and try again.'); return s__('ClusterIntegration|Update failed. Please check the logs and try again.');
}, },
@ -200,11 +220,11 @@ export default {
}, },
upgradeButtonLabel() { upgradeButtonLabel() {
let label; let label;
if (this.upgradeAvailable && !this.upgradeFailed && !this.isUpgrading) { if (this.upgradeAvailable && !this.updateFailed && !this.isUpgrading) {
label = s__('ClusterIntegration|Upgrade'); label = s__('ClusterIntegration|Upgrade');
} else if (this.isUpgrading) { } else if (this.isUpgrading) {
label = s__('ClusterIntegration|Updating'); label = s__('ClusterIntegration|Updating');
} else if (this.upgradeFailed) { } else if (this.updateFailed) {
label = s__('ClusterIntegration|Retry update'); label = s__('ClusterIntegration|Retry update');
} }
@ -212,24 +232,29 @@ export default {
}, },
isUpgrading() { isUpgrading() {
// Since upgrading is handled asynchronously on the backend we need this check to prevent any delay on the frontend // Since upgrading is handled asynchronously on the backend we need this check to prevent any delay on the frontend
return ( return this.status === APPLICATION_STATUS.UPDATING;
this.status === APPLICATION_STATUS.UPDATING ||
(this.upgradeRequested && !this.upgradeSuccessful)
);
}, },
shouldShowUpgradeDetails() { shouldShowUpgradeDetails() {
// This method only returns true when; // This method only returns true when;
// Upgrade was successful OR Upgrade failed // Upgrade was successful OR Upgrade failed
// AND new upgrade is unavailable AND version information is present. // AND new upgrade is unavailable AND version information is present.
return ( return (this.updateSuccessful || this.updateFailed) && !this.upgradeAvailable && this.version;
(this.upgradeSuccessful || this.upgradeFailed) && !this.upgradeAvailable && this.version },
); uninstallSuccessDescription() {
return sprintf(s__('ClusterIntegration|%{title} uninstalled successfully.'), {
title: this.title,
});
}, },
}, },
watch: { watch: {
status() { updateSuccessful(updateSuccessful) {
if (this.status === APPLICATION_STATUS.UPDATE_ERRORED) { if (updateSuccessful) {
eventHub.$emit('upgradeFailed', this.id); this.$toast.show(this.upgradeSuccessDescription);
}
},
uninstallSuccessful(uninstallSuccessful) {
if (uninstallSuccessful) {
this.$toast.show(this.uninstallSuccessDescription);
} }
}, },
}, },
@ -246,8 +271,10 @@ export default {
params: this.installApplicationRequestParams, params: this.installApplicationRequestParams,
}); });
}, },
dismissUpgradeSuccess() { uninstallConfirmed() {
eventHub.$emit('dismissUpgradeSuccess', this.id); eventHub.$emit('uninstallApplication', {
id: this.id,
});
}, },
}, },
}; };
@ -257,7 +284,7 @@ export default {
<div <div
:class="[ :class="[
rowJsClass, rowJsClass,
isInstalled && 'cluster-application-installed', installed && 'cluster-application-installed',
disabled && 'cluster-application-disabled', disabled && 'cluster-application-disabled',
]" ]"
class="cluster-application-row gl-responsive-table-row gl-responsive-table-row-col-span" class="cluster-application-row gl-responsive-table-row gl-responsive-table-row-col-span"
@ -280,16 +307,12 @@ export default {
target="blank" target="blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="js-cluster-application-title" class="js-cluster-application-title"
>{{ title }}</a
> >
{{ title }} <span v-else class="js-cluster-application-title">{{ title }}</span>
</a>
<span v-else class="js-cluster-application-title"> {{ title }} </span>
</strong> </strong>
<slot name="description"></slot> <slot name="description"></slot>
<div <div v-if="hasError" class="cluster-application-error text-danger prepend-top-10">
v-if="hasError || isUnknownStatus"
class="cluster-application-error text-danger prepend-top-10"
>
<p class="js-cluster-application-general-error-message append-bottom-0"> <p class="js-cluster-application-general-error-message append-bottom-0">
{{ generalErrorDescription }} {{ generalErrorDescription }}
</p> </p>
@ -308,39 +331,25 @@ export default {
class="form-text text-muted label p-0 js-cluster-application-upgrade-details" class="form-text text-muted label p-0 js-cluster-application-upgrade-details"
> >
{{ versionLabel }} {{ versionLabel }}
<span v-if="updateSuccessful">to</span>
<span v-if="upgradeSuccessful"> to</span>
<gl-link <gl-link
v-if="upgradeSuccessful" v-if="updateSuccessful"
:href="chartRepo" :href="chartRepo"
target="_blank" target="_blank"
class="js-cluster-application-upgrade-version" class="js-cluster-application-upgrade-version"
>chart v{{ version }}</gl-link
> >
chart v{{ version }}
</gl-link>
</div> </div>
<div <div
v-if="upgradeFailed && !isUpgrading" v-if="updateFailed && !isUpgrading"
class="bs-callout bs-callout-danger cluster-application-banner mt-2 mb-0 js-cluster-application-upgrade-failure-message" class="bs-callout bs-callout-danger cluster-application-banner mt-2 mb-0 js-cluster-application-upgrade-failure-message"
> >
{{ upgradeFailureDescription }} {{ upgradeFailureDescription }}
</div> </div>
<div
v-if="upgradeRequested && upgradeSuccessful"
class="bs-callout bs-callout-success cluster-application-banner mt-2 mb-0 p-0 pl-3"
>
{{ upgradeSuccessDescription }}
<button class="close cluster-application-banner-close" @click="dismissUpgradeSuccess">
&times;
</button>
</div>
<loading-button <loading-button
v-if="upgradeAvailable || upgradeFailed || isUpgrading" v-if="upgradeAvailable || updateFailed || isUpgrading"
class="btn btn-primary js-cluster-application-upgrade-button mt-2" class="btn btn-primary js-cluster-application-upgrade-button mt-2"
:loading="isUpgrading" :loading="isUpgrading"
:disabled="isUpgrading" :disabled="isUpgrading"
@ -354,18 +363,30 @@ export default {
role="gridcell" role="gridcell"
> >
<div v-if="showManageButton" class="btn-group table-action-buttons"> <div v-if="showManageButton" class="btn-group table-action-buttons">
<a :href="manageLink" :class="{ disabled: disabled }" class="btn"> <a :href="manageLink" :class="{ disabled: disabled }" class="btn">{{
{{ manageButtonLabel }} manageButtonLabel
</a> }}</a>
</div> </div>
<div class="btn-group table-action-buttons"> <div class="btn-group table-action-buttons">
<loading-button <loading-button
v-if="displayInstallButton"
:loading="installButtonLoading" :loading="installButtonLoading"
:disabled="disabled || installButtonDisabled" :disabled="disabled || installButtonDisabled"
:label="installButtonLabel" :label="installButtonLabel"
class="js-cluster-application-install-button" class="js-cluster-application-install-button"
@click="installClicked" @click="installClicked"
/> />
<uninstall-application-button
v-if="displayUninstallButton"
v-gl-modal-directive="'uninstall-' + id"
:status="status"
class="js-cluster-application-uninstall-button"
/>
<uninstall-application-confirmation-modal
:application="id"
:application-title="title"
@confirm="uninstallConfirmed()"
/>
</div> </div>
</div> </div>
</div> </div>

View file

@ -224,9 +224,9 @@ export default {
<p class="append-bottom-0"> <p class="append-bottom-0">
{{ {{
s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster. s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster.
Helm Tiller is required to install any of the following applications.`) Helm Tiller is required to install any of the following applications.`)
}} }}
<a :href="helpPath"> {{ __('More information') }} </a> <a :href="helpPath">{{ __('More information') }}</a>
</p> </p>
<div class="cluster-application-list prepend-top-10"> <div class="cluster-application-list prepend-top-10">
@ -238,15 +238,20 @@ export default {
:status-reason="applications.helm.statusReason" :status-reason="applications.helm.statusReason"
:request-status="applications.helm.requestStatus" :request-status="applications.helm.requestStatus"
:request-reason="applications.helm.requestReason" :request-reason="applications.helm.requestReason"
:installed="applications.helm.installed"
:install-failed="applications.helm.installFailed"
:uninstallable="applications.helm.uninstallable"
:uninstall-successful="applications.helm.uninstallSuccessful"
:uninstall-failed="applications.helm.uninstallFailed"
class="rounded-top" class="rounded-top"
title-link="https://docs.helm.sh/" title-link="https://docs.helm.sh/"
> >
<div slot="description"> <div slot="description">
{{ {{
s__(`ClusterIntegration|Helm streamlines installing s__(`ClusterIntegration|Helm streamlines installing
and managing Kubernetes applications. and managing Kubernetes applications.
Tiller runs inside of your Kubernetes Cluster, Tiller runs inside of your Kubernetes Cluster,
and manages releases of your charts.`) and manages releases of your charts.`)
}} }}
</div> </div>
</application-row> </application-row>
@ -254,7 +259,7 @@ export default {
<div class="svg-container" v-html="helmInstallIllustration"></div> <div class="svg-container" v-html="helmInstallIllustration"></div>
{{ {{
s__(`ClusterIntegration|You must first install Helm Tiller before s__(`ClusterIntegration|You must first install Helm Tiller before
installing the applications below`) installing the applications below`)
}} }}
</div> </div>
<application-row <application-row
@ -265,6 +270,11 @@ export default {
:status-reason="applications.ingress.statusReason" :status-reason="applications.ingress.statusReason"
:request-status="applications.ingress.requestStatus" :request-status="applications.ingress.requestStatus"
:request-reason="applications.ingress.requestReason" :request-reason="applications.ingress.requestReason"
:installed="applications.ingress.installed"
:install-failed="applications.ingress.installFailed"
:uninstallable="applications.ingress.uninstallable"
:uninstall-successful="applications.ingress.uninstallSuccessful"
:uninstall-failed="applications.ingress.uninstallFailed"
:disabled="!helmInstalled" :disabled="!helmInstalled"
title-link="https://kubernetes.io/docs/concepts/services-networking/ingress/" title-link="https://kubernetes.io/docs/concepts/services-networking/ingress/"
> >
@ -272,16 +282,14 @@ export default {
<p> <p>
{{ {{
s__(`ClusterIntegration|Ingress gives you a way to route s__(`ClusterIntegration|Ingress gives you a way to route
requests to services based on the request host or path, requests to services based on the request host or path,
centralizing a number of services into a single entrypoint.`) centralizing a number of services into a single entrypoint.`)
}} }}
</p> </p>
<template v-if="ingressInstalled"> <template v-if="ingressInstalled">
<div class="form-group"> <div class="form-group">
<label for="ingress-endpoint"> <label for="ingress-endpoint">{{ s__('ClusterIntegration|Ingress Endpoint') }}</label>
{{ s__('ClusterIntegration|Ingress Endpoint') }}
</label>
<div v-if="ingressExternalEndpoint" class="input-group"> <div v-if="ingressExternalEndpoint" class="input-group">
<input <input
id="ingress-endpoint" id="ingress-endpoint"
@ -307,25 +315,24 @@ export default {
<p class="form-text text-muted"> <p class="form-text text-muted">
{{ {{
s__(`ClusterIntegration|Point a wildcard DNS to this s__(`ClusterIntegration|Point a wildcard DNS to this
generated endpoint in order to access generated endpoint in order to access
your application after it has been deployed.`) your application after it has been deployed.`)
}} }}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">{{
{{ __('More information') }} __('More information')
</a> }}</a>
</p> </p>
</div> </div>
<p v-if="!ingressExternalEndpoint" class="settings-message js-no-endpoint-message"> <p v-if="!ingressExternalEndpoint" class="settings-message js-no-endpoint-message">
{{ {{
s__(`ClusterIntegration|The endpoint is in s__(`ClusterIntegration|The endpoint is in
the process of being assigned. Please check your Kubernetes the process of being assigned. Please check your Kubernetes
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}} }}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">{{
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> __('More information')
{{ __('More information') }} }}</a>
</a>
</p> </p>
</template> </template>
<template v-if="!ingressInstalled"> <template v-if="!ingressInstalled">
@ -341,7 +348,12 @@ export default {
:status-reason="applications.cert_manager.statusReason" :status-reason="applications.cert_manager.statusReason"
:request-status="applications.cert_manager.requestStatus" :request-status="applications.cert_manager.requestStatus"
:request-reason="applications.cert_manager.requestReason" :request-reason="applications.cert_manager.requestReason"
:installed="applications.cert_manager.installed"
:install-failed="applications.cert_manager.installFailed"
:install-application-request-params="{ email: applications.cert_manager.email }" :install-application-request-params="{ email: applications.cert_manager.email }"
:uninstallable="applications.cert_manager.uninstallable"
:uninstall-successful="applications.cert_manager.uninstallSuccessful"
:uninstall-failed="applications.cert_manager.uninstallFailed"
:disabled="!helmInstalled" :disabled="!helmInstalled"
title-link="https://cert-manager.readthedocs.io/en/latest/#" title-link="https://cert-manager.readthedocs.io/en/latest/#"
> >
@ -349,9 +361,9 @@ export default {
<div slot="description"> <div slot="description">
<p v-html="certManagerDescription"></p> <p v-html="certManagerDescription"></p>
<div class="form-group"> <div class="form-group">
<label for="cert-manager-issuer-email"> <label for="cert-manager-issuer-email">{{
{{ s__('ClusterIntegration|Issuer Email') }} s__('ClusterIntegration|Issuer Email')
</label> }}</label>
<div class="input-group"> <div class="input-group">
<input <input
v-model="applications.cert_manager.email" v-model="applications.cert_manager.email"
@ -363,22 +375,20 @@ export default {
<p class="form-text text-muted"> <p class="form-text text-muted">
{{ {{
s__(`ClusterIntegration|Issuers represent a certificate authority. s__(`ClusterIntegration|Issuers represent a certificate authority.
You must provide an email address for your Issuer. `) You must provide an email address for your Issuer. `)
}} }}
<a <a
href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email" href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
>{{ __('More information') }}</a
> >
{{ __('More information') }}
</a>
</p> </p>
</div> </div>
</div> </div>
</template> </template>
</application-row> </application-row>
<application-row <application-row
v-if="isProjectCluster"
id="prometheus" id="prometheus"
:logo-url="prometheusLogo" :logo-url="prometheusLogo"
:title="applications.prometheus.title" :title="applications.prometheus.title"
@ -387,6 +397,11 @@ export default {
:status-reason="applications.prometheus.statusReason" :status-reason="applications.prometheus.statusReason"
:request-status="applications.prometheus.requestStatus" :request-status="applications.prometheus.requestStatus"
:request-reason="applications.prometheus.requestReason" :request-reason="applications.prometheus.requestReason"
:installed="applications.prometheus.installed"
:install-failed="applications.prometheus.installFailed"
:uninstallable="applications.prometheus.uninstallable"
:uninstall-successful="applications.prometheus.uninstallSuccessful"
:uninstall-failed="applications.prometheus.uninstallFailed"
:disabled="!helmInstalled" :disabled="!helmInstalled"
title-link="https://prometheus.io/docs/introduction/overview/" title-link="https://prometheus.io/docs/introduction/overview/"
> >
@ -403,15 +418,22 @@ export default {
:version="applications.runner.version" :version="applications.runner.version"
:chart-repo="applications.runner.chartRepo" :chart-repo="applications.runner.chartRepo"
:upgrade-available="applications.runner.upgradeAvailable" :upgrade-available="applications.runner.upgradeAvailable"
:installed="applications.runner.installed"
:install-failed="applications.runner.installFailed"
:update-successful="applications.runner.updateSuccessful"
:update-failed="applications.runner.updateFailed"
:uninstallable="applications.runner.uninstallable"
:uninstall-successful="applications.runner.uninstallSuccessful"
:uninstall-failed="applications.runner.uninstallFailed"
:disabled="!helmInstalled" :disabled="!helmInstalled"
title-link="https://docs.gitlab.com/runner/" title-link="https://docs.gitlab.com/runner/"
> >
<div slot="description"> <div slot="description">
{{ {{
s__(`ClusterIntegration|GitLab Runner connects to the s__(`ClusterIntegration|GitLab Runner connects to the
repository and executes CI/CD jobs, repository and executes CI/CD jobs,
pushing results back and deploying pushing results back and deploying
applications to production.`) applications to production.`)
}} }}
</div> </div>
</application-row> </application-row>
@ -424,6 +446,11 @@ export default {
:status-reason="applications.jupyter.statusReason" :status-reason="applications.jupyter.statusReason"
:request-status="applications.jupyter.requestStatus" :request-status="applications.jupyter.requestStatus"
:request-reason="applications.jupyter.requestReason" :request-reason="applications.jupyter.requestReason"
:installed="applications.jupyter.installed"
:install-failed="applications.jupyter.installFailed"
:uninstallable="applications.jupyter.uninstallable"
:uninstall-successful="applications.jupyter.uninstallSuccessful"
:uninstall-failed="applications.jupyter.uninstallFailed"
:install-application-request-params="{ hostname: applications.jupyter.hostname }" :install-application-request-params="{ hostname: applications.jupyter.hostname }"
:disabled="!helmInstalled" :disabled="!helmInstalled"
title-link="https://jupyterhub.readthedocs.io/en/stable/" title-link="https://jupyterhub.readthedocs.io/en/stable/"
@ -432,18 +459,16 @@ export default {
<p> <p>
{{ {{
s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns, s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns,
manages, and proxies multiple instances of the single-user manages, and proxies multiple instances of the single-user
Jupyter notebook server. JupyterHub can be used to serve Jupyter notebook server. JupyterHub can be used to serve
notebooks to a class of students, a corporate data science group, notebooks to a class of students, a corporate data science group,
or a scientific research group.`) or a scientific research group.`)
}} }}
</p> </p>
<template v-if="ingressExternalEndpoint"> <template v-if="ingressExternalEndpoint">
<div class="form-group"> <div class="form-group">
<label for="jupyter-hostname"> <label for="jupyter-hostname">{{ s__('ClusterIntegration|Jupyter Hostname') }}</label>
{{ s__('ClusterIntegration|Jupyter Hostname') }}
</label>
<div class="input-group"> <div class="input-group">
<input <input
@ -464,11 +489,11 @@ export default {
<p v-if="ingressInstalled" class="form-text text-muted"> <p v-if="ingressInstalled" class="form-text text-muted">
{{ {{
s__(`ClusterIntegration|Replace this with your own hostname if you want. s__(`ClusterIntegration|Replace this with your own hostname if you want.
If you do so, point hostname to Ingress IP Address from above.`) If you do so, point hostname to Ingress IP Address from above.`)
}} }}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">{{
{{ __('More information') }} __('More information')
</a> }}</a>
</p> </p>
</div> </div>
</template> </template>
@ -483,8 +508,14 @@ export default {
:status-reason="applications.knative.statusReason" :status-reason="applications.knative.statusReason"
:request-status="applications.knative.requestStatus" :request-status="applications.knative.requestStatus"
:request-reason="applications.knative.requestReason" :request-reason="applications.knative.requestReason"
:installed="applications.knative.installed"
:install-failed="applications.knative.installFailed"
:install-application-request-params="{ hostname: applications.knative.hostname }" :install-application-request-params="{ hostname: applications.knative.hostname }"
:uninstallable="applications.knative.uninstallable"
:uninstall-successful="applications.knative.uninstallSuccessful"
:uninstall-failed="applications.knative.uninstallFailed"
:disabled="!helmInstalled" :disabled="!helmInstalled"
v-bind="applications.knative"
title-link="https://github.com/knative/docs" title-link="https://github.com/knative/docs"
> >
<div slot="description"> <div slot="description">
@ -492,20 +523,20 @@ export default {
<p v-if="!rbac" class="rbac-notice bs-callout bs-callout-info append-bottom-0"> <p v-if="!rbac" class="rbac-notice bs-callout bs-callout-info append-bottom-0">
{{ {{
s__(`ClusterIntegration|You must have an RBAC-enabled cluster s__(`ClusterIntegration|You must have an RBAC-enabled cluster
to install Knative.`) to install Knative.`)
}} }}
<a :href="helpPath" target="_blank" rel="noopener noreferrer"> <a :href="helpPath" target="_blank" rel="noopener noreferrer">{{
{{ __('More information') }} __('More information')
</a> }}</a>
</p> </p>
<br /> <br />
</span> </span>
<p> <p>
{{ {{
s__(`ClusterIntegration|Knative extends Kubernetes to provide s__(`ClusterIntegration|Knative extends Kubernetes to provide
a set of middleware components that are essential to build modern, a set of middleware components that are essential to build modern,
source-centric, and container-based applications that can run source-centric, and container-based applications that can run
anywhere: on premises, in the cloud, or even in a third-party data center.`) anywhere: on premises, in the cloud, or even in a third-party data center.`)
}} }}
</p> </p>
@ -516,9 +547,7 @@ export default {
class="form-group col-sm-12 mb-0" class="form-group col-sm-12 mb-0"
> >
<label for="knative-domainname"> <label for="knative-domainname">
<strong> <strong>{{ s__('ClusterIntegration|Knative Domain Name:') }}</strong>
{{ s__('ClusterIntegration|Knative Domain Name:') }}
</strong>
</label> </label>
<input <input
id="knative-domainname" id="knative-domainname"
@ -531,9 +560,7 @@ export default {
<template v-if="knativeInstalled"> <template v-if="knativeInstalled">
<div class="form-group col-sm-12 col-md-6 pl-md-0 mb-0 mt-3 mt-md-0"> <div class="form-group col-sm-12 col-md-6 pl-md-0 mb-0 mt-3 mt-md-0">
<label for="knative-endpoint"> <label for="knative-endpoint">
<strong> <strong>{{ s__('ClusterIntegration|Knative Endpoint:') }}</strong>
{{ s__('ClusterIntegration|Knative Endpoint:') }}
</strong>
</label> </label>
<div v-if="knativeExternalEndpoint" class="input-group"> <div v-if="knativeExternalEndpoint" class="input-group">
<input <input
@ -565,9 +592,9 @@ export default {
`ClusterIntegration|To access your application after deployment, point a wildcard DNS to the Knative Endpoint.`, `ClusterIntegration|To access your application after deployment, point a wildcard DNS to the Knative Endpoint.`,
) )
}} }}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">{{
{{ __('More information') }} __('More information')
</a> }}</a>
</p> </p>
<p <p
@ -576,8 +603,8 @@ export default {
> >
{{ {{
s__(`ClusterIntegration|The endpoint is in s__(`ClusterIntegration|The endpoint is in
the process of being assigned. Please check your Kubernetes the process of being assigned. Please check your Kubernetes
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}} }}
</p> </p>

View file

@ -0,0 +1,33 @@
<script>
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import { APPLICATION_STATUS } from '~/clusters/constants';
const { UPDATING, UNINSTALLING } = APPLICATION_STATUS;
export default {
components: {
LoadingButton,
},
props: {
status: {
type: String,
required: true,
},
},
computed: {
disabled() {
return [UNINSTALLING, UPDATING].includes(this.status);
},
loading() {
return this.status === UNINSTALLING;
},
label() {
return this.loading ? this.__('Uninstalling') : this.__('Uninstall');
},
},
};
</script>
<template>
<loading-button :label="label" :disabled="disabled" :loading="loading" />
</template>

View file

@ -0,0 +1,74 @@
<script>
import { GlModal } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
import trackUninstallButtonClickMixin from 'ee_else_ce/clusters/mixins/track_uninstall_button_click';
import { INGRESS, CERT_MANAGER, PROMETHEUS, RUNNER, KNATIVE, JUPYTER } from '../constants';
const CUSTOM_APP_WARNING_TEXT = {
[INGRESS]: s__(
'ClusterIntegration|The associated load balancer and IP will be deleted and cannot be restored.',
),
[CERT_MANAGER]: s__(
'ClusterIntegration|The associated certifcate will be deleted and cannot be restored.',
),
[PROMETHEUS]: s__('ClusterIntegration|All data will be deleted and cannot be restored.'),
[RUNNER]: s__('ClusterIntegration|Any running pipelines will be canceled.'),
[KNATIVE]: s__('ClusterIntegration|The associated IP will be deleted and cannot be restored.'),
[JUPYTER]: '',
};
export default {
components: {
GlModal,
},
mixins: [trackUninstallButtonClickMixin],
props: {
application: {
type: String,
required: true,
},
applicationTitle: {
type: String,
required: true,
},
},
computed: {
title() {
return sprintf(s__('ClusterIntegration|Uninstall %{appTitle}'), {
appTitle: this.applicationTitle,
});
},
warningText() {
return sprintf(
s__('ClusterIntegration|You are about to uninstall %{appTitle} from your cluster.'),
{
appTitle: this.applicationTitle,
},
);
},
customAppWarningText() {
return CUSTOM_APP_WARNING_TEXT[this.application];
},
modalId() {
return `uninstall-${this.application}`;
},
},
methods: {
confirmUninstall() {
this.trackUninstallButtonClick(this.application);
this.$emit('confirm');
},
},
};
</script>
<template>
<gl-modal
ok-variant="danger"
cancel-variant="light"
:ok-title="title"
:modal-id="modalId"
:title="title"
@ok="confirmUninstall()"
>{{ warningText }} {{ customAppWarningText }}</gl-modal
>
</template>

View file

@ -7,6 +7,7 @@ export const CLUSTER_TYPE = {
// These need to match what is returned from the server // These need to match what is returned from the server
export const APPLICATION_STATUS = { export const APPLICATION_STATUS = {
NO_STATUS: null,
NOT_INSTALLABLE: 'not_installable', NOT_INSTALLABLE: 'not_installable',
INSTALLABLE: 'installable', INSTALLABLE: 'installable',
SCHEDULED: 'scheduled', SCHEDULED: 'scheduled',
@ -15,17 +16,35 @@ export const APPLICATION_STATUS = {
UPDATING: 'updating', UPDATING: 'updating',
UPDATED: 'updated', UPDATED: 'updated',
UPDATE_ERRORED: 'update_errored', UPDATE_ERRORED: 'update_errored',
UNINSTALLING: 'uninstalling',
UNINSTALL_ERRORED: 'uninstall_errored',
ERROR: 'errored', ERROR: 'errored',
}; };
/*
* The application cannot be in any of the following states without
* not being installed.
*/
export const APPLICATION_INSTALLED_STATUSES = [
APPLICATION_STATUS.INSTALLED,
APPLICATION_STATUS.UPDATING,
APPLICATION_STATUS.UNINSTALLING,
];
// These are only used client-side // These are only used client-side
export const REQUEST_SUBMITTED = 'request-submitted';
export const REQUEST_FAILURE = 'request-failure'; export const UPDATE_EVENT = 'update';
export const UPGRADE_REQUESTED = 'upgrade-requested'; export const INSTALL_EVENT = 'install';
export const UPGRADE_REQUEST_FAILURE = 'upgrade-request-failure'; export const UNINSTALL_EVENT = 'uninstall';
export const HELM = 'helm';
export const INGRESS = 'ingress'; export const INGRESS = 'ingress';
export const JUPYTER = 'jupyter'; export const JUPYTER = 'jupyter';
export const KNATIVE = 'knative'; export const KNATIVE = 'knative';
export const RUNNER = 'runner'; export const RUNNER = 'runner';
export const CERT_MANAGER = 'cert_manager'; export const CERT_MANAGER = 'cert_manager';
export const PROMETHEUS = 'prometheus';
export const APPLICATIONS = [HELM, INGRESS, JUPYTER, KNATIVE, RUNNER, CERT_MANAGER, PROMETHEUS];
export const INGRESS_DOMAIN_SUFFIX = '.nip.io'; export const INGRESS_DOMAIN_SUFFIX = '.nip.io';

View file

@ -0,0 +1,5 @@
export default {
methods: {
trackUninstallButtonClick: () => {},
},
};

View file

@ -0,0 +1,175 @@
import { APPLICATION_STATUS, UPDATE_EVENT, INSTALL_EVENT, UNINSTALL_EVENT } from '../constants';
const {
NO_STATUS,
SCHEDULED,
NOT_INSTALLABLE,
INSTALLABLE,
INSTALLING,
INSTALLED,
ERROR,
UPDATING,
UPDATED,
UPDATE_ERRORED,
UNINSTALLING,
UNINSTALL_ERRORED,
} = APPLICATION_STATUS;
const applicationStateMachine = {
/* When the application initially loads, it will have `NO_STATUS`
* It will transition from `NO_STATUS` once the async backend call is completed
*/
[NO_STATUS]: {
on: {
[SCHEDULED]: {
target: INSTALLING,
},
[NOT_INSTALLABLE]: {
target: NOT_INSTALLABLE,
},
[INSTALLABLE]: {
target: INSTALLABLE,
},
[INSTALLING]: {
target: INSTALLING,
},
[INSTALLED]: {
target: INSTALLED,
},
[ERROR]: {
target: INSTALLABLE,
effects: {
installFailed: true,
},
},
[UPDATING]: {
target: UPDATING,
},
[UPDATED]: {
target: INSTALLED,
},
[UPDATE_ERRORED]: {
target: INSTALLED,
effects: {
updateFailed: true,
},
},
[UNINSTALLING]: {
target: UNINSTALLING,
},
[UNINSTALL_ERRORED]: {
target: INSTALLED,
effects: {
uninstallFailed: true,
},
},
},
},
[NOT_INSTALLABLE]: {
on: {
[INSTALLABLE]: {
target: INSTALLABLE,
},
},
},
[INSTALLABLE]: {
on: {
[INSTALL_EVENT]: {
target: INSTALLING,
effects: {
installFailed: false,
},
},
// This is possible in artificial environments for E2E testing
[INSTALLED]: {
target: INSTALLED,
},
},
},
[INSTALLING]: {
on: {
[INSTALLED]: {
target: INSTALLED,
},
[ERROR]: {
target: INSTALLABLE,
effects: {
installFailed: true,
},
},
},
},
[INSTALLED]: {
on: {
[UPDATE_EVENT]: {
target: UPDATING,
effects: {
updateFailed: false,
updateSuccessful: false,
},
},
[UNINSTALL_EVENT]: {
target: UNINSTALLING,
effects: {
uninstallFailed: false,
uninstallSuccessful: false,
},
},
},
},
[UPDATING]: {
on: {
[UPDATED]: {
target: INSTALLED,
effects: {
updateSuccessful: true,
updateAcknowledged: false,
},
},
[UPDATE_ERRORED]: {
target: INSTALLED,
effects: {
updateFailed: true,
},
},
},
},
[UNINSTALLING]: {
on: {
[INSTALLABLE]: {
target: INSTALLABLE,
effects: {
uninstallSuccessful: true,
},
},
[UNINSTALL_ERRORED]: {
target: INSTALLED,
effects: {
uninstallFailed: true,
},
},
},
},
};
/**
* Determines an application new state based on the application current state
* and an event. If the application current state cannot handle a given event,
* the current state is returned.
*
* @param {*} application
* @param {*} event
*/
const transitionApplicationState = (application, event) => {
const newState = applicationStateMachine[application.status].on[event];
return newState
? {
...application,
status: newState.target,
...newState.effects,
}
: application;
};
export default transitionApplicationState;

View file

@ -29,6 +29,10 @@ export default class ClusterService {
return axios.patch(this.appUpdateEndpointMap[appId], params); return axios.patch(this.appUpdateEndpointMap[appId], params);
} }
uninstallApplication(appId, params) {
return axios.delete(this.appInstallEndpointMap[appId], params);
}
static updateCluster(endpoint, data) { static updateCluster(endpoint, data) {
return axios.put(endpoint, data); return axios.put(endpoint, data);
} }

View file

@ -1,6 +1,31 @@
import { s__ } from '../../locale'; import { s__ } from '../../locale';
import { parseBoolean } from '../../lib/utils/common_utils'; import { parseBoolean } from '../../lib/utils/common_utils';
import { INGRESS, JUPYTER, KNATIVE, CERT_MANAGER, RUNNER } from '../constants'; import {
INGRESS,
JUPYTER,
KNATIVE,
CERT_MANAGER,
RUNNER,
APPLICATION_INSTALLED_STATUSES,
APPLICATION_STATUS,
INSTALL_EVENT,
UPDATE_EVENT,
UNINSTALL_EVENT,
} from '../constants';
import transitionApplicationState from '../services/application_state_machine';
const isApplicationInstalled = appStatus => APPLICATION_INSTALLED_STATUSES.includes(appStatus);
const applicationInitialState = {
status: null,
statusReason: null,
requestReason: null,
installed: false,
installFailed: false,
uninstallable: false,
uninstallFailed: false,
uninstallSuccessful: false,
};
export default class ClusterStore { export default class ClusterStore {
constructor() { constructor() {
@ -12,60 +37,42 @@ export default class ClusterStore {
statusReason: null, statusReason: null,
applications: { applications: {
helm: { helm: {
...applicationInitialState,
title: s__('ClusterIntegration|Helm Tiller'), title: s__('ClusterIntegration|Helm Tiller'),
status: null,
statusReason: null,
requestStatus: null,
requestReason: null,
}, },
ingress: { ingress: {
...applicationInitialState,
title: s__('ClusterIntegration|Ingress'), title: s__('ClusterIntegration|Ingress'),
status: null,
statusReason: null,
requestStatus: null,
requestReason: null,
externalIp: null, externalIp: null,
externalHostname: null, externalHostname: null,
}, },
cert_manager: { cert_manager: {
...applicationInitialState,
title: s__('ClusterIntegration|Cert-Manager'), title: s__('ClusterIntegration|Cert-Manager'),
status: null,
statusReason: null,
requestStatus: null,
requestReason: null,
email: null, email: null,
}, },
runner: { runner: {
...applicationInitialState,
title: s__('ClusterIntegration|GitLab Runner'), title: s__('ClusterIntegration|GitLab Runner'),
status: null,
statusReason: null,
requestStatus: null,
requestReason: null,
version: null, version: null,
chartRepo: 'https://gitlab.com/charts/gitlab-runner', chartRepo: 'https://gitlab.com/charts/gitlab-runner',
upgradeAvailable: null, upgradeAvailable: null,
updateAcknowledged: true,
updateSuccessful: false,
updateFailed: false,
}, },
prometheus: { prometheus: {
...applicationInitialState,
title: s__('ClusterIntegration|Prometheus'), title: s__('ClusterIntegration|Prometheus'),
status: null,
statusReason: null,
requestStatus: null,
requestReason: null,
}, },
jupyter: { jupyter: {
...applicationInitialState,
title: s__('ClusterIntegration|JupyterHub'), title: s__('ClusterIntegration|JupyterHub'),
status: null,
statusReason: null,
requestStatus: null,
requestReason: null,
hostname: null, hostname: null,
}, },
knative: { knative: {
...applicationInitialState,
title: s__('ClusterIntegration|Knative'), title: s__('ClusterIntegration|Knative'),
status: null,
statusReason: null,
requestStatus: null,
requestReason: null,
hostname: null, hostname: null,
isEditingHostName: false, isEditingHostName: false,
externalIp: null, externalIp: null,
@ -97,6 +104,40 @@ export default class ClusterStore {
this.state.statusReason = reason; this.state.statusReason = reason;
} }
installApplication(appId) {
this.handleApplicationEvent(appId, INSTALL_EVENT);
}
notifyInstallFailure(appId) {
this.handleApplicationEvent(appId, APPLICATION_STATUS.ERROR);
}
updateApplication(appId) {
this.handleApplicationEvent(appId, UPDATE_EVENT);
}
notifyUpdateFailure(appId) {
this.handleApplicationEvent(appId, APPLICATION_STATUS.UPDATE_ERRORED);
}
uninstallApplication(appId) {
this.handleApplicationEvent(appId, UNINSTALL_EVENT);
}
notifyUninstallFailure(appId) {
this.handleApplicationEvent(appId, APPLICATION_STATUS.UNINSTALL_ERRORED);
}
handleApplicationEvent(appId, event) {
const currentAppState = this.state.applications[appId];
this.state.applications[appId] = transitionApplicationState(currentAppState, event);
}
acknowledgeSuccessfulUpdate(appId) {
this.state.applications[appId].updateAcknowledged = true;
}
updateAppProperty(appId, prop, value) { updateAppProperty(appId, prop, value) {
this.state.applications[appId][prop] = value; this.state.applications[appId][prop] = value;
} }
@ -112,12 +153,17 @@ export default class ClusterStore {
status_reason: statusReason, status_reason: statusReason,
version, version,
update_available: upgradeAvailable, update_available: upgradeAvailable,
can_uninstall: uninstallable,
} = serverAppEntry; } = serverAppEntry;
const currentApplicationState = this.state.applications[appId] || {};
const nextApplicationState = transitionApplicationState(currentApplicationState, status);
this.state.applications[appId] = { this.state.applications[appId] = {
...(this.state.applications[appId] || {}), ...currentApplicationState,
status, ...nextApplicationState,
statusReason, statusReason,
installed: isApplicationInstalled(nextApplicationState.status),
uninstallable,
}; };
if (appId === INGRESS) { if (appId === INGRESS) {

View file

@ -12,6 +12,7 @@ import stageStagingComponent from './components/stage_staging_component.vue';
import stageTestComponent from './components/stage_test_component.vue'; import stageTestComponent from './components/stage_test_component.vue';
import CycleAnalyticsService from './cycle_analytics_service'; import CycleAnalyticsService from './cycle_analytics_service';
import CycleAnalyticsStore from './cycle_analytics_store'; import CycleAnalyticsStore from './cycle_analytics_store';
import { __ } from '~/locale';
Vue.use(Translate); Vue.use(Translate);
@ -61,7 +62,7 @@ export default () => {
methods: { methods: {
handleError() { handleError() {
this.store.setErrorState(true); this.store.setErrorState(true);
return new Flash('There was an error while fetching cycle analytics data.'); return new Flash(__('There was an error while fetching cycle analytics data.'));
}, },
initDropdown() { initDropdown() {
const $dropdown = $('.js-ca-dropdown'); const $dropdown = $('.js-ca-dropdown');

View file

@ -3,6 +3,7 @@
import $ from 'jquery'; import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import { __ } from '~/locale';
const CommentAndResolveBtn = Vue.extend({ const CommentAndResolveBtn = Vue.extend({
props: { props: {
@ -31,15 +32,15 @@ const CommentAndResolveBtn = Vue.extend({
buttonText: function() { buttonText: function() {
if (this.isDiscussionResolved) { if (this.isDiscussionResolved) {
if (this.textareaIsEmpty) { if (this.textareaIsEmpty) {
return 'Unresolve discussion'; return __('Unresolve discussion');
} else { } else {
return 'Comment & unresolve discussion'; return __('Comment & unresolve discussion');
} }
} else { } else {
if (this.textareaIsEmpty) { if (this.textareaIsEmpty) {
return 'Resolve discussion'; return __('Resolve discussion');
} else { } else {
return 'Comment & resolve discussion'; return __('Comment & resolve discussion');
} }
} }
}, },

View file

@ -5,6 +5,7 @@ import Vue from 'vue';
import collapseIcon from '../icons/collapse_icon.svg'; import collapseIcon from '../icons/collapse_icon.svg';
import Notes from '../../notes'; import Notes from '../../notes';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
import { n__ } from '~/locale';
const DiffNoteAvatars = Vue.extend({ const DiffNoteAvatars = Vue.extend({
components: { components: {
@ -44,7 +45,7 @@ const DiffNoteAvatars = Vue.extend({
if (this.discussion) { if (this.discussion) {
const extra = this.discussion.notesCount() - this.shownAvatars; const extra = this.discussion.notesCount() - this.shownAvatars;
return `${extra} more comment${extra > 1 ? 's' : ''}`; return n__('%d more comment', '%d more comments', extra);
} }
return ''; return '';

View file

@ -3,6 +3,7 @@
import $ from 'jquery'; import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import { __ } from '~/locale';
import DiscussionMixins from '../mixins/discussion'; import DiscussionMixins from '../mixins/discussion';
@ -23,9 +24,9 @@ const JumpToDiscussion = Vue.extend({
computed: { computed: {
buttonText: function() { buttonText: function() {
if (this.discussionId) { if (this.discussionId) {
return 'Jump to next unresolved discussion'; return __('Jump to next unresolved discussion');
} else { } else {
return 'Jump to first unresolved discussion'; return __('Jump to first unresolved discussion');
} }
}, },
allResolved: function() { allResolved: function() {

View file

@ -4,6 +4,7 @@
import $ from 'jquery'; import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import Flash from '../../flash'; import Flash from '../../flash';
import { sprintf, __ } from '~/locale';
const ResolveBtn = Vue.extend({ const ResolveBtn = Vue.extend({
props: { props: {
@ -55,12 +56,14 @@ const ResolveBtn = Vue.extend({
}, },
buttonText() { buttonText() {
if (this.isResolved) { if (this.isResolved) {
return `Resolved by ${this.resolvedByName}`; return sprintf(__('Resolved by %{resolvedByName}'), {
resolvedByName: this.resolvedByName,
});
} else if (this.canResolve) { } else if (this.canResolve) {
return 'Mark as resolved'; return __('Mark as resolved');
} }
return 'Unable to resolve'; return __('Unable to resolve');
}, },
isResolved() { isResolved() {
if (this.note) { if (this.note) {
@ -132,7 +135,8 @@ const ResolveBtn = Vue.extend({
this.updateTooltip(); this.updateTooltip();
}) })
.catch( .catch(
() => new Flash('An error occurred when trying to resolve a comment. Please try again.'), () =>
new Flash(__('An error occurred when trying to resolve a comment. Please try again.')),
); );
}, },
}, },

View file

@ -3,6 +3,7 @@
/* global ResolveService */ /* global ResolveService */
import Vue from 'vue'; import Vue from 'vue';
import { __ } from '~/locale';
const ResolveDiscussionBtn = Vue.extend({ const ResolveDiscussionBtn = Vue.extend({
props: { props: {
@ -41,9 +42,9 @@ const ResolveDiscussionBtn = Vue.extend({
}, },
buttonText: function() { buttonText: function() {
if (this.isDiscussionResolved) { if (this.isDiscussionResolved) {
return 'Unresolve discussion'; return __('Unresolve discussion');
} else { } else {
return 'Resolve discussion'; return __('Resolve discussion');
} }
}, },
loading: function() { loading: function() {

View file

@ -3,6 +3,7 @@
import Vue from 'vue'; import Vue from 'vue';
import Flash from '../../flash'; import Flash from '../../flash';
import '../../vue_shared/vue_resource_interceptor'; import '../../vue_shared/vue_resource_interceptor';
import { __ } from '~/locale';
window.gl = window.gl || {}; window.gl = window.gl || {};
@ -49,7 +50,8 @@ class ResolveServiceClass {
discussion.updateHeadline(data); discussion.updateHeadline(data);
}) })
.catch( .catch(
() => new Flash('An error occurred when trying to resolve a discussion. Please try again.'), () =>
new Flash(__('An error occurred when trying to resolve a discussion. Please try again.')),
); );
} }

View file

@ -113,9 +113,10 @@ export default {
<commit-pipeline-status <commit-pipeline-status
v-if="commit.pipeline_status_path" v-if="commit.pipeline_status_path"
:endpoint="commit.pipeline_status_path" :endpoint="commit.pipeline_status_path"
class="d-inline-flex"
/> />
<div class="commit-sha-group"> <div class="commit-sha-group">
<div class="label label-monospace" v-text="commit.short_id"></div> <div class="label label-monospace monospace" v-text="commit.short_id"></div>
<clipboard-button <clipboard-button
:text="commit.id" :text="commit.id"
:title="__('Copy commit SHA to clipboard')" :title="__('Copy commit SHA to clipboard')"

View file

@ -1,5 +1,8 @@
<script> <script>
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import diffLineNoteFormMixin from 'ee_else_ce/notes/mixins/diff_line_note_form';
import draftCommentsMixin from 'ee_else_ce/diffs/mixins/draft_comments';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
import NotDiffableViewer from '~/vue_shared/components/diff_viewer/viewers/not_diffable.vue'; import NotDiffableViewer from '~/vue_shared/components/diff_viewer/viewers/not_diffable.vue';
import NoPreviewViewer from '~/vue_shared/components/diff_viewer/viewers/no_preview.vue'; import NoPreviewViewer from '~/vue_shared/components/diff_viewer/viewers/no_preview.vue';
@ -14,6 +17,7 @@ import { diffViewerModes } from '~/ide/constants';
export default { export default {
components: { components: {
GlLoadingIcon,
InlineDiffView, InlineDiffView,
ParallelDiffView, ParallelDiffView,
DiffViewer, DiffViewer,
@ -22,7 +26,9 @@ export default {
ImageDiffOverlay, ImageDiffOverlay,
NotDiffableViewer, NotDiffableViewer,
NoPreviewViewer, NoPreviewViewer,
DiffFileDrafts: () => import('ee_component/batch_comments/components/diff_file_drafts.vue'),
}, },
mixins: [diffLineNoteFormMixin, draftCommentsMixin],
props: { props: {
diffFile: { diffFile: {
type: Object, type: Object,
@ -58,10 +64,13 @@ export default {
return this.diffViewerMode === diffViewerModes.not_diffable; return this.diffViewerMode === diffViewerModes.not_diffable;
}, },
diffFileCommentForm() { diffFileCommentForm() {
return this.getCommentFormForDiffFile(this.diffFile.file_hash); return this.getCommentFormForDiffFile(this.diffFileHash);
}, },
showNotesContainer() { showNotesContainer() {
return this.diffFile.discussions.length || this.diffFileCommentForm; return this.imageDiscussions.length || this.diffFileCommentForm;
},
diffFileHash() {
return this.diffFile.file_hash;
}, },
}, },
methods: { methods: {
@ -101,6 +110,7 @@ export default {
:diff-lines="diffFile.parallel_diff_lines || []" :diff-lines="diffFile.parallel_diff_lines || []"
:help-page-path="helpPagePath" :help-page-path="helpPagePath"
/> />
<gl-loading-icon v-if="diffFile.renderingLines" size="md" class="mt-3" />
</template> </template>
<not-diffable-viewer v-else-if="notDiffable" /> <not-diffable-viewer v-else-if="notDiffable" />
<no-preview-viewer v-else-if="noPreview" /> <no-preview-viewer v-else-if="noPreview" />
@ -112,15 +122,15 @@ export default {
:new-sha="diffFile.diff_refs.head_sha" :new-sha="diffFile.diff_refs.head_sha"
:old-path="diffFile.old_path" :old-path="diffFile.old_path"
:old-sha="diffFile.diff_refs.base_sha" :old-sha="diffFile.diff_refs.base_sha"
:file-hash="diffFile.file_hash" :file-hash="diffFileHash"
:project-path="projectPath" :project-path="projectPath"
:a-mode="diffFile.a_mode" :a-mode="diffFile.a_mode"
:b-mode="diffFile.b_mode" :b-mode="diffFile.b_mode"
> >
<image-diff-overlay <image-diff-overlay
slot="image-overlay" slot="image-overlay"
:discussions="diffFile.discussions" :discussions="imageDiscussions"
:file-hash="diffFile.file_hash" :file-hash="diffFileHash"
:can-comment="getNoteableData.current_user.can_create_note" :can-comment="getNoteableData.current_user.can_create_note"
/> />
<div v-if="showNotesContainer" class="note-container"> <div v-if="showNotesContainer" class="note-container">
@ -131,14 +141,16 @@ export default {
:should-collapse-discussions="true" :should-collapse-discussions="true"
:render-avatar-badge="true" :render-avatar-badge="true"
/> />
<diff-file-drafts :file-hash="diffFileHash" class="diff-file-discussions" />
<note-form <note-form
v-if="diffFileCommentForm" v-if="diffFileCommentForm"
ref="noteForm" ref="noteForm"
:is-editing="false" :is-editing="false"
:save-button-title="__('Comment')" :save-button-title="__('Comment')"
class="diff-comment-form new-note discussion-form discussion-form-container" class="diff-comment-form new-note discussion-form discussion-form-container"
@handleFormUpdateAddToReview="addToReview"
@handleFormUpdate="handleSaveNote" @handleFormUpdate="handleSaveNote"
@cancelForm="closeDiffFileCommentForm(diffFile.file_hash)" @cancelForm="closeDiffFileCommentForm(diffFileHash)"
/> />
</div> </div>
</diff-viewer> </diff-viewer>

View file

@ -301,7 +301,7 @@ export default {
class="view-file js-view-file-button" class="view-file js-view-file-button"
:title="viewFileButtonText" :title="viewFileButtonText"
> >
<icon name="external-link" /> <icon name="doc-text" />
</gl-button> </gl-button>
<a <a

View file

@ -84,8 +84,6 @@ export default {
}, },
shouldShowCommentButton() { shouldShowCommentButton() {
return ( return (
this.isLoggedIn &&
this.showCommentButton &&
this.isHover && this.isHover &&
!this.isMatchLine && !this.isMatchLine &&
!this.isContextLine && !this.isContextLine &&
@ -102,6 +100,9 @@ export default {
} }
return this.showCommentButton && this.hasDiscussions; return this.showCommentButton && this.hasDiscussions;
}, },
shouldRenderCommentButton() {
return this.isLoggedIn && this.showCommentButton;
},
}, },
methods: { methods: {
...mapActions('diffs', ['loadMoreLines', 'showCommentForm', 'setHighlightedRow']), ...mapActions('diffs', ['loadMoreLines', 'showCommentForm', 'setHighlightedRow']),
@ -167,6 +168,7 @@ export default {
> >
<template v-else> <template v-else>
<button <button
v-if="shouldRenderCommentButton"
v-show="shouldShowCommentButton" v-show="shouldShowCommentButton"
type="button" type="button"
class="add-diff-note js-add-diff-note-button qa-diff-comment" class="add-diff-note js-add-diff-note-button qa-diff-comment"

View file

@ -89,17 +89,19 @@ export default {
classNameMap() { classNameMap() {
const { type } = this.line; const { type } = this.line;
return { return [
hll: this.isHighlighted, type,
[type]: type, {
[LINE_UNFOLD_CLASS_NAME]: this.isMatchLine, hll: this.isHighlighted,
[LINE_HOVER_CLASS_NAME]: [LINE_UNFOLD_CLASS_NAME]: this.isMatchLine,
this.isLoggedIn && [LINE_HOVER_CLASS_NAME]:
this.isHover && this.isLoggedIn &&
!this.isMatchLine && this.isHover &&
!this.isContextLine && !this.isMatchLine &&
!this.isMetaLine, !this.isContextLine &&
}; !this.isMetaLine,
},
];
}, },
lineNumber() { lineNumber() {
return this.lineType === OLD_LINE_TYPE ? this.line.old_line : this.line.new_line; return this.lineType === OLD_LINE_TYPE ? this.line.old_line : this.line.new_line;

View file

@ -1,6 +1,7 @@
<script> <script>
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import _ from 'underscore'; import _ from 'underscore';
import imageDiffMixin from 'ee_else_ce/diffs/mixins/image_diff';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
export default { export default {
@ -8,6 +9,7 @@ export default {
components: { components: {
Icon, Icon,
}, },
mixins: [imageDiffMixin],
props: { props: {
discussions: { discussions: {
type: [Array, Object], type: [Array, Object],
@ -48,7 +50,6 @@ export default {
}, },
}, },
methods: { methods: {
...mapActions(['toggleDiscussion']),
...mapActions('diffs', ['openDiffFileCommentForm']), ...mapActions('diffs', ['openDiffFileCommentForm']),
getImageDimensions() { getImageDimensions() {
return { return {
@ -105,15 +106,15 @@ export default {
v-for="(discussion, index) in allDiscussions" v-for="(discussion, index) in allDiscussions"
:key="discussion.id" :key="discussion.id"
:style="getPosition(discussion)" :style="getPosition(discussion)"
:class="badgeClass" :class="[badgeClass, { 'is-draft': discussion.isDraft }]"
:disabled="!shouldToggleDiscussion" :disabled="!shouldToggleDiscussion"
class="js-image-badge" class="js-image-badge"
type="button" type="button"
@click="toggleDiscussion({ discussionId: discussion.id })" @click="clickedToggle(discussion)"
> >
<icon v-if="showCommentIcon" name="image-comment-dark" /> <icon v-if="showCommentIcon" name="image-comment-dark" />
<template v-else> <template v-else>
{{ index + 1 }} {{ toggleText(discussion, index) }}
</template> </template>
</button> </button>
<button <button

View file

@ -41,7 +41,7 @@ export default {
<template> <template>
<tr v-if="shouldRender" :class="className" class="notes_holder"> <tr v-if="shouldRender" :class="className" class="notes_holder">
<td class="notes_content" colspan="3"> <td class="notes-content" colspan="3">
<div class="content"> <div class="content">
<diff-discussions <diff-discussions
v-if="line.discussions.length" v-if="line.discussions.length"

View file

@ -1,12 +1,11 @@
<script> <script>
import { mapGetters, mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import DiffTableCell from './diff_table_cell.vue'; import DiffTableCell from './diff_table_cell.vue';
import { import {
NEW_LINE_TYPE, NEW_LINE_TYPE,
OLD_LINE_TYPE, OLD_LINE_TYPE,
CONTEXT_LINE_TYPE, CONTEXT_LINE_TYPE,
CONTEXT_LINE_CLASS_NAME, CONTEXT_LINE_CLASS_NAME,
PARALLEL_DIFF_VIEW_TYPE,
LINE_POSITION_LEFT, LINE_POSITION_LEFT,
LINE_POSITION_RIGHT, LINE_POSITION_RIGHT,
} from '../constants'; } from '../constants';
@ -45,16 +44,16 @@ export default {
return this.line.line_code !== null && this.line.line_code === state.diffs.highlightedRow; return this.line.line_code !== null && this.line.line_code === state.diffs.highlightedRow;
}, },
}), }),
...mapGetters('diffs', ['isInlineView']),
isContextLine() { isContextLine() {
return this.line.type === CONTEXT_LINE_TYPE; return this.line.type === CONTEXT_LINE_TYPE;
}, },
classNameMap() { classNameMap() {
return { return [
[this.line.type]: this.line.type, this.line.type,
[CONTEXT_LINE_CLASS_NAME]: this.isContextLine, {
[PARALLEL_DIFF_VIEW_TYPE]: this.isParallelView, [CONTEXT_LINE_CLASS_NAME]: this.isContextLine,
}; },
];
}, },
inlineRowId() { inlineRowId() {
return this.line.line_code || `${this.fileHash}_${this.line.old_line}_${this.line.new_line}`; return this.line.line_code || `${this.fileHash}_${this.line.old_line}_${this.line.new_line}`;

View file

@ -87,7 +87,7 @@ export default {
<template> <template>
<tr v-if="shouldRender" :class="className" class="notes_holder"> <tr v-if="shouldRender" :class="className" class="notes_holder">
<td class="notes_content parallel old" colspan="2"> <td class="notes-content parallel old" colspan="2">
<div v-if="shouldRenderDiscussionsOnLeft" class="content"> <div v-if="shouldRenderDiscussionsOnLeft" class="content">
<diff-discussions <diff-discussions
v-if="line.left.discussions.length" v-if="line.left.discussions.length"
@ -105,7 +105,7 @@ export default {
line-position="left" line-position="left"
/> />
</td> </td>
<td class="notes_content parallel new" colspan="2"> <td class="notes-content parallel new" colspan="2">
<div v-if="shouldRenderDiscussionsOnRight" class="content"> <div v-if="shouldRenderDiscussionsOnRight" class="content">
<diff-discussions <diff-discussions
v-if="line.right.discussions.length" v-if="line.right.discussions.length"

View file

@ -50,3 +50,10 @@ export const LEFT_LINE_KEY = 'left';
export const CENTERED_LIMITED_CONTAINER_CLASSES = export const CENTERED_LIMITED_CONTAINER_CLASSES =
'container-limited limit-container-width mx-lg-auto px-3'; 'container-limited limit-container-width mx-lg-auto px-3';
export const MAX_RENDERING_DIFF_LINES = 500;
export const MAX_RENDERING_BULK_ROWS = 30;
export const MIN_RENDERING_MS = 2;
export const START_RENDERING_INDEX = 200;
export const INLINE_DIFF_LINES_KEY = 'highlighted_diff_lines';
export const PARALLEL_DIFF_LINES_KEY = 'parallel_diff_lines';

View file

@ -3,5 +3,8 @@ export default {
shouldRenderDraftRow: () => () => false, shouldRenderDraftRow: () => () => false,
shouldRenderParallelDraftRow: () => () => false, shouldRenderParallelDraftRow: () => () => false,
draftForLine: () => () => ({}), draftForLine: () => () => ({}),
imageDiscussions() {
return this.diffFile.discussions;
},
}, },
}; };

View file

@ -0,0 +1,13 @@
import { mapActions } from 'vuex';
export default {
methods: {
...mapActions(['toggleDiscussion']),
clickedToggle(discussion) {
this.toggleDiscussion({ discussionId: discussion.id });
},
toggleText(discussion, index) {
return index + 1;
},
},
};

View file

@ -7,7 +7,12 @@ import { handleLocationHash, historyPushState, scrollToElement } from '~/lib/uti
import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility'; import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility';
import TreeWorker from '../workers/tree_worker'; import TreeWorker from '../workers/tree_worker';
import eventHub from '../../notes/event_hub'; import eventHub from '../../notes/event_hub';
import { getDiffPositionByLineCode, getNoteFormData } from './utils'; import {
getDiffPositionByLineCode,
getNoteFormData,
convertExpandLines,
idleCallback,
} from './utils';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { import {
PARALLEL_DIFF_VIEW_TYPE, PARALLEL_DIFF_VIEW_TYPE,
@ -17,6 +22,16 @@ import {
TREE_LIST_STORAGE_KEY, TREE_LIST_STORAGE_KEY,
WHITESPACE_STORAGE_KEY, WHITESPACE_STORAGE_KEY,
TREE_LIST_WIDTH_STORAGE_KEY, TREE_LIST_WIDTH_STORAGE_KEY,
OLD_LINE_KEY,
NEW_LINE_KEY,
TYPE_KEY,
LEFT_LINE_KEY,
MAX_RENDERING_DIFF_LINES,
MAX_RENDERING_BULK_ROWS,
MIN_RENDERING_MS,
START_RENDERING_INDEX,
INLINE_DIFF_LINES_KEY,
PARALLEL_DIFF_LINES_KEY,
} from '../constants'; } from '../constants';
import { diffViewerModes } from '~/ide/constants'; import { diffViewerModes } from '~/ide/constants';
@ -313,13 +328,98 @@ export const cacheTreeListWidth = (_, size) => {
}; };
export const requestFullDiff = ({ commit }, filePath) => commit(types.REQUEST_FULL_DIFF, filePath); export const requestFullDiff = ({ commit }, filePath) => commit(types.REQUEST_FULL_DIFF, filePath);
export const receiveFullDiffSucess = ({ commit }, { filePath, data }) => export const receiveFullDiffSucess = ({ commit }, { filePath }) =>
commit(types.RECEIVE_FULL_DIFF_SUCCESS, { filePath, data }); commit(types.RECEIVE_FULL_DIFF_SUCCESS, { filePath });
export const receiveFullDiffError = ({ commit }, filePath) => { export const receiveFullDiffError = ({ commit }, filePath) => {
commit(types.RECEIVE_FULL_DIFF_ERROR, filePath); commit(types.RECEIVE_FULL_DIFF_ERROR, filePath);
createFlash(s__('MergeRequest|Error loading full diff. Please try again.')); createFlash(s__('MergeRequest|Error loading full diff. Please try again.'));
}; };
export const setExpandedDiffLines = ({ commit, state }, { file, data }) => {
const expandedDiffLines = {
highlighted_diff_lines: convertExpandLines({
diffLines: file.highlighted_diff_lines,
typeKey: TYPE_KEY,
oldLineKey: OLD_LINE_KEY,
newLineKey: NEW_LINE_KEY,
data,
mapLine: ({ line, oldLine, newLine }) =>
Object.assign(line, {
old_line: oldLine,
new_line: newLine,
line_code: `${file.file_hash}_${oldLine}_${newLine}`,
}),
}),
parallel_diff_lines: convertExpandLines({
diffLines: file.parallel_diff_lines,
typeKey: [LEFT_LINE_KEY, TYPE_KEY],
oldLineKey: [LEFT_LINE_KEY, OLD_LINE_KEY],
newLineKey: [LEFT_LINE_KEY, NEW_LINE_KEY],
data,
mapLine: ({ line, oldLine, newLine }) => ({
left: {
...line,
old_line: oldLine,
line_code: `${file.file_hash}_${oldLine}_${newLine}`,
},
right: {
...line,
new_line: newLine,
line_code: `${file.file_hash}_${newLine}_${oldLine}`,
},
}),
}),
};
const currentDiffLinesKey =
state.diffViewType === INLINE_DIFF_VIEW_TYPE ? INLINE_DIFF_LINES_KEY : PARALLEL_DIFF_LINES_KEY;
const hiddenDiffLinesKey =
state.diffViewType === INLINE_DIFF_VIEW_TYPE ? PARALLEL_DIFF_LINES_KEY : INLINE_DIFF_LINES_KEY;
commit(types.SET_HIDDEN_VIEW_DIFF_FILE_LINES, {
filePath: file.file_path,
lines: expandedDiffLines[hiddenDiffLinesKey],
});
if (expandedDiffLines[currentDiffLinesKey].length > MAX_RENDERING_DIFF_LINES) {
let index = START_RENDERING_INDEX;
commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, {
filePath: file.file_path,
lines: expandedDiffLines[currentDiffLinesKey].slice(0, index),
});
commit(types.TOGGLE_DIFF_FILE_RENDERING_MORE, file.file_path);
const idleCb = t => {
const startIndex = index;
while (
t.timeRemaining() >= MIN_RENDERING_MS &&
index !== expandedDiffLines[currentDiffLinesKey].length &&
index - startIndex !== MAX_RENDERING_BULK_ROWS
) {
const line = expandedDiffLines[currentDiffLinesKey][index];
if (line) {
commit(types.ADD_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: file.file_path, line });
index += 1;
}
}
if (index !== expandedDiffLines[currentDiffLinesKey].length) {
idleCallback(idleCb);
} else {
commit(types.TOGGLE_DIFF_FILE_RENDERING_MORE, file.file_path);
}
};
idleCallback(idleCb);
} else {
commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, {
filePath: file.file_path,
lines: expandedDiffLines[currentDiffLinesKey],
});
}
};
export const fetchFullDiff = ({ dispatch }, file) => export const fetchFullDiff = ({ dispatch }, file) =>
axios axios
.get(file.context_lines_path, { .get(file.context_lines_path, {
@ -328,8 +428,10 @@ export const fetchFullDiff = ({ dispatch }, file) =>
from_merge_request: true, from_merge_request: true,
}, },
}) })
.then(({ data }) => dispatch('receiveFullDiffSucess', { filePath: file.file_path, data })) .then(({ data }) => {
.then(() => scrollToElement(`#${file.file_hash}`)) dispatch('receiveFullDiffSucess', { filePath: file.file_path });
dispatch('setExpandedDiffLines', { file, data });
})
.catch(() => dispatch('receiveFullDiffError', file.file_path)); .catch(() => dispatch('receiveFullDiffError', file.file_path));
export const toggleFullDiff = ({ dispatch, getters, state }, filePath) => { export const toggleFullDiff = ({ dispatch, getters, state }, filePath) => {
@ -340,7 +442,6 @@ export const toggleFullDiff = ({ dispatch, getters, state }, filePath) => {
if (file.isShowingFullFile) { if (file.isShowingFullFile) {
dispatch('loadCollapsedDiff', file) dispatch('loadCollapsedDiff', file)
.then(() => dispatch('assignDiscussionsToDiff', getters.getDiffFileDiscussions(file))) .then(() => dispatch('assignDiscussionsToDiff', getters.getDiffFileDiscussions(file)))
.then(() => scrollToElement(`#${file.file_hash}`))
.catch(() => dispatch('receiveFullDiffError', filePath)); .catch(() => dispatch('receiveFullDiffError', filePath));
} else { } else {
dispatch('fetchFullDiff', file); dispatch('fetchFullDiff', file);

View file

@ -28,3 +28,8 @@ export const REQUEST_FULL_DIFF = 'REQUEST_FULL_DIFF';
export const RECEIVE_FULL_DIFF_SUCCESS = 'RECEIVE_FULL_DIFF_SUCCESS'; export const RECEIVE_FULL_DIFF_SUCCESS = 'RECEIVE_FULL_DIFF_SUCCESS';
export const RECEIVE_FULL_DIFF_ERROR = 'RECEIVE_FULL_DIFF_ERROR'; export const RECEIVE_FULL_DIFF_ERROR = 'RECEIVE_FULL_DIFF_ERROR';
export const SET_FILE_COLLAPSED = 'SET_FILE_COLLAPSED'; export const SET_FILE_COLLAPSED = 'SET_FILE_COLLAPSED';
export const SET_HIDDEN_VIEW_DIFF_FILE_LINES = 'SET_HIDDEN_VIEW_DIFF_FILE_LINES';
export const SET_CURRENT_VIEW_DIFF_FILE_LINES = 'SET_CURRENT_VIEW_DIFF_FILE_LINES';
export const ADD_CURRENT_VIEW_DIFF_FILE_LINES = 'ADD_CURRENT_VIEW_DIFF_FILE_LINES';
export const TOGGLE_DIFF_FILE_RENDERING_MORE = 'TOGGLE_DIFF_FILE_RENDERING_MORE';

View file

@ -6,10 +6,8 @@ import {
addContextLines, addContextLines,
prepareDiffData, prepareDiffData,
isDiscussionApplicableToLine, isDiscussionApplicableToLine,
convertExpandLines,
} from './utils'; } from './utils';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { OLD_LINE_KEY, NEW_LINE_KEY, TYPE_KEY, LEFT_LINE_KEY } from '../constants';
export default { export default {
[types.SET_BASE_CONFIG](state, options) { [types.SET_BASE_CONFIG](state, options) {
@ -160,7 +158,9 @@ export default {
} }
if (!file.parallel_diff_lines || !file.highlighted_diff_lines) { if (!file.parallel_diff_lines || !file.highlighted_diff_lines) {
file.discussions = (file.discussions || []).concat(discussion); file.discussions = (file.discussions || [])
.filter(d => d.id !== discussion.id)
.concat(discussion);
} }
return file; return file;
@ -263,45 +263,11 @@ export default {
file.isLoadingFullFile = false; file.isLoadingFullFile = false;
}, },
[types.RECEIVE_FULL_DIFF_SUCCESS](state, { filePath, data }) { [types.RECEIVE_FULL_DIFF_SUCCESS](state, { filePath }) {
const file = findDiffFile(state.diffFiles, filePath, 'file_path'); const file = findDiffFile(state.diffFiles, filePath, 'file_path');
file.isShowingFullFile = true; file.isShowingFullFile = true;
file.isLoadingFullFile = false; file.isLoadingFullFile = false;
file.highlighted_diff_lines = convertExpandLines({
diffLines: file.highlighted_diff_lines,
typeKey: [TYPE_KEY],
oldLineKey: [OLD_LINE_KEY],
newLineKey: [NEW_LINE_KEY],
data,
mapLine: ({ line, oldLine, newLine }) => ({
...line,
old_line: oldLine,
new_line: newLine,
line_code: `${file.file_hash}_${oldLine}_${newLine}`,
}),
});
file.parallel_diff_lines = convertExpandLines({
diffLines: file.parallel_diff_lines,
typeKey: [LEFT_LINE_KEY, TYPE_KEY],
oldLineKey: [LEFT_LINE_KEY, OLD_LINE_KEY],
newLineKey: [LEFT_LINE_KEY, NEW_LINE_KEY],
data,
mapLine: ({ line, oldLine, newLine }) => ({
left: {
...line,
old_line: oldLine,
line_code: `${file.file_hash}_${oldLine}_${newLine}`,
},
right: {
...line,
new_line: newLine,
line_code: `${file.file_hash}_${newLine}_${oldLine}`,
},
}),
});
}, },
[types.SET_FILE_COLLAPSED](state, { filePath, collapsed }) { [types.SET_FILE_COLLAPSED](state, { filePath, collapsed }) {
const file = state.diffFiles.find(f => f.file_path === filePath); const file = state.diffFiles.find(f => f.file_path === filePath);
@ -310,4 +276,30 @@ export default {
file.viewer.collapsed = collapsed; file.viewer.collapsed = collapsed;
} }
}, },
[types.SET_HIDDEN_VIEW_DIFF_FILE_LINES](state, { filePath, lines }) {
const file = state.diffFiles.find(f => f.file_path === filePath);
const hiddenDiffLinesKey =
state.diffViewType === 'inline' ? 'parallel_diff_lines' : 'highlighted_diff_lines';
file[hiddenDiffLinesKey] = lines;
},
[types.SET_CURRENT_VIEW_DIFF_FILE_LINES](state, { filePath, lines }) {
const file = state.diffFiles.find(f => f.file_path === filePath);
const currentDiffLinesKey =
state.diffViewType === 'inline' ? 'highlighted_diff_lines' : 'parallel_diff_lines';
file[currentDiffLinesKey] = lines;
},
[types.ADD_CURRENT_VIEW_DIFF_FILE_LINES](state, { filePath, line }) {
const file = state.diffFiles.find(f => f.file_path === filePath);
const currentDiffLinesKey =
state.diffViewType === 'inline' ? 'highlighted_diff_lines' : 'parallel_diff_lines';
file[currentDiffLinesKey].push(line);
},
[types.TOGGLE_DIFF_FILE_RENDERING_MORE](state, filePath) {
const file = state.diffFiles.find(f => f.file_path === filePath);
file.renderingLines = !file.renderingLines;
},
}; };

View file

@ -253,6 +253,7 @@ export function prepareDiffData(diffData) {
isShowingFullFile: false, isShowingFullFile: false,
isLoadingFullFile: false, isLoadingFullFile: false,
discussions: [], discussions: [],
renderingLines: false,
}); });
} }
} }
@ -423,27 +424,33 @@ export const convertExpandLines = ({
mapLine, mapLine,
}) => { }) => {
const dataLength = data.length; const dataLength = data.length;
const lines = [];
for (let i = 0, diffLinesLength = diffLines.length; i < diffLinesLength; i += 1) {
const line = diffLines[i];
return diffLines.reduce((acc, line, i) => {
if (_.property(typeKey)(line) === 'match') { if (_.property(typeKey)(line) === 'match') {
const beforeLine = diffLines[i - 1]; const beforeLine = diffLines[i - 1];
const afterLine = diffLines[i + 1]; const afterLine = diffLines[i + 1];
const beforeLineIndex = _.property(newLineKey)(beforeLine) || 0; const newLineProperty = _.property(newLineKey);
const afterLineIndex = _.property(newLineKey)(afterLine) - 1 || dataLength; const beforeLineIndex = newLineProperty(beforeLine) || 0;
const afterLineIndex = newLineProperty(afterLine) - 1 || dataLength;
acc.push( lines.push(
...data.slice(beforeLineIndex, afterLineIndex).map((l, index) => ({ ...data.slice(beforeLineIndex, afterLineIndex).map((l, index) =>
...mapLine({ mapLine({
line: { ...l, hasForm: false, discussions: [] }, line: Object.assign(l, { hasForm: false, discussions: [] }),
oldLine: (_.property(oldLineKey)(beforeLine) || 0) + index + 1, oldLine: (_.property(oldLineKey)(beforeLine) || 0) + index + 1,
newLine: (_.property(newLineKey)(beforeLine) || 0) + index + 1, newLine: (newLineProperty(beforeLine) || 0) + index + 1,
}), }),
})), ),
); );
} else { } else {
acc.push(line); lines.push(line);
} }
}
return acc; return lines;
}, []);
}; };
export const idleCallback = cb => requestIdleCallback(cb);

View file

@ -1,4 +1,5 @@
import _ from 'underscore'; import _ from 'underscore';
import $ from 'jquery';
class DirtySubmitForm { class DirtySubmitForm {
constructor(form) { constructor(form) {
@ -26,6 +27,7 @@ class DirtySubmitForm {
); );
this.form.addEventListener('input', throttledUpdateDirtyInput); this.form.addEventListener('input', throttledUpdateDirtyInput);
this.form.addEventListener('change', throttledUpdateDirtyInput); this.form.addEventListener('change', throttledUpdateDirtyInput);
$(this.form).on('change.select2', throttledUpdateDirtyInput);
this.form.addEventListener('submit', event => this.formSubmit(event)); this.form.addEventListener('submit', event => this.formSubmit(event));
} }

View file

@ -104,7 +104,7 @@ class DueDateSelect {
const dateObj = new Date(dateArray[0], dateArray[1] - 1, dateArray[2]); const dateObj = new Date(dateArray[0], dateArray[1] - 1, dateArray[2]);
this.displayedDate = dateFormat(dateObj, 'mmm d, yyyy'); this.displayedDate = dateFormat(dateObj, 'mmm d, yyyy');
} else { } else {
this.displayedDate = 'No due date'; this.displayedDate = __('None');
} }
} }
@ -132,7 +132,7 @@ class DueDateSelect {
submitSelectedDate(isDropdown) { submitSelectedDate(isDropdown) {
const selectedDateValue = this.datePayload[this.abilityName].due_date; const selectedDateValue = this.datePayload[this.abilityName].due_date;
const hasDueDate = this.displayedDate !== 'No due date'; const hasDueDate = this.displayedDate !== __('None');
const displayedDateStyle = hasDueDate ? 'bold' : 'no-value'; const displayedDateStyle = hasDueDate ? 'bold' : 'no-value';
this.$loading.removeClass('hidden').fadeIn(); this.$loading.removeClass('hidden').fadeIn();

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